diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-02-28 03:02:23 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-02-28 03:02:23 +0000 |
commit | 77a9c60aa670d262d9bc98fe327067a40c3c2afc (patch) | |
tree | f613992afcd3d40fb8756bcb0e00f0105e7b78d0 /clang/lib/Sema/SemaTemplate.cpp | |
parent | c1a40220b4f4983706a4509f0291bb8c2a24b8a1 (diff) | |
download | bcm5719-llvm-77a9c60aa670d262d9bc98fe327067a40c3c2afc.tar.gz bcm5719-llvm-77a9c60aa670d262d9bc98fe327067a40c3c2afc.zip |
Fix a couple of cases where we would fail to correctly parse deduced class template specialization types.
Specifically, we would not properly parse these types within template arguments
(for non-type template parameters), and in tentative parses. Fixing both of
these essentially requires that we parse deduced template specialization types
as types in all contexts, even in template argument lists -- in particular,
tentative parsing may look ahead and annotate a deduced template specialization
type before we figure out that we're actually supposed to treat the tokens as a
template-name. We deal with this by simply permitting deduced template
specialization types when parsing template arguments, and converting them to
template template arguments.
llvm-svn: 326299
Diffstat (limited to 'clang/lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 7c6af5793fc..8dbae9cdcea 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -783,6 +783,56 @@ static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S, SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl); } +/// Convert a parsed type into a parsed template argument. This is mostly +/// trivial, except that we may have parsed a C++17 deduced class template +/// specialization type, in which case we should form a template template +/// argument instead of a type template argument. +ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) { + TypeSourceInfo *TInfo; + QualType T = GetTypeFromParser(ParsedType.get(), &TInfo); + if (T.isNull()) + return ParsedTemplateArgument(); + assert(TInfo && "template argument with no location"); + + // If we might have formed a deduced template specialization type, convert + // it to a template template argument. + if (getLangOpts().CPlusPlus17) { + TypeLoc TL = TInfo->getTypeLoc(); + SourceLocation EllipsisLoc; + if (auto PET = TL.getAs<PackExpansionTypeLoc>()) { + EllipsisLoc = PET.getEllipsisLoc(); + TL = PET.getPatternLoc(); + } + + CXXScopeSpec SS; + if (auto ET = TL.getAs<ElaboratedTypeLoc>()) { + SS.Adopt(ET.getQualifierLoc()); + TL = ET.getNamedTypeLoc(); + } + + if (auto DTST = TL.getAs<DeducedTemplateSpecializationTypeLoc>()) { + TemplateName Name = DTST.getTypePtr()->getTemplateName(); + if (SS.isSet()) + Name = Context.getQualifiedTemplateName(SS.getScopeRep(), + /*HasTemplateKeyword*/ false, + Name.getAsTemplateDecl()); + ParsedTemplateArgument Result(SS, TemplateTy::make(Name), + DTST.getTemplateNameLoc()); + if (EllipsisLoc.isValid()) + Result = Result.getTemplatePackExpansion(EllipsisLoc); + return Result; + } + } + + // This is a normal type template argument. Note, if the type template + // argument is an injected-class-name for a template, it has a dual nature + // and can be used as either a type or a template. We handle that in + // convertTypeTemplateArgumentToTemplate. + return ParsedTemplateArgument(ParsedTemplateArgument::Type, + ParsedType.get().getAsOpaquePtr(), + TInfo->getTypeLoc().getLocStart()); +} + /// ActOnTypeParameter - Called when a C++ template type parameter /// (e.g., "typename T") has been parsed. Typename specifies whether /// the keyword "typename" was used to declare the type parameter @@ -4148,11 +4198,12 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, ArgType = Arg.getAsType(); TSI = AL.getTypeSourceInfo(); break; - case TemplateArgument::Template: { + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { // We have a template type parameter but the template argument // is a template without any arguments. SourceRange SR = AL.getSourceRange(); - TemplateName Name = Arg.getAsTemplate(); + TemplateName Name = Arg.getAsTemplateOrTemplatePattern(); Diag(SR.getBegin(), diag::err_template_missing_args) << (int)getTemplateNameKindForDiagnostics(Name) << Name << SR; if (TemplateDecl *Decl = Name.getAsTemplateDecl()) |