[clang] 499b2a8 - PR45294: Fix handling of assumed template names looked up in the lexical

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 30 18:50:02 PDT 2020


Already fixed in llvmorg-11-init-7209-g33087323007 :)

On Mon, 30 Mar 2020 at 18:30, Hubert Tong via cfe-commits <
cfe-commits at 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 at 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 at -2 {{'typename' occurs outside of a template}}
>> -  // expected-error at -3 {{'template' keyword outside of a template}}
>> +  // expected-error at -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 at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200330/924f6660/attachment-0001.html>


More information about the cfe-commits mailing list