Author: rsmith Date: Thu May 10 19:43:08 2018 New Revision: 332076 URL: http://llvm.org/viewvc/llvm-project?rev=332076&view=rev Log: Improve diagnostics and error recovery for template name lookup.
For 'x::template y', consistently give a "no member named 'y' in 'x'" diagnostic if there is no such member, and give a 'template keyword not followed by a template' name error if there is such a member but it's not a template. In the latter case, add a note pointing at the non-template. Don't suggest inserting a 'template' keyword in 'X::Y<' if X is dependent if the lookup of X::Y was actually not a dependent lookup and found only non-templates. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprMember.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/test/CXX/drs/dr1xx.cpp cfe/trunk/test/CXX/drs/dr3xx.cpp cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp cfe/trunk/test/SemaTemplate/metafun-apply.cpp cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp cfe/trunk/test/SemaTemplate/template-id-expr.cpp cfe/trunk/test/SemaTemplate/typo-dependent-name.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu May 10 19:43:08 2018 @@ -4505,6 +4505,8 @@ def note_using_value_decl_missing_typena def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; +def note_template_kw_refers_to_non_template : Note< + "declared as a non-template here">; def err_template_kw_refers_to_class_template : Error< "'%0%1' instantiated to a class template, not a function template">; def note_referenced_class_template : Note< Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu May 10 19:43:08 2018 @@ -6090,9 +6090,10 @@ public: bool hasAnyAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true); - void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, + bool LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, - bool &MemberOfUnknownSpecialization); + bool &MemberOfUnknownSpecialization, + SourceLocation TemplateKWLoc = SourceLocation()); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Thu May 10 19:43:08 2018 @@ -515,7 +515,7 @@ bool Parser::ParseOptionalCXXScopeSpecif << FixItHint::CreateInsertion(Tok.getLocation(), "template "); if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName( - getCurScope(), SS, SourceLocation(), TemplateName, ObjectType, + getCurScope(), SS, Tok.getLocation(), TemplateName, ObjectType, EnteringContext, Template, /*AllowInjectedClassName*/ true)) { // Consume the identifier. ConsumeToken(); Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu May 10 19:43:08 2018 @@ -2087,8 +2087,9 @@ Sema::ActOnIdExpression(Scope *S, CXXSco // this becomes a performance hit, we can work harder to preserve those // results until we get here but it's likely not worth it. bool MemberOfUnknownSpecialization; - LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, - MemberOfUnknownSpecialization); + if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, + MemberOfUnknownSpecialization, TemplateKWLoc)) + return ExprError(); if (MemberOfUnknownSpecialization || (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprMember.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprMember.cpp Thu May 10 19:43:08 2018 @@ -640,6 +640,7 @@ static bool LookupMemberExprInRecord(Sem const RecordType *RTy, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, bool HasTemplateArgs, + SourceLocation TemplateKWLoc, TypoExpr *&TE) { SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange(); RecordDecl *RDecl = RTy->getDecl(); @@ -649,13 +650,13 @@ static bool LookupMemberExprInRecord(Sem BaseRange)) return true; - if (HasTemplateArgs) { + if (HasTemplateArgs || TemplateKWLoc.isValid()) { // LookupTemplateName doesn't expect these both to exist simultaneously. QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0); bool MOUS; - SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS); - return false; + return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS, + TemplateKWLoc); } DeclContext *DC = RDecl; @@ -733,7 +734,8 @@ static bool LookupMemberExprInRecord(Sem static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, ExprResult &BaseExpr, bool &IsArrow, SourceLocation OpLoc, CXXScopeSpec &SS, - Decl *ObjCImpDecl, bool HasTemplateArgs); + Decl *ObjCImpDecl, bool HasTemplateArgs, + SourceLocation TemplateKWLoc); ExprResult Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, @@ -761,7 +763,7 @@ Sema::BuildMemberReferenceExpr(Expr *Bas if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType(); if (LookupMemberExprInRecord( *this, R, nullptr, RecordTy->getAs<RecordType>(), OpLoc, IsArrow, - SS, TemplateKWLoc.isValid() || TemplateArgs != nullptr, TE)) + SS, TemplateArgs != nullptr, TemplateKWLoc, TE)) return ExprError(); if (TE) return TE; @@ -772,7 +774,7 @@ Sema::BuildMemberReferenceExpr(Expr *Bas ExprResult Result = LookupMemberExpr(*this, R, BaseResult, IsArrow, OpLoc, SS, ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr, - TemplateKWLoc.isValid() || TemplateArgs != nullptr); + TemplateArgs != nullptr, TemplateKWLoc); if (BaseResult.isInvalid()) return ExprError(); @@ -1226,7 +1228,8 @@ Sema::PerformMemberExprBaseConversion(Ex static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, ExprResult &BaseExpr, bool &IsArrow, SourceLocation OpLoc, CXXScopeSpec &SS, - Decl *ObjCImpDecl, bool HasTemplateArgs) { + Decl *ObjCImpDecl, bool HasTemplateArgs, + SourceLocation TemplateKWLoc) { assert(BaseExpr.get() && "no base expression"); // Perform default conversions. @@ -1276,8 +1279,8 @@ static ExprResult LookupMemberExpr(Sema // Handle field access to simple records. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { TypoExpr *TE = nullptr; - if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, - OpLoc, IsArrow, SS, HasTemplateArgs, TE)) + if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS, + HasTemplateArgs, TemplateKWLoc, TE)) return ExprError(); // Returning valid-but-null is how we indicate to the caller that @@ -1315,7 +1318,7 @@ static ExprResult LookupMemberExpr(Sema OpLoc, S.Context.getObjCClassType()); if (ShouldTryAgainWithRedefinitionType(S, BaseExpr)) return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); goto fail; } @@ -1509,7 +1512,7 @@ static ExprResult LookupMemberExpr(Sema // use the 'id' redefinition in this case. if (IsArrow && ShouldTryAgainWithRedefinitionType(S, BaseExpr)) return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); return ExprError(S.Diag(MemberLoc, diag::err_property_not_found) << MemberName << BaseType); @@ -1522,7 +1525,7 @@ static ExprResult LookupMemberExpr(Sema if (!MD) { if (ShouldTryAgainWithRedefinitionType(S, BaseExpr)) return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); goto fail; } @@ -1564,7 +1567,7 @@ static ExprResult LookupMemberExpr(Sema if (ShouldTryAgainWithRedefinitionType(S, BaseExpr)) return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); return ExprError(S.Diag(MemberLoc, diag::err_property_not_found) << MemberName << BaseType); @@ -1609,7 +1612,7 @@ static ExprResult LookupMemberExpr(Sema BaseExpr = S.ImpCastExprToType( BaseExpr.get(), S.Context.getObjCSelRedefinitionType(), CK_BitCast); return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); } // Failure cases. @@ -1632,7 +1635,7 @@ static ExprResult LookupMemberExpr(Sema // Recurse as an -> access. IsArrow = true; return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); } } @@ -1646,7 +1649,7 @@ static ExprResult LookupMemberExpr(Sema return ExprError(); BaseExpr = S.DefaultFunctionArrayConversion(BaseExpr.get()); return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); } S.Diag(OpLoc, diag::err_typecheck_member_reference_struct_union) Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu May 10 19:43:08 2018 @@ -189,8 +189,9 @@ TemplateNameKind Sema::isTemplateName(Sc QualType ObjectType = ObjectTypePtr.get(); LookupResult R(*this, TName, Name.getLocStart(), LookupOrdinaryName); - LookupTemplateName(R, S, SS, ObjectType, EnteringContext, - MemberOfUnknownSpecialization); + if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, + MemberOfUnknownSpecialization)) + return TNK_Non_template; if (R.empty()) return TNK_Non_template; if (R.isAmbiguous()) { // Suppress diagnostics; we'll redo this lookup later. @@ -252,8 +253,10 @@ bool Sema::isDeductionGuideName(Scope *S // syntactic form of a deduction guide is enough to identify it even // if we can't look up the template name at all. LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName); - LookupTemplateName(R, S, SS, /*ObjectType*/QualType(), - /*EnteringContext*/false, MemberOfUnknownSpecialization); + if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(), + /*EnteringContext*/ false, + MemberOfUnknownSpecialization)) + return false; if (R.empty()) return false; if (R.isAmbiguous()) { @@ -298,39 +301,40 @@ bool Sema::DiagnoseUnknownTemplateName(c return true; } -void Sema::LookupTemplateName(LookupResult &Found, +bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, - bool &MemberOfUnknownSpecialization) { + bool &MemberOfUnknownSpecialization, + SourceLocation TemplateKWLoc) { // Determine where to perform name lookup MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = nullptr; - bool isDependent = false; + bool IsDependent = false; if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); - isDependent = ObjectType->isDependentType(); - assert((isDependent || !ObjectType->isIncompleteType() || + IsDependent = !LookupCtx; + assert((IsDependent || !ObjectType->isIncompleteType() || ObjectType->castAs<TagType>()->isBeingDefined()) && "Caller should have completed object type"); // Template names cannot appear inside an Objective-C class or object type. if (ObjectType->isObjCObjectOrInterfaceType()) { Found.clear(); - return; + return false; } } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); - isDependent = isDependentScopeSpecifier(SS); + IsDependent = !LookupCtx; // The declaration context must be complete. if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) - return; + return true; } bool ObjectTypeSearchedInScope = false; @@ -341,34 +345,43 @@ void Sema::LookupTemplateName(LookupResu // expression or the declaration context associated with a prior // nested-name-specifier. LookupQualifiedName(Found, LookupCtx); - if (!ObjectType.isNull() && Found.empty()) { - // C++ [basic.lookup.classref]p1: - // In a class member access expression (5.2.5), if the . or -> token is - // immediately followed by an identifier followed by a <, the - // identifier must be looked up to determine whether the < is the - // beginning of a template argument list (14.2) or a less-than operator. - // The identifier is first looked up in the class of the object - // expression. If the identifier is not found, it is then looked up in - // the context of the entire postfix-expression and shall name a class - // or function template. - if (S) LookupName(Found, S); - ObjectTypeSearchedInScope = true; + + // FIXME: The C++ standard does not clearly specify what happens in the + // case where the object type is dependent, and implementations vary. In + // Clang, we treat a name after a . or -> as a template-name if lookup + // finds a non-dependent member or member of the current instantiation that + // is a type template, or finds no such members and lookup in the context + // of the postfix-expression finds a type template. In the latter case, the + // name is nonetheless dependent, and we may resolve it to a member of an + // unknown specialization when we come to instantiate the template. + IsDependent |= Found.wasNotFoundInCurrentInstantiation(); + } + + if (!SS.isSet() && (ObjectType.isNull() || Found.empty())) { + // C++ [basic.lookup.classref]p1: + // In a class member access expression (5.2.5), if the . or -> token is + // immediately followed by an identifier followed by a <, the + // identifier must be looked up to determine whether the < is the + // beginning of a template argument list (14.2) or a less-than operator. + // The identifier is first looked up in the class of the object + // expression. If the identifier is not found, it is then looked up in + // the context of the entire postfix-expression and shall name a class + // template. + if (S) + LookupName(Found, S); + + if (!ObjectType.isNull()) { + // FIXME: We should filter out all non-type templates here, particularly + // variable templates and concepts. But the exclusion of alias templates + // and template template parameters is a wording defect. AllowFunctionTemplatesInLookup = false; + ObjectTypeSearchedInScope = true; } - } else if (isDependent && (!S || ObjectType.isNull())) { - // We cannot look into a dependent object type or nested nme - // specifier. - MemberOfUnknownSpecialization = true; - return; - } else { - // Perform unqualified name lookup in the current scope. - LookupName(Found, S); - if (!ObjectType.isNull()) - AllowFunctionTemplatesInLookup = false; + IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } - if (Found.empty() && !isDependent) { + if (Found.empty() && !IsDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); Found.clear(); @@ -402,11 +415,27 @@ void Sema::LookupTemplateName(LookupResu } } + NamedDecl *ExampleLookupResult = + Found.empty() ? nullptr : Found.getRepresentativeDecl(); FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup); if (Found.empty()) { - if (isDependent) + if (IsDependent) { MemberOfUnknownSpecialization = true; - return; + return false; + } + + // If a 'template' keyword was used, a lookup that finds only non-template + // names is an error. + if (ExampleLookupResult && TemplateKWLoc.isValid()) { + Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template) + << Found.getLookupName() << SS.getRange(); + Diag(ExampleLookupResult->getLocation(), + diag::note_template_kw_refers_to_non_template) + << Found.getLookupName(); + return true; + } + + return false; } if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope && @@ -453,6 +482,8 @@ void Sema::LookupTemplateName(LookupResu } } } + + return false; } void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, @@ -4069,15 +4100,17 @@ Sema::BuildQualifiedTemplateIdExpr(CXXSc bool MemberOfUnknownSpecialization; LookupResult R(*this, NameInfo, LookupOrdinaryName); - LookupTemplateName(R, (Scope*)nullptr, SS, QualType(), /*Entering*/ false, - MemberOfUnknownSpecialization); + if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(), + /*Entering*/false, MemberOfUnknownSpecialization, + TemplateKWLoc)) + return ExprError(); if (R.isAmbiguous()) return ExprError(); if (R.empty()) { - Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_non_template) - << NameInfo.getName() << SS.getRange(); + Diag(NameInfo.getLoc(), diag::err_no_member) + << NameInfo.getName() << DC << SS.getRange(); return ExprError(); } @@ -4140,17 +4173,20 @@ TemplateNameKind Sema::ActOnDependentTem TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name, ObjectType, EnteringContext, Result, MemberOfUnknownSpecialization); - if (TNK == TNK_Non_template && LookupCtx->isDependentContext() && - isa<CXXRecordDecl>(LookupCtx) && - (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() || - cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases())) { + if (TNK == TNK_Non_template && MemberOfUnknownSpecialization) { // This is a dependent template. Handle it below. } else if (TNK == TNK_Non_template) { - Diag(Name.getLocStart(), - diag::err_template_kw_refers_to_non_template) - << GetNameFromUnqualifiedId(Name).getName() - << Name.getSourceRange() - << TemplateKWLoc; + // Do the lookup again to determine if this is a "nothing found" case or + // a "not a template" case. FIXME: Refactor isTemplateName so we don't + // need to do this. + DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name); + LookupResult R(*this, DNI.getName(), Name.getLocStart(), + LookupOrdinaryName); + bool MOUS; + if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, + MOUS, TemplateKWLoc)) + Diag(Name.getLocStart(), diag::err_no_member) + << DNI.getName() << LookupCtx << SS.getRange(); return TNK_Non_template; } else { // We found something; return it. Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Thu May 10 19:43:08 2018 @@ -957,6 +957,7 @@ public: QualType RebuildDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, const IdentifierInfo *Name, SourceLocation NameLoc, TemplateArgumentListInfo &Args, @@ -965,9 +966,9 @@ public: // TODO: avoid TemplateName abstraction CXXScopeSpec SS; SS.Adopt(QualifierLoc); - TemplateName InstName - = getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(), - nullptr, AllowInjectedClassName); + TemplateName InstName = getDerived().RebuildTemplateName( + SS, TemplateKWLoc, *Name, NameLoc, QualType(), nullptr, + AllowInjectedClassName); if (InstName.isNull()) return QualType(); @@ -1146,9 +1147,9 @@ public: /// template name. Subclasses may override this routine to provide different /// behavior. TemplateName RebuildTemplateName(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, const IdentifierInfo &Name, - SourceLocation NameLoc, - QualType ObjectType, + SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName); @@ -1160,9 +1161,9 @@ public: /// template name. Subclasses may override this routine to provide different /// behavior. TemplateName RebuildTemplateName(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, OverloadedOperatorKind Operator, - SourceLocation NameLoc, - QualType ObjectType, + SourceLocation NameLoc, QualType ObjectType, bool AllowInjectedClassName); /// Build a new template name given a template template parameter pack @@ -3752,8 +3753,12 @@ TreeTransform<Derived>::TransformTemplat ObjectType.isNull()) return Name; + // FIXME: Preserve the location of the "template" keyword. + SourceLocation TemplateKWLoc = NameLoc; + if (DTN->isIdentifier()) { return getDerived().RebuildTemplateName(SS, + TemplateKWLoc, *DTN->getIdentifier(), NameLoc, ObjectType, @@ -3761,7 +3766,8 @@ TreeTransform<Derived>::TransformTemplat AllowInjectedClassName); } - return getDerived().RebuildTemplateName(SS, DTN->getOperator(), NameLoc, + return getDerived().RebuildTemplateName(SS, TemplateKWLoc, + DTN->getOperator(), NameLoc, ObjectType, AllowInjectedClassName); } @@ -4340,6 +4346,7 @@ TypeSourceInfo *TreeTransform<Derived>:: TemplateName Template = getDerived().RebuildTemplateName(SS, + SpecTL.getTemplateKeywordLoc(), *SpecTL.getTypePtr()->getIdentifier(), SpecTL.getTemplateNameLoc(), ObjectType, UnqualLookup, @@ -6138,8 +6145,8 @@ TransformDependentTemplateSpecialization return QualType(); QualType Result = getDerived().RebuildDependentTemplateSpecializationType( - T->getKeyword(), QualifierLoc, T->getIdentifier(), - TL.getTemplateNameLoc(), NewTemplateArgs, + T->getKeyword(), QualifierLoc, TL.getTemplateKeywordLoc(), + T->getIdentifier(), TL.getTemplateNameLoc(), NewTemplateArgs, /*AllowInjectedClassName*/ false); if (Result.isNull()) return QualType(); @@ -12510,6 +12517,7 @@ TreeTransform<Derived>::RebuildTemplateN template<typename Derived> TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, QualType ObjectType, @@ -12518,7 +12526,6 @@ TreeTransform<Derived>::RebuildTemplateN UnqualifiedId TemplateName; TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; - SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, TemplateName, ParsedType::make(ObjectType), @@ -12530,6 +12537,7 @@ TreeTransform<Derived>::RebuildTemplateN template<typename Derived> TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, OverloadedOperatorKind Operator, SourceLocation NameLoc, QualType ObjectType, @@ -12538,7 +12546,6 @@ TreeTransform<Derived>::RebuildTemplateN // FIXME: Bogus location information. SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc }; Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations); - SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. Sema::TemplateTy Template; getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, Name, Modified: cfe/trunk/test/CXX/drs/dr1xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr1xx.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr1xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr1xx.cpp Thu May 10 19:43:08 2018 @@ -71,7 +71,8 @@ namespace dr109 { // dr109: yes using T::template f<int>; // expected-error {{'template' keyword not permitted here}} expected-error {{using declaration cannot refer to a template specialization}} // FIXME: We shouldn't suggest using the 'template' keyword in a location where it's not valid. using T::f<int>; // expected-error {{use 'template' keyword}} expected-error {{using declaration cannot refer to a template specialization}} - void g() { this->f<int>(123); } // expected-error {{use 'template'}} + // FIXME: The first 'using' above introduces 'f' as a non-template member of 'B', leading to bad recovery: + void g() { this->f<int>(123); } // expected-error {{expected '('}} }; } Modified: cfe/trunk/test/CXX/drs/dr3xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr3xx.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr3xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr3xx.cpp Thu May 10 19:43:08 2018 @@ -123,8 +123,7 @@ namespace dr305 { // dr305: no template<typename T> using T2 = T; }; void k(Z *z) { - // FIXME: This diagnostic is terrible. - z->~T1<int>(); // expected-error {{'T1' following the 'template' keyword does not refer to a template}} expected-error +{{}} + z->~T1<int>(); // expected-error {{no member named 'T1' in 'dr305::Z'}} expected-error +{{}} z->~T2<int>(); // expected-error {{no member named '~int'}} z->~T2<Z>(); } Modified: cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp Thu May 10 19:43:08 2018 @@ -296,17 +296,17 @@ namespace in_class_template { }; template<typename T> void f() { - typename T::template A<int> a; // expected-error {{template name refers to non-type template 'S::A'}} + typename T::template A<int> a; // expected-error {{template name refers to non-type template 'S::template A'}} } template<typename T> void g() { - T::template A<int>::B = 0; // expected-error {{template name refers to non-type template 'S::A'}} + T::template A<int>::B = 0; // expected-error {{template name refers to non-type template 'S::template A'}} } template<typename T> void h() { - class T::template A<int> c; // expected-error {{template name refers to non-type template 'S::A'}} + class T::template A<int> c; // expected-error {{template name refers to non-type template 'S::template A'}} } template<typename T> - struct X : T::template A<int> {}; // expected-error {{template name refers to non-type template 'S::A'}} + struct X : T::template A<int> {}; // expected-error {{template name refers to non-type template 'S::template A'}} template void f<S>(); // expected-note {{in instantiation of}} template void g<S>(); // expected-note {{in instantiation of}} Modified: cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp (original) +++ cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp Thu May 10 19:43:08 2018 @@ -7,6 +7,6 @@ const template basic_istream<char>; // e namespace S {} template <class X> class Y { - void x() { S::template y<char>(1); } // expected-error {{does not refer to a template}} \ + void x() { S::template y<char>(1); } // expected-error {{no member named 'y' in namespace 'S'}} \ // expected-error {{unqualified-id}} }; Modified: cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm (original) +++ cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm Thu May 10 19:43:08 2018 @@ -419,7 +419,7 @@ struct DependentTemplate { }; struct NSMutableDictionaryBuilder { - typedef NSMutableDictionary apply; + typedef NSMutableDictionary apply; // expected-note 2{{declared as a non-template here}} }; typedef DependentTemplate<NSMutableDictionaryBuilder>::type DependentTemplateFail1; // expected-note{{in instantiation of template class}} Modified: cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp (original) +++ cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp Thu May 10 19:43:08 2018 @@ -55,7 +55,7 @@ namespace PR6031 { struct NoDepBase { int foo() { class NoDepBase::Nested nested; // expected-error{{no class named 'Nested' in 'NoDepBase<T>'}} - typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{'MemberTemplate' following the 'template' keyword does not refer to a template}} \ + typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{no member named 'MemberTemplate' in 'NoDepBase<T>'}} \ // FIXME: expected-error{{unqualified-id}} return NoDepBase::a; // expected-error{{no member named 'a' in 'NoDepBase<T>'}} } @@ -103,7 +103,7 @@ namespace PR6081 { template< class X > void f0(const X & k) { - this->template f1<int>()(k); // expected-error{{'f1' following the 'template' keyword does not refer to a template}} \ + this->template f1<int>()(k); // expected-error{{no member named 'f1' in 'C<T>'}} \ // FIXME: expected-error{{unqualified-id}} \ // expected-error{{function-style cast or type construction}} \ // expected-error{{expected expression}} Modified: cfe/trunk/test/SemaTemplate/metafun-apply.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/metafun-apply.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/metafun-apply.cpp (original) +++ cfe/trunk/test/SemaTemplate/metafun-apply.cpp Thu May 10 19:43:08 2018 @@ -15,7 +15,7 @@ struct add_reference { }; struct bogus { - struct apply { + struct apply { // expected-note{{declared as a non-template here}} typedef int type; }; }; Modified: cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp (original) +++ cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp Thu May 10 19:43:08 2018 @@ -49,7 +49,7 @@ namespace N { struct X; }; - struct B; + struct B; // expected-note{{declared as a non-template here}} } struct ::N::A<int>::X { @@ -131,7 +131,7 @@ namespace PR9226 { template<typename T, typename U> struct Y { - typedef typename T::template f<U> type; // expected-error{{template name refers to non-type template 'X::f'}} + typedef typename T::template f<U> type; // expected-error{{template name refers to non-type template 'X::template f'}} }; Y<X, int> yxi; // expected-note{{in instantiation of template class 'PR9226::Y<PR9226::X, int>' requested here}} @@ -144,7 +144,7 @@ namespace PR9449 { template <typename T> void f() { int s<T>::template n<T>::* f; // expected-error{{implicit instantiation of undefined template 'PR9449::s<int>'}} \ - // expected-error{{following the 'template' keyword}} + // expected-error{{no member named 'n'}} } template void f<int>(); // expected-note{{in instantiation of}} Modified: cfe/trunk/test/SemaTemplate/template-id-expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/template-id-expr.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/template-id-expr.cpp (original) +++ cfe/trunk/test/SemaTemplate/template-id-expr.cpp Thu May 10 19:43:08 2018 @@ -56,7 +56,7 @@ struct Y0 { template<typename U> static void f2(U); - void f3(int); + void f3(int); // expected-note 2{{declared as a non-template here}} static int f4(int); template<typename U> @@ -100,7 +100,7 @@ struct Y1 { template<typename U> static void f2(U); - void f3(int); + void f3(int); // expected-note 4{{declared as a non-template here}} static int f4(int); template<typename U> @@ -131,10 +131,39 @@ struct Y1 { void use_Y1(Y1<int> y1) { y1.f<int>(); } // expected-note {{in instantiation of}} +template<typename T> +struct Y2 : Y1<T> { + typedef ::Y1<T> Y1; + + template<typename U> + void f(Y1 *p) { + Y1::template f1<U>(0); + Y1::template f1(0); + p->template f1(0); + + Y1::template f2<U>(0); + Y1::template f2(0); + + Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + + int x; + x = Y1::f4(0); + x = Y1::f4<int>(0); // expected-error {{use 'template'}} expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + + x = p->f4(0); + x = p->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{use 'template'}} + x = p->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + } +}; + +void use_Y2(Y2<int> y2) { y2.f<int>(0); } // expected-note {{in instantiation of}} + struct A { template<int I> struct B { - static void b1(); + static void b1(); // expected-note {{declared as a non-template here}} }; }; Modified: cfe/trunk/test/SemaTemplate/typo-dependent-name.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/typo-dependent-name.cpp?rev=332076&r1=332075&r2=332076&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/typo-dependent-name.cpp (original) +++ cfe/trunk/test/SemaTemplate/typo-dependent-name.cpp Thu May 10 19:43:08 2018 @@ -1,18 +1,45 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics + +using nullptr_t = decltype(nullptr); template<typename T> struct Base { T inner; }; +int z; + template<typename T> -struct X { - template<typename U> +struct X : Base<T> { + static int z; + + template<int U> struct Inner { }; bool f(T other) { - return this->inner < other; + // A pair of comparisons; 'inner' is a dependent name so can't be assumed + // to be a template. + return this->inner < other > ::z; } }; + +void use_x(X<int> x) { x.f(0); } + +template<typename T> +struct Y { + static int z; + + template<int U> + struct Inner : Y { // expected-note {{declared here}} + }; + + bool f(T other) { + // We can determine that 'inner' does not exist at parse time, so can + // perform typo correction in this case. + return this->inner<other>::z; // expected-error {{no template named 'inner' in 'Y<T>'; did you mean 'Inner'?}} + } +}; + +struct Q { constexpr operator int() { return 0; } }; +void use_y(Y<Q> x) { x.f(Q()); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits