Already fixed in llvmorg-11-init-7209-g33087323007 :) On Mon, 30 Mar 2020 at 18:30, Hubert Tong via cfe-commits < cfe-commits@lists.llvm.org> wrote:
> I have not found which of the few commits on Friday having to do with > template-ids is responsible, but this now produces a crash (trace is below): > struct A; > struct B : A<int> {}; > > Richard, would you take a look? > > Thanks, > > > Hubert Tong > > <stdin>:2:12: error: unknown template name 'A' > struct B : A<int> {}; > ^ > PLEASE submit a bug report to https://bugs.llvm.org/ and include the > crash backtrace, preprocessed source, and associated run script. > Stack dump: > 0. Program arguments: /build/bin/clang++ -cc1 -xc++ - > 1. <stdin>:2:19: current parser token '{' > 2. <stdin>:2:1: parsing struct/union/class body 'B' > #0 0x00003fffb2016418 llvm::sys::PrintStackTrace(llvm::raw_ostream&) > (/build/bin/../lib/libLLVMSupport.so.11git+0x206418) > #1 0x00003fffb2016540 PrintStackTraceSignalHandler(void*) > (/build/bin/../lib/libLLVMSupport.so.11git+0x206540) > #2 0x00003fffb2013b38 llvm::sys::RunSignalHandlers() > (/build/bin/../lib/libLLVMSupport.so.11git+0x203b38) > #3 0x00003fffb2013d2c SignalHandler(int) > (/build/bin/../lib/libLLVMSupport.so.11git+0x203d2c) > #4 0x00003fffb4570478 0x478 > clang::Sema::ActOnBaseSpecifier(clang::Decl*, clang::SourceRange, > clang::ParsedAttributes&, bool, clang::AccessSpecifier, > clang::OpaquePtr<clang::QualType>, clang::SourceLocation, > clang::SourceLocation) > #5 0x00003fffb4570478 > #6 0x00003fffb4570478 clang::Parser::ParseBaseSpecifier(clang::Decl*) > (+0x478) > #7 0x0000001c00000017 > #8 0x00003fffad949354 clang::Parser::ParseBaseClause(clang::Decl*) > (/build/bin/../lib/../lib/libclangSema.so.11git+0x469354) > #9 0x00003fffae1b3368 > clang::Parser::ParseCXXMemberSpecification(clang::SourceLocation, > clang::SourceLocation, clang::Parser::ParsedAttributesWithRange&, unsigned > int, clang::Decl*) (/build/bin/../lib/../lib/libclangParse.so.11git+0x73368) > #10 0x00003fffae1b3668 > clang::Parser::ParseClassSpecifier(clang::tok::TokenKind, > clang::SourceLocation, clang::DeclSpec&, clang::Parser::ParsedTemplateInfo > const&, clang::AccessSpecifier, bool, clang::Parser::DeclSpecContext, > clang::Parser::ParsedAttributesWithRange&) > (/build/bin/../lib/../lib/libclangParse.so.11git+0x73668) > #11 0x00003fffae1b884c > clang::Parser::ParseDeclarationSpecifiers(clang::DeclSpec&, > clang::Parser::ParsedTemplateInfo const&, clang::AccessSpecifier, > clang::Parser::DeclSpecContext, clang::Parser::LateParsedAttrList*) > (/build/bin/../lib/../lib/libclangParse.so.11git+0x7884c) > #12 0x00003fffae1ba2ac > clang::Parser::ParseDeclOrFunctionDefInternal(clang::Parser::ParsedAttributesWithRange&, > clang::ParsingDeclSpec&, clang::AccessSpecifier) > (/build/bin/../lib/../lib/libclangParse.so.11git+0x7a2ac) > #13 0x00003fffae19b4f0 > clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsedAttributesWithRange&, > clang::ParsingDeclSpec*, clang::AccessSpecifier) (.part.221) > (/build/bin/../lib/../lib/libclangParse.so.11git+0x5b4f0) > #14 0x00003fffae248894 > clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&, > clang::ParsingDeclSpec*) > (/build/bin/../lib/../lib/libclangParse.so.11git+0x108894) > #15 0x00003fffae249174 > clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, > bool) (/build/bin/../lib/../lib/libclangParse.so.11git+0x109174) > #16 0x00003fffae24d880 clang::ParseAST(clang::Sema&, bool, bool) > (/build/bin/../lib/../lib/libclangParse.so.11git+0x10d880) > #17 0x00003fffae24f00c clang::ASTFrontendAction::ExecuteAction() > (/build/bin/../lib/../lib/libclangParse.so.11git+0x10f00c) > #18 0x00003fffae1743a8 clang::FrontendAction::Execute() > (/build/bin/../lib/../lib/libclangParse.so.11git+0x343a8) > #19 0x00003fffb07bc5c0 > clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) > (/build/bin/../lib/libclangFrontend.so.11git+0x11c5c0) > #20 0x00003fffb07c100c > clang::ExecuteCompilerInvocation(clang::CompilerInstance*) > (/build/bin/../lib/libclangFrontend.so.11git+0x12100c) > #21 0x00003fffb076d900 cc1_main(llvm::ArrayRef<char const*>, char const*, > void*) (/build/bin/../lib/libclangFrontend.so.11git+0xcd900) > #22 0x00003fffb06749dc ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&) > (/build/bin/../lib/libclangFrontendTool.so.11git+0x49dc) > #23 0x000000001001635c main (/build/bin/clang+++0x1001635c) > #24 0x000000001000f6b8 generic_start_main.isra.0 > (/build/bin/clang+++0x1000f6b8) > #25 0x000000001000cdcc __libc_start_main (/build/bin/clang+++0x1000cdcc) > > /build/bin/../lib/libLLVMSupport.so.11git(_ZN4llvm3sys15PrintStackTraceERNS_11raw_ostreamE+0x38)[0x3fffb2016418] > /build/bin/../lib/libLLVMSupport.so.11git(+0x206540)[0x3fffb2016540] > > /build/bin/../lib/libLLVMSupport.so.11git(_ZN4llvm3sys17RunSignalHandlersEv+0x78)[0x3fffb2013b38] > /build/bin/../lib/libLLVMSupport.so.11git(+0x203d2c)[0x3fffb2013d2c] > [0x3fffb4570478] > [0x1c00000017] > > /build/bin/../lib/../lib/libclangSema.so.11git(_ZN5clang4Sema18ActOnBaseSpecifierEPNS_4DeclENS_11SourceRangeERNS_16ParsedAttributesEbNS_15AccessSpecifierENS_9OpaquePtrINS_8QualTypeEEENS_14SourceLocationESA_+0x234)[0x3fffad949354] > > /build/bin/../lib/../lib/libclangParse.so.11git(_ZN5clang6Parser18ParseBaseSpecifierEPNS_4DeclE+0x1b8)[0x3fffae1b3368] > > /build/bin/../lib/../lib/libclangParse.so.11git(_ZN5clang6Parser15ParseBaseClauseEPNS_4DeclE+0x78)[0x3fffae1b3668] > > /build/bin/../lib/../lib/libclangParse.so.11git(_ZN5clang6Parser27ParseCXXMemberSpecificationENS_14SourceLocationES1_RNS0_25ParsedAttributesWithRangeEjPNS_4DeclE+0x7cc)[0x3fffae1b884c] > > /build/bin/../lib/../lib/libclangParse.so.11git(_ZN5clang6Parser19ParseClassSpecifierENS_3tok9TokenKindENS_14SourceLocationERNS_8DeclSpecERKNS0_18ParsedTemplateInfoENS_15AccessSpecifierEbNS0_15DeclSpecContextERNS0_25ParsedAttributesWithRangeE+0x15ec)[0x3fffae1ba2ac] > > /build/bin/../lib/../lib/libclangParse.so.11git(_ZN5clang6Parser26ParseDeclarationSpecifiersERNS_8DeclSpecERKNS0_18ParsedTemplateInfoENS_15AccessSpecifierENS0_15DeclSpecContextEPNS0_18LateParsedAttrListE+0xea0)[0x3fffae19b4f0] > > /build/bin/../lib/../lib/libclangParse.so.11git(_ZN5clang6Parser30ParseDeclOrFunctionDefInternalERNS0_25ParsedAttributesWithRangeERNS_15ParsingDeclSpecENS_15AccessSpecifierE+0x94)[0x3fffae248894] > /build/bin/../lib/../lib/libclangParse.so.11git(+0x109174)[0x3fffae249174] > > /build/bin/../lib/../lib/libclangParse.so.11git(_ZN5clang6Parser24ParseExternalDeclarationERNS0_25ParsedAttributesWithRangeEPNS_15ParsingDeclSpecE+0x710)[0x3fffae24d880] > > /build/bin/../lib/../lib/libclangParse.so.11git(_ZN5clang6Parser17ParseTopLevelDeclERNS_9OpaquePtrINS_12DeclGroupRefEEEb+0x12c)[0x3fffae24f00c] > > /build/bin/../lib/../lib/libclangParse.so.11git(_ZN5clang8ParseASTERNS_4SemaEbb+0x2c8)[0x3fffae1743a8] > > /build/bin/../lib/libclangFrontend.so.11git(_ZN5clang17ASTFrontendAction13ExecuteActionEv+0x70)[0x3fffb07bc5c0] > > /build/bin/../lib/libclangFrontend.so.11git(_ZN5clang14FrontendAction7ExecuteEv+0x10c)[0x3fffb07c100c] > > /build/bin/../lib/libclangFrontend.so.11git(_ZN5clang16CompilerInstance13ExecuteActionERNS_14FrontendActionE+0x240)[0x3fffb076d900] > > /build/bin/../lib/libclangFrontendTool.so.11git(_ZN5clang25ExecuteCompilerInvocationEPNS_16CompilerInstanceE+0xb1c)[0x3fffb06749dc] > > /build/bin/clang++(_Z8cc1_mainN4llvm8ArrayRefIPKcEES2_Pv+0x136c)[0x1001635c] > /build/bin/clang++[0x1000f6b8] > /build/bin/clang++(main+0xe4c)[0x1000cdcc] > /lib64/libc.so.6(+0x25100)[0x3fffaff55100] > /lib64/libc.so.6(__libc_start_main+0xc4)[0x3fffaff552f4] > On Sat, Mar 28, 2020 at 12:13 AM Richard Smith via cfe-commits < > cfe-commits@lists.llvm.org> wrote: > >> >> Author: Richard Smith >> Date: 2020-03-27T21:07:06-07:00 >> New Revision: 499b2a8d63ca9b319ce3aae462029f37ce7d96dd >> >> URL: >> https://github.com/llvm/llvm-project/commit/499b2a8d63ca9b319ce3aae462029f37ce7d96dd >> DIFF: >> https://github.com/llvm/llvm-project/commit/499b2a8d63ca9b319ce3aae462029f37ce7d96dd.diff >> >> LOG: PR45294: Fix handling of assumed template names looked up in the >> lexical >> scope. >> >> There are a few contexts in which we assume a name is a template name; >> if such a context is one where we should perform an unqualified lookup, >> and lookup finds nothing, we would form a dependent template name even >> if the name is not dependent. This happens in particular for the lookup >> of a pseudo-destructor. >> >> In passing, rename ActOnDependentTemplateName to just ActOnTemplateName >> given that we apply it for non-dependent template names too. >> >> Added: >> >> >> Modified: >> clang/include/clang/Basic/DiagnosticSemaKinds.td >> clang/lib/Parse/ParseExprCXX.cpp >> clang/lib/Parse/Parser.cpp >> clang/lib/Sema/SemaTemplate.cpp >> clang/test/Parser/cxx-decl.cpp >> clang/test/SemaCXX/literal-operators.cpp >> clang/test/SemaCXX/pseudo-destructors.cpp >> clang/test/SemaTemplate/nested-name-spec-template.cpp >> >> Removed: >> >> >> >> >> ################################################################################ >> diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td >> b/clang/include/clang/Basic/DiagnosticSemaKinds.td >> index d2aa2902bb2a..b48f92f38939 100644 >> --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td >> +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td >> @@ -4919,6 +4919,9 @@ 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_dependent_non_template : Error< >> + "%0%select{| following the 'template' keyword}1 " >> + "cannot refer to a dependent template">; >> 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< >> >> diff --git a/clang/lib/Parse/ParseExprCXX.cpp >> b/clang/lib/Parse/ParseExprCXX.cpp >> index 985bcf689d21..761fad9456be 100644 >> --- a/clang/lib/Parse/ParseExprCXX.cpp >> +++ b/clang/lib/Parse/ParseExprCXX.cpp >> @@ -1773,6 +1773,12 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, >> SourceLocation OpLoc, >> >> // If there is a '<', the second type name is a template-id. Parse >> // it as such. >> + // >> + // FIXME: This is not a context in which a '<' is assumed to start a >> template >> + // argument list. This affects examples such as >> + // void f(auto *p) { p->~X<int>(); } >> + // ... but there's no ambiguity, and nowhere to write 'template' in >> such an >> + // example, so we accept it anyway. >> if (Tok.is(tok::less) && >> ParseUnqualifiedIdTemplateId( >> SS, ObjectType, Base && Base->containsErrors(), >> SourceLocation(), >> >> diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp >> index 47b5de320ebf..a33e40b8768d 100644 >> --- a/clang/lib/Parse/Parser.cpp >> +++ b/clang/lib/Parse/Parser.cpp >> @@ -1878,11 +1878,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { >> Tok.getLocation()); >> } else if (Tok.is(tok::annot_template_id)) { >> TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); >> - if (TemplateId->isInvalid()) >> - return true; >> - if (TemplateId->Kind != TNK_Type_template && >> - TemplateId->Kind != TNK_Dependent_template_name && >> - TemplateId->Kind != TNK_Undeclared_template) { >> + if (!TemplateId->mightBeType()) { >> Diag(Tok, diag::err_typename_refers_to_non_type_template) >> << Tok.getAnnotationRange(); >> return true; >> @@ -1891,14 +1887,13 @@ bool Parser::TryAnnotateTypeOrScopeToken() { >> ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), >> TemplateId->NumArgs); >> >> - Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, >> - TemplateId->TemplateKWLoc, >> - TemplateId->Template, >> - TemplateId->Name, >> - TemplateId->TemplateNameLoc, >> - TemplateId->LAngleLoc, >> - TemplateArgsPtr, >> - TemplateId->RAngleLoc); >> + Ty = TemplateId->isInvalid() >> + ? TypeError() >> + : Actions.ActOnTypenameType( >> + getCurScope(), TypenameLoc, SS, >> TemplateId->TemplateKWLoc, >> + TemplateId->Template, TemplateId->Name, >> + TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, >> + TemplateArgsPtr, TemplateId->RAngleLoc); >> } else { >> Diag(Tok, diag::err_expected_type_name_after_typename) >> << SS.getRange(); >> >> diff --git a/clang/lib/Sema/SemaTemplate.cpp >> b/clang/lib/Sema/SemaTemplate.cpp >> index 74d1fbe2ec77..1e2ebc5037bc 100755 >> --- a/clang/lib/Sema/SemaTemplate.cpp >> +++ b/clang/lib/Sema/SemaTemplate.cpp >> @@ -377,6 +377,9 @@ bool Sema::LookupTemplateName(LookupResult &Found, >> if (ATK) >> *ATK = AssumedTemplateKind::None; >> >> + if (SS.isInvalid()) >> + return true; >> + >> Found.setTemplateNameLookup(true); >> >> // Determine where to perform name lookup >> @@ -386,7 +389,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, >> 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"); >> + assert(SS.isEmpty() && "ObjectType and scope specifier cannot >> coexist"); >> LookupCtx = computeDeclContext(ObjectType); >> IsDependent = !LookupCtx && ObjectType->isDependentType(); >> assert((IsDependent || !ObjectType->isIncompleteType() || >> @@ -412,11 +415,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, >> Found.clear(); >> return false; >> } >> - } else if (SS.isSet()) { >> + } else if (SS.isNotEmpty()) { >> // 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 = !LookupCtx; >> + IsDependent = !LookupCtx && isDependentScopeSpecifier(SS); >> >> // The declaration context must be complete. >> if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) >> @@ -443,7 +446,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, >> IsDependent |= Found.wasNotFoundInCurrentInstantiation(); >> } >> >> - if (!SS.isSet() && (ObjectType.isNull() || Found.empty())) { >> + if (SS.isEmpty() && (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 >> @@ -470,7 +473,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, >> if (Found.isAmbiguous()) >> return false; >> >> - if (ATK && !SS.isSet() && ObjectType.isNull() && >> TemplateKWLoc.isInvalid()) { >> + if (ATK && SS.isEmpty() && ObjectType.isNull() && >> TemplateKWLoc.isInvalid()) { >> // C++2a [temp.names]p2: >> // A name is also considered to refer to a template if it is an >> // unqualified-id followed by a < and name lookup finds either one >> or more >> @@ -3470,6 +3473,10 @@ QualType Sema::CheckTemplateIdType(TemplateName >> Name, >> >> DTN->getIdentifier(), >> TemplateArgs); >> >> + if (Name.getAsAssumedTemplateName() && >> + resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, >> TemplateLoc)) >> + return QualType(); >> + >> TemplateDecl *Template = Name.getAsTemplateDecl(); >> if (!Template || isa<FunctionTemplateDecl>(Template) || >> isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) { >> @@ -4652,95 +4659,111 @@ TemplateNameKind Sema::ActOnTemplateName(Scope >> *S, >> diag::ext_template_outside_of_template) >> << FixItHint::CreateRemoval(TemplateKWLoc); >> >> + if (SS.isInvalid()) >> + return TNK_Non_template; >> + >> + // Figure out where isTemplateName is going to look. >> DeclContext *LookupCtx = nullptr; >> - if (SS.isSet()) >> + if (SS.isNotEmpty()) >> LookupCtx = computeDeclContext(SS, EnteringContext); >> - if (!LookupCtx && ObjectType) >> - LookupCtx = computeDeclContext(ObjectType.get()); >> - if (LookupCtx) { >> - // C++0x [temp.names]p5: >> - // If a name prefixed by the keyword template is not the name of >> - // a template, the program is ill-formed. [Note: the keyword >> - // template may not be applied to non-template members of class >> - // templates. -end note ] [ Note: as is the case with the >> - // typename prefix, the template prefix is allowed in cases >> - // where it is not strictly necessary; i.e., when the >> - // nested-name-specifier or the expression on the left of the -> >> - // or . is not dependent on a template-parameter, or the use >> - // does not appear in the scope of a template. -end note] >> - // >> - // Note: C++03 was more strict here, because it banned the use of >> - // the "template" keyword prior to a template-name that was not a >> - // dependent name. C++ DR468 relaxed this requirement (the >> - // "template" keyword is now permitted). We follow the C++0x >> - // rules, even in C++03 mode with a warning, retroactively applying >> the DR. >> - bool MemberOfUnknownSpecialization; >> - TemplateNameKind TNK = isTemplateName(S, SS, >> TemplateKWLoc.isValid(), Name, >> - ObjectType, EnteringContext, >> Result, >> - MemberOfUnknownSpecialization); >> - if (TNK == TNK_Non_template && MemberOfUnknownSpecialization) { >> - // This is a dependent template. Handle it below. >> - } else if (TNK == TNK_Non_template) { >> - // 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.getBeginLoc(), >> - LookupOrdinaryName); >> - bool MOUS; >> - if (!LookupTemplateName(R, S, SS, ObjectType.get(), >> EnteringContext, >> - MOUS, TemplateKWLoc) && !R.isAmbiguous()) >> + else if (ObjectType) >> + LookupCtx = computeDeclContext(GetTypeFromParser(ObjectType)); >> + >> + // C++0x [temp.names]p5: >> + // If a name prefixed by the keyword template is not the name of >> + // a template, the program is ill-formed. [Note: the keyword >> + // template may not be applied to non-template members of class >> + // templates. -end note ] [ Note: as is the case with the >> + // typename prefix, the template prefix is allowed in cases >> + // where it is not strictly necessary; i.e., when the >> + // nested-name-specifier or the expression on the left of the -> >> + // or . is not dependent on a template-parameter, or the use >> + // does not appear in the scope of a template. -end note] >> + // >> + // Note: C++03 was more strict here, because it banned the use of >> + // the "template" keyword prior to a template-name that was not a >> + // dependent name. C++ DR468 relaxed this requirement (the >> + // "template" keyword is now permitted). We follow the C++0x >> + // rules, even in C++03 mode with a warning, retroactively applying >> the DR. >> + bool MemberOfUnknownSpecialization; >> + TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), >> Name, >> + ObjectType, EnteringContext, >> Result, >> + MemberOfUnknownSpecialization); >> + if (TNK != TNK_Non_template) { >> + // We resolved this to a (non-dependent) template name. Return it. >> + auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx); >> + if (!AllowInjectedClassName && SS.isNotEmpty() && LookupRD && >> + Name.getKind() == UnqualifiedIdKind::IK_Identifier && >> + Name.Identifier && LookupRD->getIdentifier() == Name.Identifier) >> { >> + // C++14 [class.qual]p2: >> + // In a lookup in which function names are not ignored and the >> + // nested-name-specifier nominates a class C, if the name >> specified >> + // [...] is the injected-class-name of C, [...] the name is >> instead >> + // considered to name the constructor >> + // >> + // We don't get here if naming the constructor would be valid, so >> we >> + // just reject immediately and recover by treating the >> + // injected-class-name as naming the template. >> + Diag(Name.getBeginLoc(), >> + diag::ext_out_of_line_qualified_id_type_names_constructor) >> + << Name.Identifier >> + << 0 /*injected-class-name used as template name*/ >> + << TemplateKWLoc.isValid(); >> + } >> + return TNK; >> + } >> + >> + if (!MemberOfUnknownSpecialization) { >> + // Didn't find a template name, and the lookup wasn't dependent. >> + // 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.getBeginLoc(), >> + LookupOrdinaryName); >> + bool MOUS; >> + // FIXME: If LookupTemplateName fails here, we'll have produced its >> + // diagnostics twice. >> + if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, >> + MOUS, TemplateKWLoc) && !R.isAmbiguous()) { >> + if (LookupCtx) >> Diag(Name.getBeginLoc(), diag::err_no_member) >> << DNI.getName() << LookupCtx << SS.getRange(); >> - return TNK_Non_template; >> - } else { >> - // We found something; return it. >> - auto *LookupRD = dyn_cast<CXXRecordDecl>(LookupCtx); >> - if (!AllowInjectedClassName && SS.isSet() && LookupRD && >> - Name.getKind() == UnqualifiedIdKind::IK_Identifier && >> - Name.Identifier && LookupRD->getIdentifier() == >> Name.Identifier) { >> - // C++14 [class.qual]p2: >> - // In a lookup in which function names are not ignored and the >> - // nested-name-specifier nominates a class C, if the name >> specified >> - // [...] is the injected-class-name of C, [...] the name is >> instead >> - // considered to name the constructor >> - // >> - // We don't get here if naming the constructor would be valid, >> so we >> - // just reject immediately and recover by treating the >> - // injected-class-name as naming the template. >> - Diag(Name.getBeginLoc(), >> - diag::ext_out_of_line_qualified_id_type_names_constructor) >> - << Name.Identifier >> - << 0 /*injected-class-name used as template name*/ >> - << 1 /*'template' keyword was used*/; >> - } >> - return TNK; >> + else >> + Diag(Name.getBeginLoc(), diag::err_undeclared_use) >> + << DNI.getName() << SS.getRange(); >> } >> + return TNK_Non_template; >> } >> >> NestedNameSpecifier *Qualifier = SS.getScopeRep(); >> >> switch (Name.getKind()) { >> case UnqualifiedIdKind::IK_Identifier: >> - Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, >> - >> Name.Identifier)); >> + Result = TemplateTy::make( >> + Context.getDependentTemplateName(Qualifier, Name.Identifier)); >> return TNK_Dependent_template_name; >> >> case UnqualifiedIdKind::IK_OperatorFunctionId: >> - Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, >> - >> Name.OperatorFunctionId.Operator)); >> + Result = TemplateTy::make(Context.getDependentTemplateName( >> + Qualifier, Name.OperatorFunctionId.Operator)); >> return TNK_Function_template; >> >> case UnqualifiedIdKind::IK_LiteralOperatorId: >> - llvm_unreachable("literal operator id cannot have a dependent >> scope"); >> + // This is a kind of template name, but can never occur in a >> dependent >> + // scope (literal operators can only be declared at namespace scope). >> + break; >> >> default: >> break; >> } >> >> - Diag(Name.getBeginLoc(), diag::err_template_kw_refers_to_non_template) >> + // This name cannot possibly name a dependent template. Diagnose this >> now >> + // rather than building a dependent template name that can never be >> valid. >> + Diag(Name.getBeginLoc(), >> + diag::err_template_kw_refers_to_dependent_non_template) >> << GetNameFromUnqualifiedId(Name).getName() << >> Name.getSourceRange() >> - << TemplateKWLoc; >> + << TemplateKWLoc.isValid() << TemplateKWLoc; >> return TNK_Non_template; >> } >> >> >> diff --git a/clang/test/Parser/cxx-decl.cpp >> b/clang/test/Parser/cxx-decl.cpp >> index ba1cce419a46..dbf3a3e70bb0 100644 >> --- a/clang/test/Parser/cxx-decl.cpp >> +++ b/clang/test/Parser/cxx-decl.cpp >> @@ -240,8 +240,7 @@ namespace PR17255 { >> void foo() { >> typename A::template B<> c; // expected-error {{use of undeclared >> identifier 'A'}} >> #if __cplusplus <= 199711L >> - // expected-error@-2 {{'typename' occurs outside of a template}} >> - // expected-error@-3 {{'template' keyword outside of a template}} >> + // expected-error@-2 {{'template' keyword outside of a template}} >> #endif >> } >> } >> >> diff --git a/clang/test/SemaCXX/literal-operators.cpp >> b/clang/test/SemaCXX/literal-operators.cpp >> index 304aa7cab7f3..834d5ec7923e 100644 >> --- a/clang/test/SemaCXX/literal-operators.cpp >> +++ b/clang/test/SemaCXX/literal-operators.cpp >> @@ -47,3 +47,7 @@ template <unsigned long long...> void operator "" >> _invalid(); // expected-error >> _Complex float operator""if(long double); // expected-warning >> {{reserved}} >> _Complex float test_if_1() { return 2.0f + 1.5if; }; >> void test_if_2() { "foo"if; } // expected-error {{no matching literal >> operator for call to 'operator""if'}} >> + >> +template<typename T> void dependent_member_template() { >> + T().template operator""_foo<int>(); // expected-error >> {{'operator""_foo' following the 'template' keyword cannot refer to a >> dependent template}} >> +} >> >> diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp >> b/clang/test/SemaCXX/pseudo-destructors.cpp >> index b71b523de683..292324893dd0 100644 >> --- a/clang/test/SemaCXX/pseudo-destructors.cpp >> +++ b/clang/test/SemaCXX/pseudo-destructors.cpp >> @@ -119,3 +119,54 @@ void test2(Foo d) { >> d.~Derived(); // expected-error {{member reference type >> 'dotPointerAccess::Foo' (aka 'dotPointerAccess::Derived *') is a pointer; >> did you mean to use '->'}} >> } >> } >> + >> +int pr45294 = 1 .~undeclared_tempate_name<>(); // expected-error {{use >> of undeclared 'undeclared_tempate_name'}} >> + >> +namespace TwoPhaseLookup { >> + namespace NonTemplate { >> + struct Y {}; >> + using G = Y; >> + template<typename T> void f(T *p) { p->~G(); } // expected-error >> {{no member named '~Y'}} >> + void h1(Y *p) { p->~G(); } >> + void h2(Y *p) { f(p); } >> + namespace N { struct G{}; } >> + void h3(N::G *p) { p->~G(); } >> + void h4(N::G *p) { f(p); } // expected-note {{instantiation of}} >> + } >> + >> + namespace NonTemplateUndeclared { >> + struct Y {}; >> + template<typename T> void f(T *p) { p->~G(); } // expected-error >> {{undeclared identifier 'G' in destructor name}} >> + using G = Y; >> + void h1(Y *p) { p->~G(); } >> + void h2(Y *p) { f(p); } // expected-note {{instantiation of}} >> + namespace N { struct G{}; } >> + void h3(N::G *p) { p->~G(); } >> + void h4(N::G *p) { f(p); } >> + } >> + >> + namespace Template { >> + template<typename T> struct Y {}; >> + template<class U> using G = Y<U>; >> + template<typename T> void f(T *p) { p->~G<int>(); } // >> expected-error {{no member named '~Y'}} >> + void h1(Y<int> *p) { p->~G<int>(); } >> + void h2(Y<int> *p) { f(p); } >> + namespace N { template<typename T> struct G {}; } >> + void h3(N::G<int> *p) { p->~G<int>(); } >> + void h4(N::G<int> *p) { f(p); } // expected-note {{instantiation of}} >> + } >> + >> + namespace TemplateUndeclared { >> + template<typename T> struct Y {}; >> + // FIXME: Formally, this is ill-formed before we hit any >> instantiation, >> + // because we aren't supposed to treat the '<' as introducing a >> template >> + // name. >> + template<typename T> void f(T *p) { p->~G<int>(); } // >> expected-error {{no member named 'G'}} >> + template<class U> using G = Y<U>; >> + void h1(Y<int> *p) { p->~G<int>(); } >> + void h2(Y<int> *p) { f(p); } // expected-note {{instantiation of}} >> + namespace N { template<typename T> struct G {}; } >> + void h3(N::G<int> *p) { p->~G<int>(); } >> + void h4(N::G<int> *p) { f(p); } >> + } >> +} >> >> diff --git a/clang/test/SemaTemplate/nested-name-spec-template.cpp >> b/clang/test/SemaTemplate/nested-name-spec-template.cpp >> index 3e7f506040a6..07dd41bfe27b 100644 >> --- a/clang/test/SemaTemplate/nested-name-spec-template.cpp >> +++ b/clang/test/SemaTemplate/nested-name-spec-template.cpp >> @@ -142,8 +142,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{{no member named 'n'}} >> + int s<T>::template n<T>::* f; // expected-error{{implicit >> instantiation of undefined template 'PR9449::s<int>'}} >> } >> >> template void f<int>(); // expected-note{{in instantiation of}} >> >> >> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits@lists.llvm.org >> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits