Author: rsmith Date: Tue Feb 27 19:02:23 2018 New Revision: 326299 URL: http://llvm.org/viewvc/llvm-project?rev=326299&view=rev Log: 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. Modified: cfe/trunk/include/clang/Sema/DeclSpec.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/TemplateName.cpp cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/lib/Parse/ParseTemplate.cpp cfe/trunk/lib/Parse/ParseTentative.cpp cfe/trunk/lib/Parse/Parser.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp Modified: cfe/trunk/include/clang/Sema/DeclSpec.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/DeclSpec.h (original) +++ cfe/trunk/include/clang/Sema/DeclSpec.h Tue Feb 27 19:02:23 2018 @@ -326,6 +326,7 @@ public: PQ_TypeSpecifier = 2, PQ_TypeQualifier = 4, PQ_FunctionSpecifier = 8 + // FIXME: Attributes should be included here. }; private: @@ -1732,7 +1733,8 @@ enum class DeclaratorContext { ConversionIdContext, // C++ conversion-type-id. TrailingReturnContext, // C++11 trailing-type-specifier. TrailingReturnVarContext, // C++11 trailing-type-specifier for variable. - TemplateTypeArgContext, // Template type argument. + TemplateArgContext, // Any template argument (in template argument list). + TemplateTypeArgContext, // Template type argument (in default argument). AliasDeclContext, // C++11 alias-declaration. AliasTemplateContext // C++11 alias-declaration template. }; @@ -1949,6 +1951,7 @@ public: case DeclaratorContext::BlockLiteralContext: case DeclaratorContext::LambdaExprContext: case DeclaratorContext::ConversionIdContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: @@ -1986,6 +1989,7 @@ public: case DeclaratorContext::BlockLiteralContext: case DeclaratorContext::LambdaExprContext: case DeclaratorContext::ConversionIdContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: @@ -2027,6 +2031,7 @@ public: case DeclaratorContext::BlockLiteralContext: case DeclaratorContext::LambdaExprContext: case DeclaratorContext::ConversionIdContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: @@ -2082,6 +2087,7 @@ public: case DeclaratorContext::BlockLiteralContext: case DeclaratorContext::LambdaExprContext: case DeclaratorContext::ConversionIdContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: return false; @@ -2291,6 +2297,7 @@ public: case DeclaratorContext::BlockLiteralContext: case DeclaratorContext::LambdaExprContext: case DeclaratorContext::ConversionIdContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: @@ -2326,13 +2333,14 @@ public: case DeclaratorContext::ConversionIdContext: case DeclaratorContext::TrailingReturnContext: case DeclaratorContext::TrailingReturnVarContext: + case DeclaratorContext::TemplateTypeArgContext: return false; case DeclaratorContext::BlockContext: case DeclaratorContext::ForContext: case DeclaratorContext::InitStmtContext: case DeclaratorContext::ConditionContext: - case DeclaratorContext::TemplateTypeArgContext: + case DeclaratorContext::TemplateArgContext: return true; } Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Feb 27 19:02:23 2018 @@ -6168,6 +6168,8 @@ public: void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); + ParsedTemplateArgument ActOnTemplateTypeArgument(TypeResult ParsedType); + void NoteAllFoundTemplates(TemplateName Name); QualType CheckTemplateIdType(TemplateName Template, Modified: cfe/trunk/lib/AST/TemplateName.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TemplateName.cpp?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/lib/AST/TemplateName.cpp (original) +++ cfe/trunk/lib/AST/TemplateName.cpp Tue Feb 27 19:02:23 2018 @@ -185,6 +185,11 @@ bool TemplateName::isInstantiationDepend } 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)) Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Feb 27 19:02:23 2018 @@ -2686,7 +2686,8 @@ Parser::getDeclSpecContextFromDeclarator 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(Decla // 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); Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseTemplate.cpp (original) +++ cfe/trunk/lib/Parse/ParseTemplate.cpp Tue Feb 27 19:02:23 2018 @@ -1207,15 +1207,9 @@ ParsedTemplateArgument Parser::ParseTemp 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. Modified: cfe/trunk/lib/Parse/ParseTentative.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseTentative.cpp (original) +++ cfe/trunk/lib/Parse/ParseTentative.cpp Tue Feb 27 19:02:23 2018 @@ -1246,6 +1246,17 @@ Parser::isCXXDeclarationSpecifier(Parser 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 *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 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; Modified: cfe/trunk/lib/Parse/Parser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/lib/Parse/Parser.cpp (original) +++ cfe/trunk/lib/Parse/Parser.cpp Tue Feb 27 19:02:23 2018 @@ -1775,8 +1775,8 @@ bool Parser::TryAnnotateTypeOrScopeToken *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(); Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Feb 27 19:02:23 2018 @@ -783,6 +783,56 @@ static void maybeDiagnoseTemplateParamet 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(Tem 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()) Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Feb 27 19:02:23 2018 @@ -2852,6 +2852,14 @@ static QualType GetDeclSpecTypeForDeclar 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 GetDeclSpecTypeForDeclar 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 *GetFullTypeForDec 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 *GetFullTypeForDec !(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 *GetFullTypeForDec 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. Modified: cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp Tue Feb 27 19:02:23 2018 @@ -65,8 +65,8 @@ namespace WrongScope { }; template<typename T> struct Local {}; void f() { - Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}} + Local(int) -> Local<int>; // expected-error {{expected}} using WrongScope::Local; - Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}} + Local(int) -> Local<int>; // expected-error {{expected}} } } Modified: cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp?rev=326299&r1=326298&r2=326299&view=diff ============================================================================== --- cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp (original) +++ cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp Tue Feb 27 19:02:23 2018 @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s -template <typename T> struct A { // expected-note 35{{declared here}} +template <typename T> struct A { // expected-note 38{{declared here}} constexpr A() {} constexpr A(int) {} constexpr operator int() { return 0; } @@ -17,6 +17,12 @@ namespace template_template_arg { Y<A> ya; // expected-error {{requires template arguments}} X<::A> xcca; Y<::A> ycca; // expected-error {{requires template arguments}} + X<A*> xap; // expected-error {{requires template arguments}} + X<const A> xca; // expected-error {{requires template arguments}} + X<A const> xac; // expected-error {{requires template arguments}} + // FIXME: This should not parse as a template template argument due to the + // trailing attributes. + X<A [[]]> xa_attr; template<template<typename> typename = A> struct XD {}; template<typename = A> struct YD {}; // expected-error {{requires template arguments}} @@ -28,6 +34,23 @@ namespace template_template_arg { template<typename T = A> struct G { }; // expected-error {{requires template arguments}} } +namespace template_template_arg_pack { + template<template<typename> typename...> struct XP {}; + template<typename...> struct YP {}; + + struct Z { template<typename T> struct Q {}; }; // expected-note 2{{here}} + + template<typename T> using ZId = Z; + + template<typename ...Ts> struct A { + XP<ZId<Ts>::Q...> xe; + YP<ZId<Ts>::Q...> ye; // expected-error {{requires template arguments}} + + XP<ZId<Ts>::Q> xp; // expected-error {{unexpanded parameter pack}} + YP<ZId<Ts>::Q> yp; // expected-error {{requires template arguments}} + }; +} + namespace injected_class_name { template<typename T> struct A { A(T); @@ -193,3 +216,18 @@ namespace typename_specifier { template<typename T> void g(typename T::A = 0); // expected-note {{refers to class template member}} void h() { g<X>(); } // expected-error {{no matching function}} } + +namespace parenthesized { + template<typename T> struct X { X(T); }; + auto n = (X([]{})); +} + +namespace within_template_arg_list { + template<typename T> struct X { constexpr X(T v) : v(v) {} T v; }; + template<int N = X(1).v> struct Y {}; + using T = Y<>; + using T = Y<X(1).v>; + using T = Y<within_template_arg_list::X(1).v>; + + template<int ...N> struct Z { Y<X(N)...> y; }; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits