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