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 | |
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')
-rw-r--r-- | clang/lib/AST/TemplateName.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTentative.cpp | 39 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 55 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 12 |
7 files changed, 108 insertions, 22 deletions
diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index bd04fd8366b..548468ed17c 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -185,6 +185,11 @@ bool TemplateName::isInstantiationDependent() const { } bool TemplateName::containsUnexpandedParameterPack() const { + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { + if (QTN->getQualifier()->containsUnexpandedParameterPack()) + return true; + } + if (TemplateDecl *Template = getAsTemplateDecl()) { if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 3a3096fd059..deefcaf3251 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2686,7 +2686,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) { return DeclSpecContext::DSC_top_level; if (Context == DeclaratorContext::TemplateParamContext) return DeclSpecContext::DSC_template_param; - if (Context == DeclaratorContext::TemplateTypeArgContext) + if (Context == DeclaratorContext::TemplateArgContext || + Context == DeclaratorContext::TemplateTypeArgContext) return DeclSpecContext::DSC_template_type_arg; if (Context == DeclaratorContext::TrailingReturnContext || Context == DeclaratorContext::TrailingReturnVarContext) @@ -5637,7 +5638,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // An identifier within parens is unlikely to be intended to be anything // other than a name being "declared". DiagnoseIdentifier = true; - else if (D.getContext() == DeclaratorContext::TemplateTypeArgContext) + else if (D.getContext() == DeclaratorContext::TemplateArgContext) // T<int N> is an accidental identifier; T<int N indicates a missing '>'. DiagnoseIdentifier = NextToken().isOneOf(tok::comma, tok::greater, tok::greatergreater); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 46367316719..88a5745350d 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1207,15 +1207,9 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { EnterExpressionEvaluationContext EnterConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); if (isCXXTypeId(TypeIdAsTemplateArgument)) { - SourceLocation Loc = Tok.getLocation(); TypeResult TypeArg = ParseTypeName( - /*Range=*/nullptr, DeclaratorContext::TemplateTypeArgContext); - if (TypeArg.isInvalid()) - return ParsedTemplateArgument(); - - return ParsedTemplateArgument(ParsedTemplateArgument::Type, - TypeArg.get().getAsOpaquePtr(), - Loc); + /*Range=*/nullptr, DeclaratorContext::TemplateArgContext); + return Actions.ActOnTemplateTypeArgument(TypeArg); } // Try to parse a template template argument. diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 10c084b66da..88c0e176b02 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1246,6 +1246,17 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case ANK_TentativeDecl: return TPResult::False; case ANK_TemplateName: + // In C++17, this could be a type template for class template argument + // deduction. Try to form a type annotation for it. If we're in a + // template template argument, we'll undo this when checking the + // validity of the argument. + if (getLangOpts().CPlusPlus17) { + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error; + if (Tok.isNot(tok::identifier)) + break; + } + // A bare type template-name which can't be a template template // argument is an error, and was probably intended to be a type. return GreaterThanIsOperator ? TPResult::True : TPResult::False; @@ -1424,8 +1435,6 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, *HasMissingTypename = true; return TPResult::Ambiguous; } - - // FIXME: Fails to either revert or commit the tentative parse! } else { // Try to resolve the name. If it doesn't exist, assume it was // intended to name a type and keep disambiguating. @@ -1435,19 +1444,33 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case ANK_TentativeDecl: return TPResult::False; case ANK_TemplateName: + // In C++17, this could be a type template for class template + // argument deduction. + if (getLangOpts().CPlusPlus17) { + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error; + if (Tok.isNot(tok::identifier)) + break; + } + // A bare type template-name which can't be a template template // argument is an error, and was probably intended to be a type. - return GreaterThanIsOperator ? TPResult::True : TPResult::False; + // In C++17, this could be class template argument deduction. + return (getLangOpts().CPlusPlus17 || GreaterThanIsOperator) + ? TPResult::True + : TPResult::False; case ANK_Unresolved: return HasMissingTypename ? TPResult::Ambiguous : TPResult::False; case ANK_Success: - // Annotated it, check again. - assert(Tok.isNot(tok::annot_cxxscope) || - NextToken().isNot(tok::identifier)); - return isCXXDeclarationSpecifier(BracedCastResult, - HasMissingTypename); + break; } + + // Annotated it, check again. + assert(Tok.isNot(tok::annot_cxxscope) || + NextToken().isNot(tok::identifier)); + return isCXXDeclarationSpecifier(BracedCastResult, + HasMissingTypename); } } return TPResult::False; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index ce5a479b4b3..f617d240b09 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1775,8 +1775,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS, *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, false, NextToken().is(tok::period), nullptr, /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo*/ true, - /*IsClassTemplateDeductionContext*/GreaterThanIsOperator)) { + /*NonTrivialTypeSourceInfo*/true, + /*IsClassTemplateDeductionContext*/true)) { SourceLocation BeginLoc = Tok.getLocation(); if (SS.isNotEmpty()) // it was a C++ qualified type name. BeginLoc = SS.getBeginLoc(); 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()) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index e323b31f8e7..72ade3b1c1e 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2852,6 +2852,14 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::BlockLiteralContext: Error = 9; // Block literal break; + case DeclaratorContext::TemplateArgContext: + // Within a template argument list, a deduced template specialization + // type will be reinterpreted as a template template argument. + if (isa<DeducedTemplateSpecializationType>(Deduced) && + !D.getNumTypeObjects() && + D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier) + break; + LLVM_FALLTHROUGH; case DeclaratorContext::TemplateTypeArgContext: Error = 10; // Template type argument break; @@ -2991,6 +2999,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::CXXNewContext: case DeclaratorContext::CXXCatchContext: case DeclaratorContext::ObjCCatchContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: DiagID = diag::err_type_defined_in_type_specifier; break; @@ -4011,6 +4020,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::LambdaExprParameterContext: case DeclaratorContext::ObjCCatchContext: case DeclaratorContext::TemplateParamContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TypeNameContext: case DeclaratorContext::FunctionalCastContext: @@ -4832,6 +4842,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, !(Kind == Member && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) && !IsTypedefName && + D.getContext() != DeclaratorContext::TemplateArgContext && D.getContext() != DeclaratorContext::TemplateTypeArgContext) { SourceLocation Loc = D.getLocStart(); SourceRange RemovalRange; @@ -4959,6 +4970,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::ConversionIdContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: // FIXME: We may want to allow parameter packs in block-literal contexts // in the future. |