<div dir="ltr"><div dir="ltr">On Tue, 13 Aug 2019 at 18:09, Alex L via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Hi Richard,<div><br></div><div>Did you get a chance to look at the issue that was reported by Akira? It's causing a lot of pain on our end.</div></div></blockquote><div><br></div><div>Sorry, I missed that email. I'll take a look tomorrow.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>Thanks,</div><div>Alex</div><div><br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, 8 Jul 2019 at 18:27, Akira Hatanaka via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">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"><div style="overflow-wrap: break-word;">Hi Richard,<div><br></div><div>It looks like this patch is causing clang to reject the following code, which used to compile fine:</div><div><br></div><div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">$ cat test.cpp</span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">typedef __attribute__((__ext_vector_type__(2))) float vector_float2;</span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,0,0);min-height:13px"><span style="font-variant-ligatures:no-common-ligatures"></span><br></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">bool foo123(vector_float2 &A, vector_float2 &B)</span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">{</span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">  return A.x < B.x && B.y > A.y;</span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="font-variant-ligatures:no-common-ligatures">}</span></div><div><br><blockquote type="cite"><div>On May 8, 2019, at 8:31 PM, Richard Smith via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:</div><br class="gmail-m_-4421249378052617701gmail-m_3852814868304150230Apple-interchange-newline"><div><div>Author: rsmith<br>Date: Wed May  8 20:31:27 2019<br>New Revision: 360308<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=360308&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=360308&view=rev</a><br>Log:<br>[c++20] Implement P0846R0: allow (ADL-only) calls to template-ids whose<br>template name is not visible to unqualified lookup.<br><br>In order to support this without a severe degradation in our ability to<br>diagnose typos in template names, this change significantly restructures<br>the way we handle template-id-shaped syntax for which lookup of the<br>template name finds nothing.<br><br>Instead of eagerly diagnosing an undeclared template name, we now form a<br>placeholder template-name representing a name that is known to not find<br>any templates. When the parser sees such a name, it attempts to<br>disambiguate whether we have a less-than comparison or a template-id.<br>Any diagnostics or typo-correction for the name are delayed until its<br>point of use.<br><br>The upshot should be a small improvement of our diagostic quality<br>overall: we now take more syntactic context into account when trying to<br>resolve an undeclared identifier on the left hand side of a '<'. In<br>fact, this works well enough that the backwards-compatible portion (for<br>an undeclared identifier rather than a lookup that finds functions but<br>no function templates) is enabled in all language modes.<br><br>Added:<br>    cfe/trunk/test/SemaCXX/cxx2a-adl-only-template-id.cpp<br>Modified:<br>    cfe/trunk/include/clang/AST/ASTContext.h<br>    cfe/trunk/include/clang/AST/DeclarationName.h<br>    cfe/trunk/include/clang/AST/TemplateName.h<br>    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td<br>    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>    cfe/trunk/include/clang/Basic/TemplateKinds.h<br>    cfe/trunk/include/clang/Parse/Parser.h<br>    cfe/trunk/include/clang/Sema/Sema.h<br>    cfe/trunk/lib/AST/ASTContext.cpp<br>    cfe/trunk/lib/AST/ASTImporter.cpp<br>    cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp<br>    cfe/trunk/lib/AST/ItaniumMangle.cpp<br>    cfe/trunk/lib/AST/ODRHash.cpp<br>    cfe/trunk/lib/AST/TemplateName.cpp<br>    cfe/trunk/lib/Parse/ParseDecl.cpp<br>    cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>    cfe/trunk/lib/Parse/ParseExprCXX.cpp<br>    cfe/trunk/lib/Parse/ParseTemplate.cpp<br>    cfe/trunk/lib/Parse/ParseTentative.cpp<br>    cfe/trunk/lib/Parse/Parser.cpp<br>    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp<br>    cfe/trunk/lib/Sema/SemaDecl.cpp<br>    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>    cfe/trunk/lib/Sema/SemaExpr.cpp<br>    cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>    cfe/trunk/lib/Sema/SemaOverload.cpp<br>    cfe/trunk/lib/Sema/SemaTemplate.cpp<br>    cfe/trunk/lib/Serialization/ASTReader.cpp<br>    cfe/trunk/lib/Serialization/ASTWriter.cpp<br>    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp<br>    cfe/trunk/test/CXX/drs/dr2xx.cpp<br>    cfe/trunk/test/CXX/drs/dr6xx.cpp<br>    cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p5.cpp<br>    cfe/trunk/test/FixIt/typo-crash.cpp<br>    cfe/trunk/test/Misc/diag-template-diffing.cpp<br>    cfe/trunk/test/Modules/module-private.cpp<br>    cfe/trunk/test/Modules/submodules-merge-defs.cpp<br>    cfe/trunk/test/Parser/cxx-ambig-init-templ.cpp<br>    cfe/trunk/test/Parser/cxx-template-argument.cpp<br>    cfe/trunk/test/Parser/cxx-template-decl.cpp<br>    cfe/trunk/test/SemaCXX/alias-template.cpp<br>    cfe/trunk/test/SemaCXX/class.cpp<br>    cfe/trunk/test/SemaCXX/destructor.cpp<br>    cfe/trunk/test/SemaCXX/invalid-member-expr.cpp<br>    cfe/trunk/test/SemaCXX/typo-correction.cpp<br>    cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp<br>    cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp<br>    cfe/trunk/test/SemaTemplate/rdar9173693.cpp<br>    cfe/trunk/test/SemaTemplate/recovery-crash.cpp<br>    cfe/trunk/tools/libclang/CIndex.cpp<br>    cfe/trunk/www/cxx_status.html<br><br>Modified: cfe/trunk/include/clang/AST/ASTContext.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/AST/ASTContext.h (original)<br>+++ cfe/trunk/include/clang/AST/ASTContext.h Wed May  8 20:31:27 2019<br>@@ -1977,6 +1977,7 @@ public:<br><br>   TemplateName getOverloadedTemplateName(UnresolvedSetIterator Begin,<br>                                          UnresolvedSetIterator End) const;<br>+  TemplateName getAssumedTemplateName(DeclarationName Name) const;<br><br>   TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,<br>                                         bool TemplateKeyword,<br><br>Modified: cfe/trunk/include/clang/AST/DeclarationName.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclarationName.h?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclarationName.h?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/AST/DeclarationName.h (original)<br>+++ cfe/trunk/include/clang/AST/DeclarationName.h Wed May  8 20:31:27 2019<br>@@ -863,4 +863,24 @@ struct DenseMapInfo<clang::DeclarationNa<br><br> } // namespace llvm<br><br>+// The definition of AssumedTemplateStorage is factored out of TemplateName to<br>+// resolve a cyclic dependency between it and DeclarationName (via Type).<br>+namespace clang {<br>+<br>+/// A structure for storing the information associated with a name that has<br>+/// been assumed to be a template name (despite finding no TemplateDecls).<br>+class AssumedTemplateStorage : public UncommonTemplateNameStorage {<br>+  friend class ASTContext;<br>+<br>+  AssumedTemplateStorage(DeclarationName Name)<br>+      : UncommonTemplateNameStorage(Assumed, 0), Name(Name) {}<br>+  DeclarationName Name;<br>+<br>+public:<br>+  /// Get the name of the template.<br>+  DeclarationName getDeclName() const { return Name; }<br>+};<br>+<br>+} // namespace clang<br>+<br> #endif // LLVM_CLANG_AST_DECLARATIONNAME_H<br><br>Modified: cfe/trunk/include/clang/AST/TemplateName.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateName.h?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateName.h?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/AST/TemplateName.h (original)<br>+++ cfe/trunk/include/clang/AST/TemplateName.h Wed May  8 20:31:27 2019<br>@@ -31,6 +31,7 @@ class NamedDecl;<br> class NestedNameSpecifier;<br> enum OverloadedOperatorKind : int;<br> class OverloadedTemplateStorage;<br>+class AssumedTemplateStorage;<br> class PartialDiagnostic;<br> struct PrintingPolicy;<br> class QualifiedTemplateName;<br>@@ -46,6 +47,7 @@ class UncommonTemplateNameStorage {<br> protected:<br>   enum Kind {<br>     Overloaded,<br>+    Assumed, // defined in DeclarationName.h<br>     SubstTemplateTemplateParm,<br>     SubstTemplateTemplateParmPack<br>   };<br>@@ -78,6 +80,12 @@ public:<br>              : nullptr;<br>   }<br><br>+  AssumedTemplateStorage *getAsAssumedTemplateName()  {<br>+    return Bits.Kind == Assumed<br>+             ? reinterpret_cast<AssumedTemplateStorage *>(this)<br>+             : nullptr;<br>+  }<br>+<br>   SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() {<br>     return Bits.Kind == SubstTemplateTemplateParm<br>              ? reinterpret_cast<SubstTemplateTemplateParmStorage *>(this)<br>@@ -194,6 +202,10 @@ public:<br>     /// A set of overloaded template declarations.<br>     OverloadedTemplate,<br><br>+    /// An unqualified-id that has been assumed to name a function template<br>+    /// that will be found by ADL.<br>+    AssumedTemplate,<br>+<br>     /// A qualified template name, where the qualification is kept<br>     /// to describe the source code as written.<br>     QualifiedTemplate,<br>@@ -215,6 +227,7 @@ public:<br>   TemplateName() = default;<br>   explicit TemplateName(TemplateDecl *Template);<br>   explicit TemplateName(OverloadedTemplateStorage *Storage);<br>+  explicit TemplateName(AssumedTemplateStorage *Storage);<br>   explicit TemplateName(SubstTemplateTemplateParmStorage *Storage);<br>   explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage);<br>   explicit TemplateName(QualifiedTemplateName *Qual);<br>@@ -236,7 +249,7 @@ public:<br>   TemplateDecl *getAsTemplateDecl() const;<br><br>   /// Retrieve the underlying, overloaded function template<br>-  // declarations that this template name refers to, if known.<br>+  /// declarations that this template name refers to, if known.<br>   ///<br>   /// \returns The set of overloaded function templates that this template<br>   /// name refers to, if known. If the template name does not refer to a<br>@@ -244,6 +257,10 @@ public:<br>   /// refers to a single template, returns NULL.<br>   OverloadedTemplateStorage *getAsOverloadedTemplate() const;<br><br>+  /// Retrieve information on a name that has been assumed to be a<br>+  /// template-name in order to permit a call via ADL.<br>+  AssumedTemplateStorage *getAsAssumedTemplateName() const;<br>+<br>   /// Retrieve the substituted template template parameter, if<br>   /// known.<br>   ///<br><br>Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)<br>+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Wed May  8 20:31:27 2019<br>@@ -744,7 +744,8 @@ def err_typename_refers_to_non_type_temp<br> def err_expected_type_name_after_typename : Error<<br>   "expected an identifier or template-id after '::'">;<br> def err_explicit_spec_non_template : Error<<br>-  "explicit %select{specialization|instantiation}0 of non-template %1 %2">;<br>+  "explicit %select{specialization|instantiation}0 of "<br>+  "%select{non-|undeclared }3template %1 %2">;<br><br> def err_default_template_template_parameter_not_template : Error<<br>   "default template argument for a template template parameter must be a class "<br><br>Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed May  8 20:31:27 2019<br>@@ -3963,6 +3963,15 @@ def err_template_member_noparams : Error<br> def err_template_tag_noparams : Error<<br>   "extraneous 'template<>' in declaration of %0 %1">;<br><br>+def warn_cxx17_compat_adl_only_template_id : Warning<<br>+  "use of function template name with no prior function template "<br>+  "declaration in function call with explicit template arguments "<br>+  "is incompatible with C++ standards before C++2a">,<br>+  InGroup<CXXPre2aCompat>, DefaultIgnore;<br>+def ext_adl_only_template_id : ExtWarn<<br>+  "use of function template name with no prior declaration in function call "<br>+  "with explicit template arguments is a C++2a extension">, InGroup<CXX2a>;<br>+<br> // C++ Template Argument Lists<br> def err_template_missing_args : Error<<br>   "use of "<br><br>Modified: cfe/trunk/include/clang/Basic/TemplateKinds.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TemplateKinds.h?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TemplateKinds.h?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Basic/TemplateKinds.h (original)<br>+++ cfe/trunk/include/clang/Basic/TemplateKinds.h Wed May  8 20:31:27 2019<br>@@ -21,7 +21,8 @@ enum TemplateNameKind {<br>   /// The name does not refer to a template.<br>   TNK_Non_template = 0,<br>   /// The name refers to a function template or a set of overloaded<br>-  /// functions that includes at least one function template.<br>+  /// functions that includes at least one function template, or (in C++20)<br>+  /// refers to a set of non-template functions but is followed by a '<'.<br>   TNK_Function_template,<br>   /// The name refers to a template whose specialization produces a<br>   /// type. The template itself could be a class template, template<br>@@ -42,7 +43,11 @@ enum TemplateNameKind {<br>   /// whether the template name is assumed to refer to a type template or a<br>   /// function template depends on the context in which the template<br>   /// name occurs.<br>-  TNK_Dependent_template_name<br>+  TNK_Dependent_template_name,<br>+  /// Lookup for the name failed, but we're assuming it was a template name<br>+  /// anyway. In C++20, this is mandatory in order to parse ADL-only function<br>+  /// template specialization calls.<br>+  TNK_Undeclared_template,<br> };<br><br> }<br><br>Modified: cfe/trunk/include/clang/Parse/Parser.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Parse/Parser.h (original)<br>+++ cfe/trunk/include/clang/Parse/Parser.h Wed May  8 20:31:27 2019<br>@@ -2303,13 +2303,18 @@ private:<br>   /// Doesn't consume tokens.<br>   TPResult<br>   isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False,<br>-                            bool *HasMissingTypename = nullptr);<br>+                            bool *InvalidAsDeclSpec = nullptr);<br><br>   /// Given that isCXXDeclarationSpecifier returns \c TPResult::True or<br>   /// \c TPResult::Ambiguous, determine whether the decl-specifier would be<br>   /// a type-specifier other than a cv-qualifier.<br>   bool isCXXDeclarationSpecifierAType();<br><br>+  /// Determine whether the current token sequence might be<br>+  ///   '<' template-argument-list '>'<br>+  /// rather than a less-than expression.<br>+  TPResult isTemplateArgumentList(unsigned TokensToSkip);<br>+<br>   /// Determine whether an identifier has been tentatively declared as a<br>   /// non-type. Such tentative declarations should not be found to name a type<br>   /// during a tentative parse, but also should not be annotated as a non-type.<br>@@ -2994,7 +2999,6 @@ private:<br>                                UnqualifiedId &TemplateName,<br>                                bool AllowTypeAnnotation = true);<br>   void AnnotateTemplateIdTokenAsType(bool IsClassName = false);<br>-  bool IsTemplateArgumentList(unsigned Skip = 0);<br>   bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);<br>   ParsedTemplateArgument ParseTemplateTemplateArgument();<br>   ParsedTemplateArgument ParseTemplateArgument();<br><br>Modified: cfe/trunk/include/clang/Sema/Sema.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>+++ cfe/trunk/include/clang/Sema/Sema.h Wed May  8 20:31:27 2019<br>@@ -1823,7 +1823,8 @@ public:<br>     NC_NestedNameSpecifier,<br>     NC_TypeTemplate,<br>     NC_VarTemplate,<br>-    NC_FunctionTemplate<br>+    NC_FunctionTemplate,<br>+    NC_UndeclaredTemplate,<br>   };<br><br>   class NameClassification {<br>@@ -1871,6 +1872,12 @@ public:<br>       return Result;<br>     }<br><br>+    static NameClassification UndeclaredTemplate(TemplateName Name) {<br>+      NameClassification Result(NC_UndeclaredTemplate);<br>+      Result.Template = Name;<br>+      return Result;<br>+    }<br>+<br>     NameClassificationKind getKind() const { return Kind; }<br><br>     ParsedType getType() const {<br>@@ -1885,7 +1892,7 @@ public:<br><br>     TemplateName getTemplateName() const {<br>       assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate ||<br>-             Kind == NC_VarTemplate);<br>+             Kind == NC_VarTemplate || Kind == NC_UndeclaredTemplate);<br>       return Template;<br>     }<br><br>@@ -1897,6 +1904,8 @@ public:<br>         return TNK_Function_template;<br>       case NC_VarTemplate:<br>         return TNK_Var_template;<br>+      case NC_UndeclaredTemplate:<br>+        return TNK_Undeclared_template;<br>       default:<br>         llvm_unreachable("unsupported name classification.");<br>       }<br>@@ -6256,7 +6265,8 @@ public:<br>                                      bool AllowDependent = true);<br>   bool hasAnyAcceptableTemplateNames(LookupResult &R,<br>                                      bool AllowFunctionTemplates = true,<br>-                                     bool AllowDependent = true);<br>+                                     bool AllowDependent = true,<br>+                                     bool AllowNonTemplateFunctions = false);<br>   /// Try to interpret the lookup result D as a template-name.<br>   ///<br>   /// \param D A declaration found by name lookup.<br>@@ -6268,10 +6278,20 @@ public:<br>                                    bool AllowFunctionTemplates = true,<br>                                    bool AllowDependent = true);<br><br>+  enum class AssumedTemplateKind {<br>+    /// This is not assumed to be a template name.<br>+    None,<br>+    /// This is assumed to be a template name because lookup found nothing.<br>+    FoundNothing,<br>+    /// This is assumed to be a template name because lookup found one or more<br>+    /// functions (but no function templates).<br>+    FoundFunctions,<br>+  };<br>   bool LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,<br>                           QualType ObjectType, bool EnteringContext,<br>                           bool &MemberOfUnknownSpecialization,<br>-                          SourceLocation TemplateKWLoc = SourceLocation());<br>+                          SourceLocation TemplateKWLoc = SourceLocation(),<br>+                          AssumedTemplateKind *ATK = nullptr);<br><br>   TemplateNameKind isTemplateName(Scope *S,<br>                                   CXXScopeSpec &SS,<br>@@ -6282,6 +6302,20 @@ public:<br>                                   TemplateTy &Template,<br>                                   bool &MemberOfUnknownSpecialization);<br><br>+  /// Try to resolve an undeclared template name as a type template.<br>+  ///<br>+  /// Sets II to the identifier corresponding to the template name, and updates<br>+  /// Name to a corresponding (typo-corrected) type template name and TNK to<br>+  /// the corresponding kind, if possible.<br>+  void ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &Name,<br>+                                       TemplateNameKind &TNK,<br>+                                       SourceLocation NameLoc,<br>+                                       IdentifierInfo *&II);<br>+<br>+  bool resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name,<br>+                                        SourceLocation NameLoc,<br>+                                        bool Diagnose = true);<br>+<br>   /// Determine whether a particular identifier might be the name in a C++1z<br>   /// deduction-guide declaration.<br>   bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name,<br>@@ -6391,14 +6425,11 @@ public:<br>                               TemplateArgumentListInfo &TemplateArgs);<br><br>   TypeResult<br>-  ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,<br>+  ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,<br>                       TemplateTy Template, IdentifierInfo *TemplateII,<br>-                      SourceLocation TemplateIILoc,<br>-                      SourceLocation LAngleLoc,<br>-                      ASTTemplateArgsPtr TemplateArgs,<br>-                      SourceLocation RAngleLoc,<br>-                      bool IsCtorOrDtorName = false,<br>-                      bool IsClassName = false);<br>+                      SourceLocation TemplateIILoc, SourceLocation LAngleLoc,<br>+                      ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc,<br>+                      bool IsCtorOrDtorName = false, bool IsClassName = false);<br><br>   /// Parsed an elaborated-type-specifier that refers to a template-id,<br>   /// such as \c class T::template apply<U>.<br><br>Modified: cfe/trunk/lib/AST/ASTContext.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/AST/ASTContext.cpp (original)<br>+++ cfe/trunk/lib/AST/ASTContext.cpp Wed May  8 20:31:27 2019<br>@@ -5226,6 +5226,11 @@ ASTContext::getNameForTemplate(TemplateN<br>     return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc);<br>   }<br><br>+  case TemplateName::AssumedTemplate: {<br>+    AssumedTemplateStorage *Storage = Name.getAsAssumedTemplateName();<br>+    return DeclarationNameInfo(Storage->getDeclName(), NameLoc);<br>+  }<br>+<br>   case TemplateName::DependentTemplate: {<br>     DependentTemplateName *DTN = Name.getAsDependentTemplateName();<br>     DeclarationName DName;<br>@@ -5273,7 +5278,8 @@ TemplateName ASTContext::getCanonicalTem<br>   }<br><br>   case TemplateName::OverloadedTemplate:<br>-    llvm_unreachable("cannot canonicalize overloaded template");<br>+  case TemplateName::AssumedTemplate:<br>+    llvm_unreachable("cannot canonicalize unresolved template");<br><br>   case TemplateName::DependentTemplate: {<br>     DependentTemplateName *DTN = Name.getAsDependentTemplateName();<br>@@ -7620,6 +7626,13 @@ ASTContext::getOverloadedTemplateName(Un<br>   return TemplateName(OT);<br> }<br><br>+/// Retrieve a template name representing an unqualified-id that has been<br>+/// assumed to name a template for ADL purposes.<br>+TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const {<br>+  auto *OT = new (*this) AssumedTemplateStorage(Name);<br>+  return TemplateName(OT);<br>+}<br>+<br> /// Retrieve the template name that represents a qualified<br> /// template name such as \c std::vector.<br> TemplateName<br><br>Modified: cfe/trunk/lib/AST/ASTImporter.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/AST/ASTImporter.cpp (original)<br>+++ cfe/trunk/lib/AST/ASTImporter.cpp Wed May  8 20:31:27 2019<br>@@ -8126,6 +8126,14 @@ Expected<TemplateName> ASTImporter::Impo<br>                                                ToTemplates.end());<br>   }<br><br>+  case TemplateName::AssumedTemplate: {<br>+    AssumedTemplateStorage *FromStorage = From.getAsAssumedTemplateName();<br>+    auto DeclNameOrErr = Import_New(FromStorage->getDeclName());<br>+    if (!DeclNameOrErr)<br>+      return DeclNameOrErr.takeError();<br>+    return ToContext.getAssumedTemplateName(*DeclNameOrErr);<br>+  }<br>+<br>   case TemplateName::QualifiedTemplate: {<br>     QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName();<br>     auto QualifierOrErr = Import_New(QTN->getQualifier());<br><br>Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original)<br>+++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Wed May  8 20:31:27 2019<br>@@ -180,6 +180,12 @@ static bool IsStructurallyEquivalent(Str<br>     return I1 == E1 && I2 == E2;<br>   }<br><br>+  case TemplateName::AssumedTemplate: {<br>+    AssumedTemplateStorage *TN1 = N1.getAsAssumedTemplateName(),<br>+                           *TN2 = N1.getAsAssumedTemplateName();<br>+    return TN1->getDeclName() == TN2->getDeclName();<br>+  }<br>+<br>   case TemplateName::QualifiedTemplate: {<br>     QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(),<br>                           *QN2 = N2.getAsQualifiedTemplateName();<br><br>Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)<br>+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Wed May  8 20:31:27 2019<br>@@ -1891,6 +1891,7 @@ void CXXNameMangler::mangleType(Template<br>     break;<br><br>   case TemplateName::OverloadedTemplate:<br>+  case TemplateName::AssumedTemplate:<br>     llvm_unreachable("can't mangle an overloaded template name as a <type>");<br><br>   case TemplateName::DependentTemplate: {<br>@@ -2030,6 +2031,7 @@ bool CXXNameMangler::mangleUnresolvedTyp<br>     }<br><br>     case TemplateName::OverloadedTemplate:<br>+    case TemplateName::AssumedTemplate:<br>     case TemplateName::DependentTemplate:<br>       llvm_unreachable("invalid base for a template specialization type");<br><br><br>Modified: cfe/trunk/lib/AST/ODRHash.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHash.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHash.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/AST/ODRHash.cpp (original)<br>+++ cfe/trunk/lib/AST/ODRHash.cpp Wed May  8 20:31:27 2019<br>@@ -140,6 +140,7 @@ void ODRHash::AddTemplateName(TemplateNa<br>     break;<br>   // TODO: Support these cases.<br>   case TemplateName::OverloadedTemplate:<br>+  case TemplateName::AssumedTemplate:<br>   case TemplateName::QualifiedTemplate:<br>   case TemplateName::DependentTemplate:<br>   case TemplateName::SubstTemplateTemplateParm:<br><br>Modified: cfe/trunk/lib/AST/TemplateName.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TemplateName.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TemplateName.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/AST/TemplateName.cpp (original)<br>+++ cfe/trunk/lib/AST/TemplateName.cpp Wed May  8 20:31:27 2019<br>@@ -66,6 +66,8 @@ TemplateName::TemplateName(void *Ptr) {<br> TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {}<br> TemplateName::TemplateName(OverloadedTemplateStorage *Storage)<br>     : Storage(Storage) {}<br>+TemplateName::TemplateName(AssumedTemplateStorage *Storage)<br>+    : Storage(Storage) {}<br> TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)<br>     : Storage(Storage) {}<br> TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage)<br>@@ -87,6 +89,8 @@ TemplateName::NameKind TemplateName::get<br>     = Storage.get<UncommonTemplateNameStorage*>();<br>   if (uncommon->getAsOverloadedStorage())<br>     return OverloadedTemplate;<br>+  if (uncommon->getAsAssumedTemplateName())<br>+    return AssumedTemplate;<br>   if (uncommon->getAsSubstTemplateTemplateParm())<br>     return SubstTemplateTemplateParm;<br>   return SubstTemplateTemplateParmPack;<br>@@ -113,6 +117,14 @@ OverloadedTemplateStorage *TemplateName:<br>   return nullptr;<br> }<br><br>+AssumedTemplateStorage *TemplateName::getAsAssumedTemplateName() const {<br>+  if (UncommonTemplateNameStorage *Uncommon =<br>+          Storage.dyn_cast<UncommonTemplateNameStorage *>())<br>+    return Uncommon->getAsAssumedTemplateName();<br>+<br>+  return nullptr;<br>+}<br>+<br> SubstTemplateTemplateParmStorage *<br> TemplateName::getAsSubstTemplateTemplateParm() const {<br>   if (UncommonTemplateNameStorage *uncommon =<br>@@ -230,7 +242,9 @@ TemplateName::print(raw_ostream &OS, con<br>   } else if (SubstTemplateTemplateParmPackStorage *SubstPack<br>                                         = getAsSubstTemplateTemplateParmPack())<br>     OS << *SubstPack->getParameterPack();<br>-  else {<br>+  else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {<br>+    Assumed->getDeclName().print(OS, Policy);<br>+  } else {<br>     OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();<br>     (*OTS->begin())->printName(OS);<br>   }<br><br>Modified: cfe/trunk/lib/Parse/ParseDecl.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)<br>+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed May  8 20:31:27 2019<br>@@ -2916,6 +2916,7 @@ Parser::DiagnoseMissingSemiAfterTagDefin<br>       case Sema::NC_Expression:<br>       case Sema::NC_VarTemplate:<br>       case Sema::NC_FunctionTemplate:<br>+      case Sema::NC_UndeclaredTemplate:<br>         // Might be a redeclaration of a prior entity.<br>         break;<br>       }<br>@@ -3386,7 +3387,8 @@ void Parser::ParseDeclarationSpecifiers(<br>       // type-name<br>     case tok::annot_template_id: {<br>       TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);<br>-      if (TemplateId->Kind != TNK_Type_template) {<br>+      if (TemplateId->Kind != TNK_Type_template &&<br>+          TemplateId->Kind != TNK_Undeclared_template) {<br>         // This template-id does not refer to a type name, so we're<br>         // done with the type-specifiers.<br>         goto DoneWithDeclSpec;<br><br>Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)<br>+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Wed May  8 20:31:27 2019<br>@@ -597,10 +597,11 @@ bool Parser::ParseUsingDeclarator(Declar<br><br>   // Parse nested-name-specifier.<br>   IdentifierInfo *LastII = nullptr;<br>-  ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false,<br>-                                 /*MayBePseudoDtor=*/nullptr,<br>-                                 /*IsTypename=*/false,<br>-                                 /*LastII=*/&LastII);<br>+  if (ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false,<br>+                                     /*MayBePseudoDtor=*/nullptr,<br>+                                     /*IsTypename=*/false,<br>+                                     /*LastII=*/&LastII))<br>+    return true;<br>   if (D.SS.isInvalid())<br>     return true;<br><br>@@ -1111,7 +1112,8 @@ TypeResult Parser::ParseBaseTypeSpecifie<br><br>   // Parse optional nested-name-specifier<br>   CXXScopeSpec SS;<br>-  ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);<br>+  if (ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false))<br>+    return true;<br><br>   BaseLoc = Tok.getLocation();<br><br>@@ -1135,7 +1137,8 @@ TypeResult Parser::ParseBaseTypeSpecifie<br>   if (<a href="http://Tok.is" target="_blank">Tok.is</a>(tok::annot_template_id)) {<br>     TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);<br>     if (TemplateId->Kind == TNK_Type_template ||<br>-        TemplateId->Kind == TNK_Dependent_template_name) {<br>+        TemplateId->Kind == TNK_Dependent_template_name ||<br>+        TemplateId->Kind == TNK_Undeclared_template) {<br>       AnnotateTemplateIdTokenAsType(/*IsClassName*/true);<br><br>       assert(<a href="http://Tok.is" target="_blank">Tok.is</a>(tok::annot_typename) && "template-id -> type failed");<br>@@ -1554,6 +1557,36 @@ void Parser::ParseClassSpecifier(tok::To<br><br>   TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;<br><br>+  auto RecoverFromUndeclaredTemplateName = [&](IdentifierInfo *Name,<br>+                                               SourceLocation NameLoc,<br>+                                               SourceRange TemplateArgRange,<br>+                                               bool KnownUndeclared) {<br>+    Diag(NameLoc, diag::err_explicit_spec_non_template)<br>+        << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)<br>+        << TagTokKind << Name << TemplateArgRange << KnownUndeclared;<br>+<br>+    // Strip off the last template parameter list if it was empty, since<br>+    // we've removed its template argument list.<br>+    if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) {<br>+      if (TemplateParams->size() > 1) {<br>+        TemplateParams->pop_back();<br>+      } else {<br>+        TemplateParams = nullptr;<br>+        const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind =<br>+            ParsedTemplateInfo::NonTemplate;<br>+      }<br>+    } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {<br>+      // Pretend this is just a forward declaration.<br>+      TemplateParams = nullptr;<br>+      const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind =<br>+          ParsedTemplateInfo::NonTemplate;<br>+      const_cast<ParsedTemplateInfo &>(TemplateInfo).TemplateLoc =<br>+          SourceLocation();<br>+      const_cast<ParsedTemplateInfo &>(TemplateInfo).ExternLoc =<br>+          SourceLocation();<br>+    }<br>+  };<br>+<br>   // Parse the (optional) class name or simple-template-id.<br>   IdentifierInfo *Name = nullptr;<br>   SourceLocation NameLoc;<br>@@ -1574,38 +1607,26 @@ void Parser::ParseClassSpecifier(tok::To<br>         // try to give any location information for the list.<br>         LAngleLoc = RAngleLoc = SourceLocation();<br>       }<br>-<br>-      Diag(NameLoc, diag::err_explicit_spec_non_template)<br>-          << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)<br>-          << TagTokKind << Name << SourceRange(LAngleLoc, RAngleLoc);<br>-<br>-      // Strip off the last template parameter list if it was empty, since<br>-      // we've removed its template argument list.<br>-      if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) {<br>-        if (TemplateParams->size() > 1) {<br>-          TemplateParams->pop_back();<br>-        } else {<br>-          TemplateParams = nullptr;<br>-          const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind<br>-            = ParsedTemplateInfo::NonTemplate;<br>-        }<br>-      } else if (TemplateInfo.Kind<br>-                                == ParsedTemplateInfo::ExplicitInstantiation) {<br>-        // Pretend this is just a forward declaration.<br>-        TemplateParams = nullptr;<br>-        const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind<br>-          = ParsedTemplateInfo::NonTemplate;<br>-        const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc<br>-          = SourceLocation();<br>-        const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc<br>-          = SourceLocation();<br>-      }<br>+      RecoverFromUndeclaredTemplateName(<br>+          Name, NameLoc, SourceRange(LAngleLoc, RAngleLoc), false);<br>     }<br>   } else if (<a href="http://Tok.is" target="_blank">Tok.is</a>(tok::annot_template_id)) {<br>     TemplateId = takeTemplateIdAnnotation(Tok);<br>     NameLoc = ConsumeAnnotationToken();<br><br>-    if (TemplateId->Kind != TNK_Type_template &&<br>+    if (TemplateId->Kind == TNK_Undeclared_template) {<br>+      // Try to resolve the template name to a type template.<br>+      Actions.ActOnUndeclaredTypeTemplateName(getCurScope(), TemplateId->Template,<br>+                                              TemplateId->Kind, NameLoc, Name);<br>+      if (TemplateId->Kind == TNK_Undeclared_template) {<br>+        RecoverFromUndeclaredTemplateName(<br>+            Name, NameLoc,<br>+            SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc), true);<br>+        TemplateId = nullptr;<br>+      }<br>+    }<br>+<br>+    if (TemplateId && TemplateId->Kind != TNK_Type_template &&<br>         TemplateId->Kind != TNK_Dependent_template_name) {<br>       // The template-name in the simple-template-id refers to<br>       // something other than a class template. Give an appropriate<br>@@ -1616,7 +1637,7 @@ void Parser::ParseClassSpecifier(tok::To<br><br>       // FIXME: Name may be null here.<br>       Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)<br>-        << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range;<br>+          << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range;<br><br>       DS.SetTypeSpecError();<br>       SkipUntil(tok::semi, StopBeforeMatch);<br>@@ -3451,7 +3472,8 @@ void Parser::ParseConstructorInitializer<br> MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {<br>   // parse '::'[opt] nested-name-specifier[opt]<br>   CXXScopeSpec SS;<br>-  ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);<br>+  if (ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false))<br>+    return true;<br><br>   // : identifier<br>   IdentifierInfo *II = nullptr;<br>@@ -3477,11 +3499,14 @@ MemInitResult Parser::ParseMemInitialize<br>                                            ? takeTemplateIdAnnotation(Tok)<br>                                            : nullptr;<br>     if (TemplateId && (TemplateId->Kind == TNK_Type_template ||<br>-                       TemplateId->Kind == TNK_Dependent_template_name)) {<br>+                       TemplateId->Kind == TNK_Dependent_template_name ||<br>+                       TemplateId->Kind == TNK_Undeclared_template)) {<br>       AnnotateTemplateIdTokenAsType(/*IsClassName*/true);<br>       assert(<a href="http://Tok.is" target="_blank">Tok.is</a>(tok::annot_typename) && "template-id -> type failed");<br>       TemplateTypeTy = getTypeAnnotation(Tok);<br>       ConsumeAnnotationToken();<br>+      if (!TemplateTypeTy)<br>+        return true;<br>     } else {<br>       Diag(Tok, diag::err_expected_member_or_base_name);<br>       return true;<br><br>Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)<br>+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed May  8 20:31:27 2019<br>@@ -487,6 +487,14 @@ bool Parser::ParseOptionalCXXScopeSpecif<br>                                                         EnteringContext,<br>                                                         Template,<br>                                               MemberOfUnknownSpecialization)) {<br>+        // If lookup didn't find anything, we treat the name as a template-name<br>+        // anyway. C++20 requires this, and in prior language modes it improves<br>+        // error recovery. But before we commit to this, check that we actually<br>+        // have something that looks like a template-argument-list next.<br>+        if (!IsTypename && TNK == TNK_Undeclared_template &&<br>+            isTemplateArgumentList(1) == TPResult::False)<br>+          break;<br>+<br>         // We have found a template name, so annotate this token<br>         // with a template-id annotation. We do not permit the<br>         // template-id to be translated into a type annotation,<br>@@ -501,7 +509,7 @@ bool Parser::ParseOptionalCXXScopeSpecif<br>       }<br><br>       if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) &&<br>-          (IsTypename || IsTemplateArgumentList(1))) {<br>+          (IsTypename || isTemplateArgumentList(1) == TPResult::True)) {<br>         // We have something like t::getAs<T>, where getAs is a<br>         // member of an unknown specialization. However, this will only<br>         // parse correctly as a template, so suggest the keyword 'template'<br>@@ -2138,9 +2146,15 @@ bool Parser::ParseUnqualifiedIdTemplateI<br>                                    TemplateKWLoc.isValid(), Id,<br>                                    ObjectType, EnteringContext, Template,<br>                                    MemberOfUnknownSpecialization);<br>+      // If lookup found nothing but we're assuming that this is a template<br>+      // name, double-check that makes sense syntactically before committing<br>+      // to it.<br>+      if (TNK == TNK_Undeclared_template &&<br>+          isTemplateArgumentList(0) == TPResult::False)<br>+        return false;<br><br>       if (TNK == TNK_Non_template && MemberOfUnknownSpecialization &&<br>-          ObjectType && IsTemplateArgumentList()) {<br>+          ObjectType && isTemplateArgumentList(0) == TPResult::True) {<br>         // We have something like t->getAs<T>(), where getAs is a<br>         // member of an unknown specialization. However, this will only<br>         // parse correctly as a template, so suggest the keyword 'template'<br>@@ -2244,11 +2258,9 @@ bool Parser::ParseUnqualifiedIdTemplateI<br>   ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs);<br><br>   // Constructor and destructor names.<br>-  TypeResult Type<br>-    = Actions.ActOnTemplateIdType(SS, TemplateKWLoc,<br>-                                  Template, Name, NameLoc,<br>-                                  LAngleLoc, TemplateArgsPtr, RAngleLoc,<br>-                                  /*IsCtorOrDtorName=*/true);<br>+  TypeResult Type = Actions.ActOnTemplateIdType(<br>+      getCurScope(), SS, TemplateKWLoc, Template, Name, NameLoc, LAngleLoc,<br>+      TemplateArgsPtr, RAngleLoc, /*IsCtorOrDtorName=*/true);<br>   if (Type.isInvalid())<br>     return true;<br><br><br>Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)<br>+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Wed May  8 20:31:27 2019<br>@@ -1031,6 +1031,8 @@ bool Parser::AnnotateTemplateIdToken(Tem<br>     // If we failed to parse the template ID but skipped ahead to a >, we're not<br>     // going to be able to form a token annotation.  Eat the '>' if present.<br>     TryConsumeToken(tok::greater);<br>+    // FIXME: Annotate the token stream so we don't produce the same errors<br>+    // again if we're doing this annotation as part of a tentative parse.<br>     return true;<br>   }<br><br>@@ -1039,13 +1041,15 @@ bool Parser::AnnotateTemplateIdToken(Tem<br>   // Build the annotation token.<br>   if (TNK == TNK_Type_template && AllowTypeAnnotation) {<br>     TypeResult Type = Actions.ActOnTemplateIdType(<br>-        SS, TemplateKWLoc, Template, TemplateName.Identifier,<br>+        getCurScope(), SS, TemplateKWLoc, Template, TemplateName.Identifier,<br>         TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc);<br>     if (Type.isInvalid()) {<br>       // If we failed to parse the template ID but skipped ahead to a >, we're<br>       // not going to be able to form a token annotation.  Eat the '>' if<br>       // present.<br>       TryConsumeToken(tok::greater);<br>+      // FIXME: Annotate the token stream so we don't produce the same errors<br>+      // again if we're doing this annotation as part of a tentative parse.<br>       return true;<br>     }<br><br>@@ -1108,14 +1112,16 @@ void Parser::AnnotateTemplateIdTokenAsTy<br><br>   TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);<br>   assert((TemplateId->Kind == TNK_Type_template ||<br>-          TemplateId->Kind == TNK_Dependent_template_name) &&<br>+          TemplateId->Kind == TNK_Dependent_template_name ||<br>+          TemplateId->Kind == TNK_Undeclared_template) &&<br>          "Only works for type and dependent templates");<br><br>   ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),<br>                                      TemplateId->NumArgs);<br><br>   TypeResult Type<br>-    = Actions.ActOnTemplateIdType(TemplateId->SS,<br>+    = Actions.ActOnTemplateIdType(getCurScope(),<br>+                                  TemplateId->SS,<br>                                   TemplateId->TemplateKWLoc,<br>                                   TemplateId->Template,<br>                                   TemplateId->Name,<br>@@ -1272,36 +1278,6 @@ ParsedTemplateArgument Parser::ParseTemp<br>                                 ExprArg.get(), Loc);<br> }<br><br>-/// Determine whether the current tokens can only be parsed as a<br>-/// template argument list (starting with the '<') and never as a '<'<br>-/// expression.<br>-bool Parser::IsTemplateArgumentList(unsigned Skip) {<br>-  struct AlwaysRevertAction : TentativeParsingAction {<br>-    AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { }<br>-    ~AlwaysRevertAction() { Revert(); }<br>-  } Tentative(*this);<br>-<br>-  while (Skip) {<br>-    ConsumeAnyToken();<br>-    --Skip;<br>-  }<br>-<br>-  // '<'<br>-  if (!TryConsumeToken(tok::less))<br>-    return false;<br>-<br>-  // An empty template argument list.<br>-  if (<a href="http://Tok.is" target="_blank">Tok.is</a>(tok::greater))<br>-    return true;<br>-<br>-  // See whether we have declaration specifiers, which indicate a type.<br>-  while (isCXXDeclarationSpecifier() == TPResult::True)<br>-    ConsumeAnyToken();<br>-<br>-  // If we have a '>' or a ',' then this is a template argument list.<br>-  return Tok.isOneOf(tok::greater, tok::comma);<br>-}<br>-<br> /// ParseTemplateArgumentList - Parse a C++ template-argument-list<br> /// (C++ [temp.names]). Returns true if there was an error.<br> ///<br><br>Modified: cfe/trunk/lib/Parse/ParseTentative.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)<br>+++ cfe/trunk/lib/Parse/ParseTentative.cpp Wed May  8 20:31:27 2019<br>@@ -1178,12 +1178,17 @@ public:<br> /// be either a decl-specifier or a function-style cast, and TPResult::Error<br> /// if a parsing error was found and reported.<br> ///<br>-/// If HasMissingTypename is provided, a name with a dependent scope specifier<br>-/// will be treated as ambiguous if the 'typename' keyword is missing. If this<br>-/// happens, *HasMissingTypename will be set to 'true'. This will also be used<br>-/// as an indicator that undeclared identifiers (which will trigger a later<br>-/// parse error) should be treated as types. Returns TPResult::Ambiguous in<br>-/// such cases.<br>+/// If InvalidAsDeclSpec is not null, some cases that would be ill-formed as<br>+/// declaration specifiers but possibly valid as some other kind of construct<br>+/// return TPResult::Ambiguous instead of TPResult::False. When this happens,<br>+/// the intent is to keep trying to disambiguate, on the basis that we might<br>+/// find a better reason to treat this construct as a declaration later on.<br>+/// When this happens and the name could possibly be valid in some other<br>+/// syntactic context, *InvalidAsDeclSpec is set to 'true'. The current cases<br>+/// that trigger this are:<br>+///<br>+///   * When parsing X::Y (with no 'typename') where X is dependent<br>+///   * When parsing X<Y> where X is undeclared<br> ///<br> ///         decl-specifier:<br> ///           storage-class-specifier<br>@@ -1281,7 +1286,7 @@ public:<br> ///<br> Parser::TPResult<br> Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,<br>-                                  bool *HasMissingTypename) {<br>+                                  bool *InvalidAsDeclSpec) {<br>   switch (Tok.getKind()) {<br>   case tok::identifier: {<br>     // Check for need to substitute AltiVec __vector keyword<br>@@ -1321,7 +1326,7 @@ Parser::isCXXDeclarationSpecifier(Parser<br>         // argument is an error, and was probably intended to be a type.<br>         return GreaterThanIsOperator ? TPResult::True : TPResult::False;<br>       case ANK_Unresolved:<br>-        return HasMissingTypename ? TPResult::Ambiguous : TPResult::False;<br>+        return InvalidAsDeclSpec ? TPResult::Ambiguous : TPResult::False;<br>       case ANK_Success:<br>         break;<br>       }<br>@@ -1342,7 +1347,7 @@ Parser::isCXXDeclarationSpecifier(Parser<br>     }<br><br>     // We annotated this token as something. Recurse to handle whatever we got.<br>-    return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);<br>+    return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec);<br>   }<br><br>   case tok::kw_typename:  // typename T::type<br>@@ -1350,7 +1355,7 @@ Parser::isCXXDeclarationSpecifier(Parser<br>     // recurse to handle whatever we get.<br>     if (TryAnnotateTypeOrScopeToken())<br>       return TPResult::Error;<br>-    return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);<br>+    return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec);<br><br>   case tok::coloncolon: {    // ::foo::bar<br>     const Token &Next = NextToken();<br>@@ -1365,7 +1370,7 @@ Parser::isCXXDeclarationSpecifier(Parser<br>     // recurse to handle whatever we get.<br>     if (TryAnnotateTypeOrScopeToken())<br>       return TPResult::Error;<br>-    return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);<br>+    return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec);<br><br>     // decl-specifier:<br>     //   storage-class-specifier<br>@@ -1471,6 +1476,16 @@ Parser::isCXXDeclarationSpecifier(Parser<br><br>   case tok::annot_template_id: {<br>     TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);<br>+    // If lookup for the template-name found nothing, don't assume we have a<br>+    // definitive disambiguation result yet.<br>+    if (TemplateId->Kind == TNK_Undeclared_template && InvalidAsDeclSpec) {<br>+      // 'template-id(' can be a valid expression but not a valid decl spec if<br>+      // the template-name is not declared, but we don't consider this to be a<br>+      // definitive disambiguation. In any other context, it's an error either<br>+      // way.<br>+      *InvalidAsDeclSpec = NextToken().is(tok::l_paren);<br>+      return TPResult::Ambiguous;<br>+    }<br>     if (TemplateId->Kind != TNK_Type_template)<br>       return TPResult::False;<br>     CXXScopeSpec SS;<br>@@ -1499,19 +1514,19 @@ Parser::isCXXDeclarationSpecifier(Parser<br>           TPResult TPR = TPResult::False;<br>           if (!isIdentifier)<br>             TPR = isCXXDeclarationSpecifier(BracedCastResult,<br>-                                            HasMissingTypename);<br>+                                            InvalidAsDeclSpec);<br><br>           if (isIdentifier ||<br>               TPR == TPResult::True || TPR == TPResult::Error)<br>             return TPResult::Error;<br><br>-          if (HasMissingTypename) {<br>+          if (InvalidAsDeclSpec) {<br>             // We can't tell whether this is a missing 'typename' or a valid<br>             // expression.<br>-            *HasMissingTypename = true;<br>+            *InvalidAsDeclSpec = true;<br>             return TPResult::Ambiguous;<br>           } else {<br>-            // In MS mode, if HasMissingTypename is not provided, and the tokens<br>+            // In MS mode, if InvalidAsDeclSpec is not provided, and the tokens<br>             // are or the form *) or &) *> or &> &&>, this can't be an expression.<br>             // The typename must be missing.<br>             if (getLangOpts().MSVCCompat) {<br>@@ -1547,8 +1562,7 @@ Parser::isCXXDeclarationSpecifier(Parser<br>                        ? TPResult::True<br>                        : TPResult::False;<br>           case ANK_Unresolved:<br>-            return HasMissingTypename ? TPResult::Ambiguous<br>-                                      : TPResult::False;<br>+            return InvalidAsDeclSpec ? TPResult::Ambiguous : TPResult::False;<br>           case ANK_Success:<br>             break;<br>           }<br>@@ -1556,8 +1570,7 @@ Parser::isCXXDeclarationSpecifier(Parser<br>           // Annotated it, check again.<br>           assert(Tok.isNot(tok::annot_cxxscope) ||<br>                  NextToken().isNot(tok::identifier));<br>-          return isCXXDeclarationSpecifier(BracedCastResult,<br>-                                           HasMissingTypename);<br>+          return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec);<br>         }<br>       }<br>       return TPResult::False;<br>@@ -2029,3 +2042,56 @@ Parser::TPResult Parser::TryParseBracket<br><br>   return TPResult::Ambiguous;<br> }<br>+<br>+/// Determine whether we might be looking at the '<' template-argument-list '>'<br>+/// of a template-id or simple-template-id, rather than a less-than comparison.<br>+/// This will often fail and produce an ambiguity, but should never be wrong<br>+/// if it returns True or False.<br>+Parser::TPResult Parser::isTemplateArgumentList(unsigned TokensToSkip) {<br>+  if (!TokensToSkip) {<br>+    if (Tok.isNot(tok::less))<br>+      return TPResult::False;<br>+    if (NextToken().is(tok::greater))<br>+      return TPResult::True;<br>+  }<br>+<br>+  RevertingTentativeParsingAction PA(*this);<br>+<br>+  while (TokensToSkip) {<br>+    ConsumeAnyToken();<br>+    --TokensToSkip;<br>+  }<br>+<br>+  if (!TryConsumeToken(tok::less))<br>+    return TPResult::False;<br>+<br>+  bool InvalidAsTemplateArgumentList = false;<br>+  while (true) {<br>+    // We can't do much to tell an expression apart from a template-argument,<br>+    // but one good distinguishing factor is that a "decl-specifier" not<br>+    // followed by '(' or '{' can't appear in an expression.<br>+    if (isCXXDeclarationSpecifier(<br>+            TPResult::False, &InvalidAsTemplateArgumentList) == TPResult::True)<br>+      return TPResult::True;<br>+<br>+    // That didn't help, try the next template-argument.<br>+    SkipUntil({tok::comma, tok::greater, tok::greatergreater,<br>+               tok::greatergreatergreater},<br>+              StopAtSemi | StopBeforeMatch);<br>+    switch (Tok.getKind()) {<br>+    case tok::comma:<br>+      ConsumeToken();<br>+      break;<br>+<br>+    case tok::greater:<br>+    case tok::greatergreater:<br>+    case tok::greatergreatergreater:<br>+      if (InvalidAsTemplateArgumentList)<br>+        return TPResult::False;<br>+      return TPResult::Ambiguous;<br>+<br>+    default:<br>+      return TPResult::False;<br>+    }<br>+  }<br>+}<br><br>Modified: cfe/trunk/lib/Parse/Parser.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Parse/Parser.cpp (original)<br>+++ cfe/trunk/lib/Parse/Parser.cpp Wed May  8 20:31:27 2019<br>@@ -315,6 +315,14 @@ bool Parser::SkipUntil(ArrayRef<tok::Tok<br>       else<br>         SkipUntil(tok::r_brace);<br>       break;<br>+    case tok::question:<br>+      // Recursively skip ? ... : pairs; these function as brackets. But<br>+      // still stop at a semicolon if requested.<br>+      ConsumeToken();<br>+      SkipUntil(tok::colon,<br>+                SkipUntilFlags(unsigned(Flags) &<br>+                               unsigned(StopAtCodeCompletion | StopAtSemi)));<br>+      break;<br><br>     // Okay, we found a ']' or '}' or ')', which we think should be balanced.<br>     // Since the user wasn't looking for this token (if they were, it would<br>@@ -1600,6 +1608,20 @@ Parser::TryAnnotateName(bool IsAddressOf<br>       Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next,<br>                            IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);<br><br>+  // If name lookup found nothing and we guessed that this was a template name,<br>+  // double-check before committing to that interpretation. C++20 requires that<br>+  // we interpret this as a template-id if it can be, but if it can't be, then<br>+  // this is an error recovery case.<br>+  if (Classification.getKind() == Sema::NC_UndeclaredTemplate &&<br>+      isTemplateArgumentList(1) == TPResult::False) {<br>+    // It's not a template-id; re-classify without the '<' as a hint.<br>+    Token FakeNext = Next;<br>+    FakeNext.setKind(tok::unknown);<br>+    Classification =<br>+        Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, FakeNext,<br>+                             IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);<br>+  }<br>+<br>   switch (Classification.getKind()) {<br>   case Sema::NC_Error:<br>     return ANK_Error;<br>@@ -1668,7 +1690,8 @@ Parser::TryAnnotateName(bool IsAddressOf<br>     }<br>     LLVM_FALLTHROUGH;<br>   case Sema::NC_VarTemplate:<br>-  case Sema::NC_FunctionTemplate: {<br>+  case Sema::NC_FunctionTemplate:<br>+  case Sema::NC_UndeclaredTemplate: {<br>     // We have a type, variable or function template followed by '<'.<br>     ConsumeToken();<br>     UnqualifiedId Id;<br>@@ -1791,7 +1814,8 @@ bool Parser::TryAnnotateTypeOrScopeToken<br>     } else if (<a href="http://Tok.is" target="_blank">Tok.is</a>(tok::annot_template_id)) {<br>       TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);<br>       if (TemplateId->Kind != TNK_Type_template &&<br>-          TemplateId->Kind != TNK_Dependent_template_name) {<br>+          TemplateId->Kind != TNK_Dependent_template_name &&<br>+          TemplateId->Kind != TNK_Undeclared_template) {<br>         Diag(Tok, diag::err_typename_refers_to_non_type_template)<br>           << Tok.getAnnotationRange();<br>         return true;<br>@@ -1890,6 +1914,8 @@ bool Parser::TryAnnotateTypeOrScopeToken<br>     }<br><br>     // If this is a template-id, annotate with a template-id or type token.<br>+    // FIXME: This appears to be dead code. We already have formed template-id<br>+    // tokens when parsing the scope specifier; this can never form a new one.<br>     if (NextToken().is(tok::less)) {<br>       TemplateTy Template;<br>       UnqualifiedId TemplateName;<br>@@ -1900,14 +1926,19 @@ bool Parser::TryAnnotateTypeOrScopeToken<br>               /*hasTemplateKeyword=*/false, TemplateName,<br>               /*ObjectType=*/nullptr, /*EnteringContext*/false, Template,<br>               MemberOfUnknownSpecialization)) {<br>-        // Consume the identifier.<br>-        ConsumeToken();<br>-        if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),<br>-                                    TemplateName)) {<br>-          // If an unrecoverable error occurred, we need to return true here,<br>-          // because the token stream is in a damaged state.  We may not return<br>-          // a valid identifier.<br>-          return true;<br>+        // Only annotate an undeclared template name as a template-id if the<br>+        // following tokens have the form of a template argument list.<br>+        if (TNK != TNK_Undeclared_template ||<br>+            isTemplateArgumentList(1) != TPResult::False) {<br>+          // Consume the identifier.<br>+          ConsumeToken();<br>+          if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),<br>+                                      TemplateName)) {<br>+            // If an unrecoverable error occurred, we need to return true here,<br>+            // because the token stream is in a damaged state.  We may not<br>+            // return a valid identifier.<br>+            return true;<br>+          }<br>         }<br>       }<br>     }<br><br>Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed May  8 20:31:27 2019<br>@@ -888,7 +888,7 @@ bool Sema::IsInvalidUnlessNestedName(Sco<br> bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,<br>                                        CXXScopeSpec &SS,<br>                                        SourceLocation TemplateKWLoc,<br>-                                       TemplateTy Template,<br>+                                       TemplateTy OpaqueTemplate,<br>                                        SourceLocation TemplateNameLoc,<br>                                        SourceLocation LAngleLoc,<br>                                        ASTTemplateArgsPtr TemplateArgsIn,<br>@@ -898,11 +898,13 @@ bool Sema::ActOnCXXNestedNameSpecifier(S<br>   if (SS.isInvalid())<br>     return true;<br><br>+  TemplateName Template = OpaqueTemplate.get();<br>+<br>   // Translate the parser's template argument list in our AST format.<br>   TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);<br>   translateTemplateArguments(TemplateArgsIn, TemplateArgs);<br><br>-  DependentTemplateName *DTN = Template.get().getAsDependentTemplateName();<br>+  DependentTemplateName *DTN = Template.getAsDependentTemplateName();<br>   if (DTN && DTN->isIdentifier()) {<br>     // Handle a dependent template specialization for which we cannot resolve<br>     // the template name.<br>@@ -930,23 +932,28 @@ bool Sema::ActOnCXXNestedNameSpecifier(S<br>     return false;<br>   }<br><br>-  TemplateDecl *TD = Template.get().getAsTemplateDecl();<br>-  if (Template.get().getAsOverloadedTemplate() || DTN ||<br>+  // If we assumed an undeclared identifier was a template name, try to<br>+  // typo-correct it now.<br>+  if (Template.getAsAssumedTemplateName() &&<br>+      resolveAssumedTemplateNameAsType(S, Template, TemplateNameLoc))<br>+    return true;<br>+<br>+  TemplateDecl *TD = Template.getAsTemplateDecl();<br>+  if (Template.getAsOverloadedTemplate() || DTN ||<br>       isa<FunctionTemplateDecl>(TD) || isa<VarTemplateDecl>(TD)) {<br>     SourceRange R(TemplateNameLoc, RAngleLoc);<br>     if (SS.getRange().isValid())<br>       R.setBegin(SS.getRange().getBegin());<br><br>     Diag(CCLoc, diag::err_non_type_template_in_nested_name_specifier)<br>-      << (TD && isa<VarTemplateDecl>(TD)) << Template.get() << R;<br>-    NoteAllFoundTemplates(Template.get());<br>+      << (TD && isa<VarTemplateDecl>(TD)) << Template << R;<br>+    NoteAllFoundTemplates(Template);<br>     return true;<br>   }<br><br>   // We were able to resolve the template name to an actual template.<br>   // Build an appropriate nested-name-specifier.<br>-  QualType T =<br>-      CheckTemplateIdType(Template.get(), TemplateNameLoc, TemplateArgs);<br>+  QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);<br>   if (T.isNull())<br>     return true;<br><br>@@ -954,7 +961,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(S<br>   // nested name specifiers.<br>   if (!T->isDependentType() && !T->getAs<TagType>()) {<br>     Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T;<br>-    NoteAllFoundTemplates(Template.get());<br>+    NoteAllFoundTemplates(Template);<br>     return true;<br>   }<br><br><br>Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed May  8 20:31:27 2019<br>@@ -917,6 +917,16 @@ Corrected:<br>       }<br>     }<br><br>+    if (getLangOpts().CPlusPlus2a && !SS.isSet() && <a href="http://NextToken.is" target="_blank">NextToken.is</a>(tok::less)) {<br>+      // In C++20 onwards, this could be an ADL-only call to a function<br>+      // template, and we're required to assume that this is a template name.<br>+      //<br>+      // FIXME: Find a way to still do typo correction in this case.<br>+      TemplateName Template =<br>+          Context.getAssumedTemplateName(NameInfo.getName());<br>+      return NameClassification::UndeclaredTemplate(Template);<br>+    }<br>+<br>     // In C, we first see whether there is a tag type by the same name, in<br>     // which case it's likely that the user just forgot to write "enum",<br>     // "struct", or "union".<br>@@ -1045,52 +1055,62 @@ Corrected:<br><br>   if (getLangOpts().CPlusPlus && <a href="http://NextToken.is" target="_blank">NextToken.is</a>(tok::less) &&<br>       (IsFilteredTemplateName ||<br>-       hasAnyAcceptableTemplateNames(Result, /*AllowFunctionTemplates=*/true,<br>-                                     /*AllowDependent=*/false))) {<br>+       hasAnyAcceptableTemplateNames(<br>+           Result, /*AllowFunctionTemplates=*/true,<br>+           /*AllowDependent=*/false,<br>+           /*AllowNonTemplateFunctions*/ !SS.isSet() &&<br>+               getLangOpts().CPlusPlus2a))) {<br>     // C++ [temp.names]p3:<br>     //   After name lookup (3.4) finds that a name is a template-name or that<br>     //   an operator-function-id or a literal- operator-id refers to a set of<br>     //   overloaded functions any member of which is a function template if<br>     //   this is followed by a <, the < is always taken as the delimiter of a<br>     //   template-argument-list and never as the less-than operator.<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<br>+    //   or more functions or finds nothing.<br>     if (!IsFilteredTemplateName)<br>       FilterAcceptableTemplateNames(Result);<br><br>-    if (!Result.empty()) {<br>-      bool IsFunctionTemplate;<br>-      bool IsVarTemplate;<br>-      TemplateName Template;<br>-      if (Result.end() - Result.begin() > 1) {<br>-        IsFunctionTemplate = true;<br>-        Template = Context.getOverloadedTemplateName(Result.begin(),<br>-                                                     Result.end());<br>-      } else {<br>-        auto *TD = cast<TemplateDecl>(getAsTemplateNameDecl(<br>-            *Result.begin(), /*AllowFunctionTemplates=*/true,<br>-            /*AllowDependent=*/false));<br>-        IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);<br>-        IsVarTemplate = isa<VarTemplateDecl>(TD);<br>-<br>-        if (SS.isSet() && !SS.isInvalid())<br>-          Template =<br>-              Context.getQualifiedTemplateName(SS.getScopeRep(),<br>-                                               /*TemplateKeyword=*/false, TD);<br>-        else<br>-          Template = TemplateName(TD);<br>-      }<br>-<br>-      if (IsFunctionTemplate) {<br>-        // Function templates always go through overload resolution, at which<br>-        // point we'll perform the various checks (e.g., accessibility) we need<br>-        // to based on which function we selected.<br>-        Result.suppressDiagnostics();<br>+    bool IsFunctionTemplate;<br>+    bool IsVarTemplate;<br>+    TemplateName Template;<br>+    if (Result.end() - Result.begin() > 1) {<br>+      IsFunctionTemplate = true;<br>+      Template = Context.getOverloadedTemplateName(Result.begin(),<br>+                                                   Result.end());<br>+    } else if (!Result.empty()) {<br>+      auto *TD = cast<TemplateDecl>(getAsTemplateNameDecl(<br>+          *Result.begin(), /*AllowFunctionTemplates=*/true,<br>+          /*AllowDependent=*/false));<br>+      IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);<br>+      IsVarTemplate = isa<VarTemplateDecl>(TD);<br>+<br>+      if (SS.isSet() && !SS.isInvalid())<br>+        Template =<br>+            Context.getQualifiedTemplateName(SS.getScopeRep(),<br>+                                             /*TemplateKeyword=*/false, TD);<br>+      else<br>+        Template = TemplateName(TD);<br>+    } else {<br>+      // All results were non-template functions. This is a function template<br>+      // name.<br>+      IsFunctionTemplate = true;<br>+      Template = Context.getAssumedTemplateName(NameInfo.getName());<br>+    }<br><br>-        return NameClassification::FunctionTemplate(Template);<br>-      }<br>+    if (IsFunctionTemplate) {<br>+      // Function templates always go through overload resolution, at which<br>+      // point we'll perform the various checks (e.g., accessibility) we need<br>+      // to based on which function we selected.<br>+      Result.suppressDiagnostics();<br><br>-      return IsVarTemplate ? NameClassification::VarTemplate(Template)<br>-                           : NameClassification::TypeTemplate(Template);<br>+      return NameClassification::FunctionTemplate(Template);<br>     }<br>+<br>+    return IsVarTemplate ? NameClassification::VarTemplate(Template)<br>+                         : NameClassification::TypeTemplate(Template);<br>   }<br><br>   NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl();<br><br>Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed May  8 20:31:27 2019<br>@@ -3881,6 +3881,8 @@ Sema::BuildMemInitializer(Decl *Construc<br><br>   if (TemplateTypeTy) {<br>     BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo);<br>+    if (BaseType.isNull())<br>+      return true;<br>   } else if (DS.getTypeSpecType() == TST_decltype) {<br>     BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());<br>   } else if (DS.getTypeSpecType() == TST_decltype_auto) {<br><br>Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed May  8 20:31:27 2019<br>@@ -2065,11 +2065,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S,<br>       // is in the wrong place to recover. Suggest the typo<br>       // correction, but don't make it a fix-it since we're not going<br>       // to recover well anyway.<br>-      AcceptableWithoutRecovery =<br>-          isa<TypeDecl>(UnderlyingND) || isa<ObjCInterfaceDecl>(UnderlyingND);<br>+      AcceptableWithoutRecovery = isa<TypeDecl>(UnderlyingND) ||<br>+                                  getAsTypeTemplateDecl(UnderlyingND) ||<br>+                                  isa<ObjCInterfaceDecl>(UnderlyingND);<br>     } else {<br>-      // FIXME: We found a keyword or a type. Suggest it, but don't provide a<br>-      // fix-it because we aren't able to recover.<br>+      // FIXME: We found a keyword. Suggest it, but don't provide a fix-it<br>+      // because we aren't able to recover.<br>       AcceptableWithoutRecovery = true;<br>     }<br><br>@@ -2221,8 +2222,10 @@ Sema::ActOnIdExpression(Scope *S, CXXSco<br>     // this becomes a performance hit, we can work harder to preserve those<br>     // results until we get here but it's likely not worth it.<br>     bool MemberOfUnknownSpecialization;<br>+    AssumedTemplateKind AssumedTemplate;<br>     if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,<br>-                           MemberOfUnknownSpecialization, TemplateKWLoc))<br>+                           MemberOfUnknownSpecialization, TemplateKWLoc,<br>+                           &AssumedTemplate))<br>       return ExprError();<br><br>     if (MemberOfUnknownSpecialization ||<br>@@ -5518,7 +5521,24 @@ tryImplicitlyCaptureThisIfImplicitMember<br> ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,<br>                                MultiExprArg ArgExprs, SourceLocation RParenLoc,<br>                                Expr *ExecConfig) {<br>-  return BuildCallExpr(Scope, Fn, LParenLoc, ArgExprs, RParenLoc, ExecConfig);<br>+  ExprResult Call =<br>+      BuildCallExpr(Scope, Fn, LParenLoc, ArgExprs, RParenLoc, ExecConfig);<br>+  if (Call.isInvalid())<br>+    return Call;<br>+<br>+  // Diagnose uses of the C++20 "ADL-only template-id call" feature in earlier<br>+  // language modes.<br>+  if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(Fn)) {<br>+    if (ULE->hasExplicitTemplateArgs() &&<br>+        ULE->decls_begin() == ULE->decls_end()) {<br>+      Diag(Fn->getExprLoc(), getLangOpts().CPlusPlus2a<br>+                                 ? diag::warn_cxx17_compat_adl_only_template_id<br>+                                 : diag::ext_adl_only_template_id)<br>+          << ULE->getName();<br>+    }<br>+  }<br>+<br>+  return Call;<br> }<br><br> /// BuildCallExpr - Handle a call to Fn with the specified array of arguments.<br><br>Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed May  8 20:31:27 2019<br>@@ -7074,7 +7074,8 @@ ExprResult Sema::ActOnPseudoDestructorEx<br>     TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;<br>     ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),<br>                                        TemplateId->NumArgs);<br>-    TypeResult T = ActOnTemplateIdType(TemplateId->SS,<br>+    TypeResult T = ActOnTemplateIdType(S,<br>+                                       TemplateId->SS,<br>                                        TemplateId->TemplateKWLoc,<br>                                        TemplateId->Template,<br>                                        TemplateId->Name,<br>@@ -7126,7 +7127,8 @@ ExprResult Sema::ActOnPseudoDestructorEx<br>       TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;<br>       ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),<br>                                          TemplateId->NumArgs);<br>-      TypeResult T = ActOnTemplateIdType(TemplateId->SS,<br>+      TypeResult T = ActOnTemplateIdType(S,<br>+                                         TemplateId->SS,<br>                                          TemplateId->TemplateKWLoc,<br>                                          TemplateId->Template,<br>                                          TemplateId->Name,<br><br>Modified: cfe/trunk/lib/Sema/SemaOverload.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed May  8 20:31:27 2019<br>@@ -12017,7 +12017,8 @@ bool Sema::buildOverloadedCallSet(Scope<br>     // We don't perform ADL for implicit declarations of builtins.<br>     // Verify that this was correctly set up.<br>     FunctionDecl *F;<br>-    if (ULE->decls_begin() + 1 == ULE->decls_end() &&<br>+    if (ULE->decls_begin() != ULE->decls_end() &&<br>+        ULE->decls_begin() + 1 == ULE->decls_end() &&<br>         (F = dyn_cast<FunctionDecl>(*ULE->decls_begin())) &&<br>         F->getBuiltinID() && F->isImplicit())<br>       llvm_unreachable("performing ADL for builtin");<br>@@ -12201,10 +12202,9 @@ ExprResult Sema::BuildOverloadedCallExpr<br>   OverloadingResult OverloadResult =<br>       CandidateSet.BestViableFunction(*this, Fn->getBeginLoc(), Best);<br><br>-  return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args,<br>-                                  RParenLoc, ExecConfig, &CandidateSet,<br>-                                  &Best, OverloadResult,<br>-                                  AllowTypoCorrection);<br>+  return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args, RParenLoc,<br>+                                  ExecConfig, &CandidateSet, &Best,<br>+                                  OverloadResult, AllowTypoCorrection);<br> }<br><br> static bool IsOverloaded(const UnresolvedSetImpl &Functions) {<br><br>Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)<br>+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed May  8 20:31:27 2019<br>@@ -130,10 +130,15 @@ void Sema::FilterAcceptableTemplateNames<br><br> bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R,<br>                                          bool AllowFunctionTemplates,<br>-                                         bool AllowDependent) {<br>-  for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I)<br>+                                         bool AllowDependent,<br>+                                         bool AllowNonTemplateFunctions) {<br>+  for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) {<br>     if (getAsTemplateNameDecl(*I, AllowFunctionTemplates, AllowDependent))<br>       return true;<br>+    if (AllowNonTemplateFunctions &&<br>+        isa<FunctionDecl>((*I)->getUnderlyingDecl()))<br>+      return true;<br>+  }<br><br>   return false;<br> }<br>@@ -171,11 +176,25 @@ TemplateNameKind Sema::isTemplateName(Sc<br><br>   QualType ObjectType = ObjectTypePtr.get();<br><br>+  AssumedTemplateKind AssumedTemplate;<br>   LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName);<br>   if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,<br>-                         MemberOfUnknownSpecialization))<br>+                         MemberOfUnknownSpecialization, SourceLocation(),<br>+                         &AssumedTemplate))<br>+    return TNK_Non_template;<br>+<br>+  if (AssumedTemplate != AssumedTemplateKind::None) {<br>+    TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName));<br>+    // Let the parser know whether we found nothing or found functions; if we<br>+    // found nothing, we want to more carefully check whether this is actually<br>+    // a function template name versus some other kind of undeclared identifier.<br>+    return AssumedTemplate == AssumedTemplateKind::FoundNothing<br>+               ? TNK_Undeclared_template<br>+               : TNK_Function_template;<br>+  }<br>+<br>+  if (R.empty())<br>     return TNK_Non_template;<br>-  if (R.empty()) return TNK_Non_template;<br><br>   NamedDecl *D = nullptr;<br>   if (R.isAmbiguous()) {<br>@@ -325,7 +344,11 @@ bool Sema::LookupTemplateName(LookupResu<br>                               QualType ObjectType,<br>                               bool EnteringContext,<br>                               bool &MemberOfUnknownSpecialization,<br>-                              SourceLocation TemplateKWLoc) {<br>+                              SourceLocation TemplateKWLoc,<br>+                              AssumedTemplateKind *ATK) {<br>+  if (ATK)<br>+    *ATK = AssumedTemplateKind::None;<br>+<br>   Found.setTemplateNameLookup(true);<br><br>   // Determine where to perform name lookup<br>@@ -405,6 +428,32 @@ bool Sema::LookupTemplateName(LookupResu<br>   if (Found.isAmbiguous())<br>     return false;<br><br>+  if (ATK && !SS.isSet() && 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>+    //   functions or finds nothing.<br>+    //<br>+    // To keep our behavior consistent, we apply the "finds nothing" part in<br>+    // all language modes, and diagnose the empty lookup in ActOnCallExpr if we<br>+    // successfully form a call to an undeclared template-id.<br>+    bool AllFunctions =<br>+        getLangOpts().CPlusPlus2a &&<br>+        std::all_of(Found.begin(), Found.end(), [](NamedDecl *ND) {<br>+          return isa<FunctionDecl>(ND->getUnderlyingDecl());<br>+        });<br>+    if (AllFunctions || (Found.empty() && !IsDependent)) {<br>+      // If lookup found any functions, or if this is a name that can only be<br>+      // used for a function, then strongly assume this is a function<br>+      // template-id.<br>+      *ATK = (Found.empty() && Found.getLookupName().isIdentifier())<br>+                 ? AssumedTemplateKind::FoundNothing<br>+                 : AssumedTemplateKind::FoundFunctions;<br>+      Found.clear();<br>+      return false;<br>+    }<br>+  }<br>+<br>   if (Found.empty() && !IsDependent) {<br>     // If we did not find any names, attempt to correct any typos.<br>     DeclarationName Name = Found.getLookupName();<br>@@ -418,13 +467,13 @@ bool Sema::LookupTemplateName(LookupResu<br>     if (TypoCorrection Corrected =<br>             CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S,<br>                         &SS, FilterCCC, CTK_ErrorRecovery, LookupCtx)) {<br>-      Found.setLookupName(Corrected.getCorrection());<br>       if (auto *ND = Corrected.getFoundDecl())<br>         Found.addDecl(ND);<br>       FilterAcceptableTemplateNames(Found);<br>       if (Found.isAmbiguous()) {<br>         Found.clear();<br>       } else if (!Found.empty()) {<br>+        Found.setLookupName(Corrected.getCorrection());<br>         if (LookupCtx) {<br>           std::string CorrectedStr(Corrected.getAsString(getLangOpts()));<br>           bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&<br>@@ -436,8 +485,6 @@ bool Sema::LookupTemplateName(LookupResu<br>           diagnoseTypo(Corrected, PDiag(diag::err_no_template_suggest) << Name);<br>         }<br>       }<br>-    } else {<br>-      Found.setLookupName(Name);<br>     }<br>   }<br><br>@@ -3348,14 +3395,65 @@ QualType Sema::CheckTemplateIdType(Templ<br>   return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);<br> }<br><br>-TypeResult<br>-Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,<br>-                          TemplateTy TemplateD, IdentifierInfo *TemplateII,<br>-                          SourceLocation TemplateIILoc,<br>-                          SourceLocation LAngleLoc,<br>-                          ASTTemplateArgsPtr TemplateArgsIn,<br>-                          SourceLocation RAngleLoc,<br>-                          bool IsCtorOrDtorName, bool IsClassName) {<br>+void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,<br>+                                           TemplateNameKind &TNK,<br>+                                           SourceLocation NameLoc,<br>+                                           IdentifierInfo *&II) {<br>+  assert(TNK == TNK_Undeclared_template && "not an undeclared template name");<br>+<br>+  TemplateName Name = ParsedName.get();<br>+  auto *ATN = Name.getAsAssumedTemplateName();<br>+  assert(ATN && "not an assumed template name");<br>+  II = ATN->getDeclName().getAsIdentifierInfo();<br>+<br>+  if (!resolveAssumedTemplateNameAsType(S, Name, NameLoc, /*Diagnose*/false)) {<br>+    // Resolved to a type template name.<br>+    ParsedName = TemplateTy::make(Name);<br>+    TNK = TNK_Type_template;<br>+  }<br>+}<br>+<br>+bool Sema::resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name,<br>+                                            SourceLocation NameLoc,<br>+                                            bool Diagnose) {<br>+  // We assumed this undeclared identifier to be an (ADL-only) function<br>+  // template name, but it was used in a context where a type was required.<br>+  // Try to typo-correct it now.<br>+  AssumedTemplateStorage *ATN = Name.getAsAssumedTemplateName();<br>+  assert(ATN && "not an assumed template name");<br>+<br>+  LookupResult R(*this, ATN->getDeclName(), NameLoc, LookupOrdinaryName);<br>+  struct CandidateCallback : CorrectionCandidateCallback {<br>+    bool ValidateCandidate(const TypoCorrection &TC) override {<br>+      return TC.getCorrectionDecl() &&<br>+             getAsTypeTemplateDecl(TC.getCorrectionDecl());<br>+    }<br>+    std::unique_ptr<CorrectionCandidateCallback> clone() override {<br>+      return llvm::make_unique<CandidateCallback>(*this);<br>+    }<br>+  } FilterCCC;<br>+<br>+  TypoCorrection Corrected =<br>+      CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, nullptr,<br>+                  FilterCCC, CTK_ErrorRecovery);<br>+  if (Corrected && Corrected.getFoundDecl()) {<br>+    diagnoseTypo(Corrected, PDiag(diag::err_no_template_suggest)<br>+                                << ATN->getDeclName());<br>+    Name = TemplateName(Corrected.getCorrectionDeclAs<TemplateDecl>());<br>+    return false;<br>+  }<br>+<br>+  if (Diagnose)<br>+    Diag(R.getNameLoc(), diag::err_no_template) << R.getLookupName();<br>+  return true;<br>+}<br>+<br>+TypeResult Sema::ActOnTemplateIdType(<br>+    Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,<br>+    TemplateTy TemplateD, IdentifierInfo *TemplateII,<br>+    SourceLocation TemplateIILoc, SourceLocation LAngleLoc,<br>+    ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc,<br>+    bool IsCtorOrDtorName, bool IsClassName) {<br>   if (SS.isInvalid())<br>     return true;<br><br>@@ -3396,6 +3494,9 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &<br>   }<br><br>   TemplateName Template = TemplateD.get();<br>+  if (Template.getAsAssumedTemplateName() &&<br>+      resolveAssumedTemplateNameAsType(S, Template, TemplateIILoc))<br>+    return true;<br><br>   // Translate the parser's template argument list in our AST format.<br>   TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);<br>@@ -4141,7 +4242,6 @@ ExprResult Sema::BuildTemplateIdExpr(con<br>   //       vs template<class T, class U> void f(U);<br><br>   // These should be filtered out by our callers.<br>-  assert(!R.empty() && "empty lookup results when building templateid");<br>   assert(!R.isAmbiguous() && "ambiguous lookup when building templateid");<br><br>   // Non-function templates require a template argument list.<br><br>Modified: cfe/trunk/lib/Serialization/ASTReader.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)<br>+++ cfe/trunk/lib/Serialization/ASTReader.cpp Wed May  8 20:31:27 2019<br>@@ -8745,6 +8745,11 @@ ASTReader::ReadTemplateName(ModuleFile &<br>     return Context.getOverloadedTemplateName(Decls.begin(), Decls.end());<br>   }<br><br>+  case TemplateName::AssumedTemplate: {<br>+    DeclarationName Name = ReadDeclarationName(F, Record, Idx);<br>+    return Context.getAssumedTemplateName(Name);<br>+  }<br>+<br>   case TemplateName::QualifiedTemplate: {<br>     NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx);<br>     bool hasTemplKeyword = Record[Idx++];<br><br>Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)<br>+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed May  8 20:31:27 2019<br>@@ -5877,6 +5877,12 @@ void ASTRecordWriter::AddTemplateName(Te<br>     break;<br>   }<br><br>+  case TemplateName::AssumedTemplate: {<br>+    AssumedTemplateStorage *ADLT = Name.getAsAssumedTemplateName();<br>+    AddDeclarationName(ADLT->getDeclName());<br>+    break;<br>+  }<br>+<br>   case TemplateName::QualifiedTemplate: {<br>     QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName();<br>     AddNestedNameSpecifier(QualT->getQualifier());<br><br>Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp (original)<br>+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp Wed May  8 20:31:27 2019<br>@@ -1,25 +1,67 @@<br> // RUN: %clang_cc1 -fsyntax-only -verify %s<br>-// expected-no-diagnostics<br>+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s<br>+// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s<br><br>-typedef int f; <br>+typedef int fn;<br><br> namespace N0 {<br>-  struct A { <br>-    friend void f(); <br>+  struct A {<br>+    friend void fn();<br>     void g() {<br>-      int i = f(1);<br>+      int i = fn(1);<br>     }<br>   };<br> }<br><br> namespace N1 {<br>-  struct A { <br>-    friend void f(A &);<br>+  struct A {<br>+    friend void fn(A &);<br>     operator int();<br>     void g(A a) {<br>-      // ADL should not apply to the lookup of 'f', it refers to the typedef<br>+      // ADL should not apply to the lookup of 'fn', it refers to the typedef<br>       // above.<br>-      int i = f(a);<br>+      int i = fn(a);<br>     }<br>   };<br> }<br>+<br>+namespace std_example {<br>+  int h; // expected-note {{non-template declaration}}<br>+  void g();<br>+#if __cplusplus <= 201703L<br>+  // expected-note@-2 {{non-template declaration}}<br>+#endif<br>+  namespace N {<br>+    struct A {};<br>+    template<class T> int f(T);<br>+    template<class T> int g(T);<br>+#if __cplusplus <= 201703L<br>+    // expected-note@-2 {{here}}<br>+#endif<br>+    template<class T> int h(T); // expected-note {{here}}<br>+  }<br>+<br>+  int x = f<N::A>(N::A());<br>+#if __cplusplus <= 201703L<br>+  // expected-warning@-2 {{C++2a extension}}<br>+#endif<br>+  int y = g<N::A>(N::A());<br>+#if __cplusplus <= 201703L<br>+  // expected-error@-2 {{'g' does not name a template but is followed by template arguments; did you mean 'N::g'?}}<br>+#endif<br>+  int z = h<N::A>(N::A()); // expected-error {{'h' does not name a template but is followed by template arguments; did you mean 'N::h'?}}<br>+}<br>+<br>+namespace AnnexD_example {<br>+  struct A {};<br>+  void operator<(void (*fp)(), A);<br>+  void f() {}<br>+  int main() {<br>+    A a;<br>+    f < a;<br>+#if __cplusplus > 201703L<br>+    // expected-error@-2 {{expected '>'}}<br>+#endif<br>+    (f) < a;<br>+  }<br>+}<br><br>Modified: cfe/trunk/test/CXX/drs/dr2xx.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr2xx.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr2xx.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/CXX/drs/dr2xx.cpp (original)<br>+++ cfe/trunk/test/CXX/drs/dr2xx.cpp Wed May  8 20:31:27 2019<br>@@ -2,6 +2,7 @@<br> // RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br> // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br> // RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br>+// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors<br><br> // PR13819 -- __SIZE_TYPE__ is incompatible.<br> typedef __SIZE_TYPE__ size_t; // expected-error 0-1 {{extension}}<br>@@ -434,7 +435,7 @@ namespace dr239 { // dr239: yes<br> namespace dr241 { // dr241: yes<br>   namespace A {<br>     struct B {};<br>-    template <int X> void f(); // expected-note 2{{candidate}}<br>+    template <int X> void f(); // expected-note 3{{candidate}}<br>     template <int X> void g(B);<br>   }<br>   namespace C {<br>@@ -442,8 +443,8 @@ namespace dr241 { // dr241: yes<br>     template <class T> void g(T t); // expected-note {{candidate}}<br>   }<br>   void h(A::B b) {<br>-    f<3>(b); // expected-error {{undeclared identifier}}<br>-    g<3>(b); // expected-error {{undeclared identifier}}<br>+    f<3>(b); // expected-error 0-1{{C++2a extension}} expected-error {{no matching}}<br>+    g<3>(b); // expected-error 0-1{{C++2a extension}}<br>     A::f<3>(b); // expected-error {{no matching}}<br>     A::g<3>(b);<br>     C::f<3>(b); // expected-error {{no matching}}<br><br>Modified: cfe/trunk/test/CXX/drs/dr6xx.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr6xx.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr6xx.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/CXX/drs/dr6xx.cpp (original)<br>+++ cfe/trunk/test/CXX/drs/dr6xx.cpp Wed May  8 20:31:27 2019<br>@@ -1048,10 +1048,13 @@ namespace dr686 { // dr686: yes<br>   template<struct R {} *> struct Y; // expected-error {{cannot be defined in a type specifier}}<br> }<br><br>-namespace dr687 { // dr687 still open<br>+namespace dr687 { // dr687 (9 c++20, but the issue is still considered open)<br>   template<typename T> void f(T a) {<br>-    // FIXME: This is valid in C++20.<br>-    g<int>(a); // expected-error {{undeclared}} expected-error {{'('}}<br>+    // This is valid in C++20.<br>+    g<int>(a);<br>+#if __cplusplus <= 201703L<br>+    // expected-error@-2 {{C++2a extension}}<br>+#endif<br><br>     // This is not.<br>     template g<int>(a); // expected-error {{expected expression}}<br><br>Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p5.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p5.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p5.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p5.cpp (original)<br>+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p5.cpp Wed May  8 20:31:27 2019<br>@@ -8,7 +8,10 @@ namespace N {<br>   };<br> }<br><br>-template class Z<int>; // expected-error{{explicit instantiation of non-template class 'Z'}}<br>+template class Z<int>; // expected-error{{explicit instantiation of undeclared template class 'Z'}}<br>+<br>+struct Q;<br>+template class Q<int>; // expected-error{{explicit instantiation of non-template class 'Q'}}<br><br> // FIXME: This example from the standard is wrong; note posted to CWG reflector<br> // on 10/27/2009<br><br>Modified: cfe/trunk/test/FixIt/typo-crash.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/typo-crash.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/typo-crash.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/FixIt/typo-crash.cpp (original)<br>+++ cfe/trunk/test/FixIt/typo-crash.cpp Wed May  8 20:31:27 2019<br>@@ -1,14 +1,8 @@<br> // RUN: %clang_cc1 -fsyntax-only -verify %s<br><br>-// FIXME: The diagnostics and recovery here are very, very poor.<br>-<br> // PR10355<br>-template<typename T> void template_id1() { // expected-note {{'template_id1' declared here}} \<br>-  // expected-note {{possible target for call}}<br>-  template_id2<> t; // expected-error {{no template named 'template_id2'; did you mean 'template_id1'?}} \<br>-  // expected-error {{expected ';' after expression}} \<br>-  // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} \<br>-  // expected-error {{use of undeclared identifier 't'}}<br>+template<typename T> void template_id1() {<br>+  template_id2<> t; // expected-error-re {{no template named 'template_id2'{{$}}}}<br>  }<br><br> // FIXME: It would be nice if we could get this correction right.<br><br>Modified: cfe/trunk/test/Misc/diag-template-diffing.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/diag-template-diffing.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/diag-template-diffing.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/Misc/diag-template-diffing.cpp (original)<br>+++ cfe/trunk/test/Misc/diag-template-diffing.cpp Wed May  8 20:31:27 2019<br>@@ -394,7 +394,7 @@ template<double* ...A> class class_ptrs<br> void set13(class_ptrs<&a13, &b13>) {}<br> void test13() {<br>   set13(class_ptrs<&c13>());<br>-  set13(class_ptrss<&a13, &b13, &d13>());<br>+  set13(class_ptrs<&a13, &b13, &d13>());<br> }<br> // CHECK-ELIDE-NOTREE: no matching function for call to 'set13'<br> // CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'class_ptrs<&c13, (no argument)>' to 'class_ptrs<&a13, &b13>' for 1st argument<br><br>Modified: cfe/trunk/test/Modules/module-private.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/module-private.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/module-private.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/Modules/module-private.cpp (original)<br>+++ cfe/trunk/test/Modules/module-private.cpp Wed May  8 20:31:27 2019<br>@@ -18,9 +18,7 @@ int test_broken() {<br>   int *ip = 0;<br>   f1(ip); // expected-error{{use of undeclared identifier 'f1'}}<br><br>-  vector<int> vec; // expected-error{{use of undeclared identifier 'vector'}} \<br>-  // expected-error{{expected '(' for function-style cast or type construction}} \<br>-  // expected-error{{use of undeclared identifier 'vec'}}<br>+  vector<int> vec; // expected-error{{no template named 'vector'}}<br><br>   VisibleStruct vs;<br>   vs.field = 0; // expected-error{{no member named 'field' in 'VisibleStruct'}}<br><br>Modified: cfe/trunk/test/Modules/submodules-merge-defs.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/submodules-merge-defs.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/submodules-merge-defs.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/Modules/submodules-merge-defs.cpp (original)<br>+++ cfe/trunk/test/Modules/submodules-merge-defs.cpp Wed May  8 20:31:27 2019<br>@@ -29,7 +29,7 @@ B::Inner2 pre_bi; // expected-error +{{m<br> // <a href="mailto:expected-note@defs.h" target="_blank">expected-note@defs.h</a>:4 +{{here}}<br> // <a href="mailto:expected-note@defs.h" target="_blank">expected-note@defs.h</a>:17 +{{here}}<br> void pre_bfi(B b) { // expected-error +{{must be imported}}<br>-  b.f<int>(); // expected-error +{{}}<br>+  b.f<int>();<br> }<br><br> C_Base<1> pre_cb1; // expected-error +{{must be imported}}<br>@@ -48,7 +48,7 @@ int pre_e = E(0); // expected-error {{mu<br> // <a href="mailto:expected-note@defs.h" target="_blank">expected-note@defs.h</a>:32 +{{here}}<br><br> int pre_ff = F<int>().f(); // expected-error +{{must be imported}}<br>-int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}} expected-error 2{{expected}}<br>+int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}}<br> // <a href="mailto:expected-note@defs.h" target="_blank">expected-note@defs.h</a>:34 +{{here}}<br><br> G::A pre_ga // expected-error +{{must be imported}}<br><br>Modified: cfe/trunk/test/Parser/cxx-ambig-init-templ.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-ambig-init-templ.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-ambig-init-templ.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/Parser/cxx-ambig-init-templ.cpp (original)<br>+++ cfe/trunk/test/Parser/cxx-ambig-init-templ.cpp Wed May  8 20:31:27 2019<br>@@ -31,7 +31,7 @@ struct S {<br><br>   void f2a(<br>     // T3<int> here is a parameter type, so must be declared before it is used.<br>-    int k1 = c < b, T3 < int > x = 0 // expected-error {{unexpected end of default argument expression}}<br>+    int k1 = c < b, T3 < int > x = 0 // expected-error {{no template named 'T3'}}<br>   );<br><br>   template<typename, int=0> struct T3 { T3(int); operator int(); };<br><br>Modified: cfe/trunk/test/Parser/cxx-template-argument.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-argument.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-argument.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/Parser/cxx-template-argument.cpp (original)<br>+++ cfe/trunk/test/Parser/cxx-template-argument.cpp Wed May  8 20:31:27 2019<br>@@ -60,33 +60,32 @@ namespace pr16225add {<br>   template<int N1, int N2> struct ABC2 {};<br><br>   template<class T1, typename T2> struct foo :<br>-    UnknownBase<T1,T2> // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<T1,T2> // expected-error {{no template named 'UnknownBase'}}<br>   { };<br><br>   template<class T1, typename T2> struct foo2 :<br>-    UnknownBase<T1,T2>, // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<T1,T2>, // expected-error {{no template named 'UnknownBase'}}<br>     Known<T1>  // expected-error {{too few template arguments for class template 'Known'}}<br>   { };<br><br>   template<class T1, typename T2> struct foo3 :<br>-    UnknownBase<T1,T2,ABC<T2,T1> > // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<T1,T2,ABC<T2,T1> > // expected-error {{no template named 'UnknownBase'}}<br>   { };<br><br>   template<class T1, typename T2> struct foo4 :<br>-    UnknownBase<T1,ABC<T2> >, // expected-error {{unknown template name 'UnknownBase'}} \<br>-                              // expected-error {{too few template arguments for class template 'ABC'}}<br>+    UnknownBase<T1,ABC<T2> >, // expected-error {{too few template arguments for class template 'ABC'}}<br>     Known<T1>  // expected-error {{too few template arguments for class template 'Known'}}<br>   { };<br><br>   template<class T1, typename T2> struct foo5 :<br>-    UnknownBase<T1,T2,ABC<T2,T1>> // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<T1,T2,ABC<T2,T1>> // expected-error {{no template named 'UnknownBase'}}<br> #if __cplusplus <= 199711L<br>     // expected-error@-2 {{use '> >'}}<br> #endif<br>   { };<br><br>   template<class T1, typename T2> struct foo6 :<br>-    UnknownBase<T1,ABC<T2,T1>>, // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<T1,ABC<T2,T1>>, // expected-error {{no template named 'UnknownBase'}}<br> #if __cplusplus <= 199711L<br>     // expected-error@-2 {{use '> >'}}<br> #endif<br>@@ -94,32 +93,32 @@ namespace pr16225add {<br>   { };<br><br>   template<class T1, typename T2, int N> struct foo7 :<br>-    UnknownBase<T1,T2,(N>1)> // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<T1,T2,(N>1)> // expected-error {{no template named 'UnknownBase'}}<br>   { };<br><br>   template<class T1, typename T2> struct foo8 :<br>-    UnknownBase<X<int,int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<X<int,int>,X<int,int>> // expected-error {{no template named 'UnknownBase'}}<br> #if __cplusplus <= 199711L<br>     // expected-error@-2 {{use '> >'}}<br> #endif<br>   { };<br><br>   template<class T1, typename T2> struct foo9 :<br>-    UnknownBase<Known<int,int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<Known<int,int>,X<int,int>> // expected-error {{no template named 'UnknownBase'}}<br> #if __cplusplus <= 199711L<br>     // expected-error@-2 {{use '> >'}}<br> #endif<br>   { };<br><br>   template<class T1, typename T2> struct foo10 :<br>-    UnknownBase<Known<int,int>,X<int,X<int,int>>> // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<Known<int,int>,X<int,X<int,int>>> // expected-error {{no template named 'UnknownBase'}}<br> #if __cplusplus <= 199711L<br>     // expected-error@-2 {{use '> >'}}<br> #endif<br>   { };<br><br>   template<int N1, int N2> struct foo11 :<br>-    UnknownBase<2<N1,N2<4> // expected-error {{unknown template name 'UnknownBase'}}<br>+    UnknownBase<2<N1,N2<4> // expected-error {{no template named 'UnknownBase'}}<br>   { };<br><br> }<br><br>Modified: cfe/trunk/test/Parser/cxx-template-decl.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-decl.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-decl.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/Parser/cxx-template-decl.cpp (original)<br>+++ cfe/trunk/test/Parser/cxx-template-decl.cpp Wed May  8 20:31:27 2019<br>@@ -128,8 +128,13 @@ void f2() {<br><br><br> // PR3844<br>-template <> struct S<int> { }; // expected-error{{explicit specialization of non-template struct 'S'}}<br>-template <> union U<int> { }; // expected-error{{explicit specialization of non-template union 'U'}}<br>+template <> struct S<int> { }; // expected-error{{explicit specialization of undeclared template struct 'S'}}<br>+template <> union U<int> { }; // expected-error{{explicit specialization of undeclared template union 'U'}}<br>+<br>+struct SS;<br>+union UU;<br>+template <> struct SS<int> { }; // expected-error{{explicit specialization of non-template struct 'SS'}}<br>+template <> union UU<int> { }; // expected-error{{explicit specialization of non-template union 'UU'}}<br><br> namespace PR6184 {<br>   namespace N {<br>@@ -230,11 +235,11 @@ struct base { };<br><br> struct t1 : base<int,<br>   public:  // expected-error {{expected expression}}<br>-};  // expected-error {{expected class name}}<br>+};<br> // expected-error@-1 {{expected '{' after base class list}}<br> struct t2 : base<int,<br>   public  // expected-error {{expected expression}}<br>-};  // expected-error {{expected class name}}<br>+};<br> // expected-error@-1 {{expected '{' after base class list}}<br><br> }<br><br>Modified: cfe/trunk/test/SemaCXX/alias-template.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/alias-template.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/alias-template.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaCXX/alias-template.cpp (original)<br>+++ cfe/trunk/test/SemaCXX/alias-template.cpp Wed May  8 20:31:27 2019<br>@@ -112,11 +112,8 @@ namespace StdExample {<br>   template<typename T> using handler_t = void (*)(T);<br>   extern handler_t<int> ignore;<br>   extern void (*ignore)(int);<br>-  // FIXME: we recover as if cell is an undeclared variable. the diagnostics are terrible!<br>-  template<typename T> using cell = pair<T*, cell<T>*>; // expected-error {{use of undeclared identifier 'cell'}} \<br>-                                                           expected-error {{'T' does not refer to a value}} \<br>-                                                           expected-note {{declared here}} \<br>-                                                           expected-error {{expected ';' after alias declaration}}<br>+  // FIXME: we recover as if cell is an undeclared variable template<br>+  template<typename T> using cell = pair<T*, cell<T>*>; // expected-error {{use of undeclared identifier 'cell'}} expected-error {{expected expression}}<br> }<br><br> namespace Access {<br><br>Modified: cfe/trunk/test/SemaCXX/class.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaCXX/class.cpp (original)<br>+++ cfe/trunk/test/SemaCXX/class.cpp Wed May  8 20:31:27 2019<br>@@ -138,7 +138,7 @@ struct S<br> // Don't crash on this bogus code.<br> namespace pr6629 {<br>   template<class T1, class T2> struct foo :<br>-    bogus<foo<T1,T2> > // expected-error {{unknown template name 'bogus'}}<br>+    bogus<foo<T1,T2> > // expected-error {{no template named 'bogus'}}<br>   { };<br><br>   template<> struct foo<unknown,unknown> { // expected-error {{undeclared identifier 'unknown'}}<br><br>Added: cfe/trunk/test/SemaCXX/cxx2a-adl-only-template-id.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx2a-adl-only-template-id.cpp?rev=360308&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx2a-adl-only-template-id.cpp?rev=360308&view=auto</a><br>==============================================================================<br>--- cfe/trunk/test/SemaCXX/cxx2a-adl-only-template-id.cpp (added)<br>+++ cfe/trunk/test/SemaCXX/cxx2a-adl-only-template-id.cpp Wed May  8 20:31:27 2019<br>@@ -0,0 +1,67 @@<br>+// RUN: %clang_cc1 -std=c++2a -verify %s<br>+<br>+namespace N {<br>+  struct Q {};<br>+  template<typename> int f(Q);<br>+  template<int> int f(Q);<br>+  template<typename> int g(Q);<br>+  template<int> int g(Q);<br>+<br>+  template<int> int some_long_name(Q); // expected-note {{here}}<br>+}<br>+N::Q q;<br>+int g();<br>+<br>+int h();<br>+template<int> int h(...);<br>+int h(int);<br>+<br>+// OK, these find the above functions by ADL.<br>+int a = f<int>(q);<br>+int b(f<int>(q));<br>+int c(f<0>(q));<br>+int d = g<int>(q);<br>+<br>+int e = h<0>(q); // ok, found by unqualified lookup<br>+<br>+void fn() {<br>+  f<0>(q);<br>+  int f;<br>+  f<0>(q); // expected-error {{invalid operands to binary expression}}<br>+}<br>+<br>+void disambig() {<br>+  // FIXME: It's unclear whether ending the template argument at the > inside the ?: is correct here (see DR579).<br>+  f<true ? 1 > 2 : 3>(q); // expected-error {{expected ':'}} expected-note {{to match}} expected-error {{expected expression}}<br>+<br>+  f < 1 + 3 > (q); // ok, function call<br>+}<br>+<br>+bool typo(int something) { // expected-note 4{{declared here}}<br>+  // FIXME: We shouldn't suggest the N:: for an ADL call if the candidate can be found by ADL.<br>+  some_logn_name<3>(q); // expected-error {{did you mean 'N::some_long_name'?}}<br>+  somethign < 3 ? h() > 4 : h(0); // expected-error {{did you mean 'something'}}<br>+  // This is parsed as a comparison on the left of a ?: expression.<br>+  somethign < 3 ? h() + 4 : h(0); // expected-error {{did you mean 'something'}}<br>+  // This is parsed as an ADL-only template-id call.<br>+  somethign < 3 ? h() + 4 : h(0) >(0); // expected-error {{undeclared identifier 'somethign'}}<br>+  bool k(somethign < 3); // expected-error {{did you mean 'something'}}<br>+  return somethign < 3; // expected-error {{did you mean 'something'}}<br>+}<br>+<br>+// Ensure that treating undeclared identifiers as template names doesn't cause<br>+// problems.<br>+struct W<int> {}; // expected-error {{undeclared template struct 'W'}}<br>+X<int>::Y xy; // expected-error {{no template named 'X'}}<br>+void xf(X<int> x); // expected-error {{no template named 'X'}}<br>+struct A : X<int> { // expected-error {{no template named 'X'}}<br>+  A() : X<int>() {} // expected-error {{no template named 'X'}}<br>+};<br>+<br>+// Similarly for treating overload sets of functions as template names.<br>+struct g<int> {}; // expected-error {{'g' refers to a function template}}<br>+g<int>::Y xy; // expected-error {{no template named 'g'}} FIXME lies<br>+void xf(g<int> x); // expected-error {{variable has incomplete type 'void'}} expected-error 1+{{}} expected-note {{}}<br>+struct B : g<int> { // expected-error {{expected class name}}<br>+  B() : g<int>() {} // expected-error {{expected class member or base class name}}<br>+};<br><br>Modified: cfe/trunk/test/SemaCXX/destructor.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/destructor.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/destructor.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaCXX/destructor.cpp (original)<br>+++ cfe/trunk/test/SemaCXX/destructor.cpp Wed May  8 20:31:27 2019<br>@@ -99,7 +99,7 @@ struct Y {<br> namespace PR6421 {<br>   class T; // expected-note{{forward declaration}}<br><br>-  class QGenericArgument // expected-note{{declared here}}<br>+  class QGenericArgument<br>   {<br>     template<typename U><br>     void foo(T t) // expected-error{{variable has incomplete type}}<br>@@ -108,8 +108,7 @@ namespace PR6421 {<br>     void disconnect()<br>     {<br>       T* t;<br>-      bob<QGenericArgument>(t); // expected-error{{undeclared identifier 'bob'}} \<br>-      // expected-error{{does not refer to a value}}<br>+      bob<QGenericArgument>(t); // expected-error{{undeclared identifier 'bob'}}<br>     }<br>   };<br> }<br><br>Modified: cfe/trunk/test/SemaCXX/invalid-member-expr.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/invalid-member-expr.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/invalid-member-expr.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaCXX/invalid-member-expr.cpp (original)<br>+++ cfe/trunk/test/SemaCXX/invalid-member-expr.cpp Wed May  8 20:31:27 2019<br>@@ -53,7 +53,10 @@ namespace test3 {<br> namespace rdar11293995 {<br><br> struct Length {<br>-  explicit Length(PassRefPtr<CalculationValue>); // expected-error {{no template named 'PassRefPtr}} expected-error {{undeclared identifier 'CalculationValue'}}<br>+  // FIXME: We try to annotate the template-id here during tentative parsing,<br>+  // and fail, then try again during the actual parse. This results in the same<br>+  // diagnostic being produced twice. :(<br>+  explicit Length(PassRefPtr<CalculationValue>); // expected-error 2{{undeclared identifier 'CalculationValue'}}<br> };<br><br> struct LengthSize {<br><br>Modified: cfe/trunk/test/SemaCXX/typo-correction.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typo-correction.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typo-correction.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaCXX/typo-correction.cpp (original)<br>+++ cfe/trunk/test/SemaCXX/typo-correction.cpp Wed May  8 20:31:27 2019<br>@@ -438,7 +438,7 @@ namespace PR17394 {<br>     long zzzzzzzzzz;<br>   };<br>   class B : private A {};<br>-  B zzzzzzzzzy<>; // expected-error {{expected ';' after top level declarator}}{}<br>+  B zzzzzzzzzy<>; // expected-error {{template specialization requires 'template<>'}} expected-error {{no variable template matches specialization}}<br> }<br><br> namespace correct_fields_in_member_funcs {<br><br>Modified: cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp (original)<br>+++ cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp Wed May  8 20:31:27 2019<br>@@ -9,7 +9,7 @@ template<typename T, typename U><br> struct X1 : T::apply<U> { }; // expected-error{{use 'template' keyword to treat 'apply' as a dependent template name}}<br><br> template<typename T><br>-struct X2 : vector<T> { }; // expected-error{{unknown template name 'vector'}}<br>+struct X2 : vector<T> { }; // expected-error{{no template named 'vector'}}<br><br> namespace PR6031 {<br>   template<typename T><br><br>Modified: cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp (original)<br>+++ cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp Wed May  8 20:31:27 2019<br>@@ -7,7 +7,7 @@ struct X {<br><br>     t->operator+<U const, 1>(1); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}}<br>     t->f1<int const, 2>(1); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}}<br>-    t->f1<3, int const>(1); // expected-error{{missing 'template' keyword prior to dependent template name 'f1'}}<br>+    t->f1<3, int const>(1); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}}<br><br>     T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}<br>     t->T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}<br>@@ -15,7 +15,7 @@ struct X {<br>     (*t).f2<N>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}<br>     (*t).f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}<br>     T::f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}<br>-    T::f2<0, int>(0); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}}<br>+    T::f2<0, int>(0); // expected-error{{use 'template' keyword to treat 'f2' as a dependent template name}}<br><br>     T::foo<N < 2 || N >= 4>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}<br><br>@@ -24,7 +24,7 @@ struct X {<br>     T::foo<T::bar < 1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}<br>     T::foo < T::bar<1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'bar'}}<br><br>-    // Prefer to diagonse a missing 'template' keyword rather than finding a non-template name.<br>+    // Prefer to diagnose a missing 'template' keyword rather than finding a non-template name.<br>     xyz < T::foo < 1 > (); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}<br>     T::foo < xyz < 1 > (); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}}<br><br>@@ -83,12 +83,12 @@ template<int N, typename T> void f(T t)<br>   T::g<mb>(0);<br><br>   // ... but this one must be a template-id.<br>-  T::g<mb, int>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'g'}}<br>+  T::g<mb, int>(0); // expected-error {{use 'template' keyword to treat 'g' as a dependent template name}} expected-error {{no matching function}}<br> }<br><br> struct Y {<br>   template <int> void f(int);<br>-  template <int = 0> static void g(int); // expected-warning 0-1{{extension}}<br>+  template <int = 0> static void g(int); // expected-warning 0-1{{extension}} expected-note {{candidate}}<br> };<br> void q() { void (*p)(int) = Y::g; }<br> template void f<0>(Y); // expected-note {{in instantiation of}}<br><br>Modified: cfe/trunk/test/SemaTemplate/rdar9173693.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/rdar9173693.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/rdar9173693.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaTemplate/rdar9173693.cpp (original)<br>+++ cfe/trunk/test/SemaTemplate/rdar9173693.cpp Wed May  8 20:31:27 2019<br>@@ -2,5 +2,8 @@<br><br> // <<a>rdar://problem/9173693</a>><br> template< bool C > struct assert { };<br>-template< bool > struct assert_arg_pred_impl { }; // expected-note 3 {{declared here}}<br>-template< typename Pred > assert<false> assert_not_arg( void (*)(Pred), typename assert_arg_pred<Pred>::type ); // expected-error 5 {{}}<br>+// FIXME: We diagnose the same problem multiple times here because we have no<br>+// way to indicate in the token stream that we already tried to annotate a<br>+// template-id and we failed.<br>+template< bool > struct assert_arg_pred_impl { }; // expected-note 4 {{declared here}}<br>+template< typename Pred > assert<false> assert_not_arg( void (*)(Pred), typename assert_arg_pred<Pred>::type ); // expected-error 6 {{}}<br><br>Modified: cfe/trunk/test/SemaTemplate/recovery-crash.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/recovery-crash.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/recovery-crash.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/test/SemaTemplate/recovery-crash.cpp (original)<br>+++ cfe/trunk/test/SemaTemplate/recovery-crash.cpp Wed May  8 20:31:27 2019<br>@@ -28,12 +28,12 @@ namespace PR16134 {<br> namespace PR16225 {<br>   template <typename T> void f();<br>   template <typename C> void g(C*) {<br>-    struct LocalStruct : UnknownBase<Mumble, C> { };  // expected-error {{unknown template name 'UnknownBase'}} \<br>-                                                      // expected-error {{use of undeclared identifier 'Mumble'}}<br>+    struct LocalStruct : UnknownBase<Mumble, C> { };  // expected-error {{use of undeclared identifier 'Mumble'}}<br>     f<LocalStruct>();<br> #if __cplusplus <= 199711L<br>     // expected-warning@-2 {{template argument uses local type 'LocalStruct'}}<br> #endif<br>+    struct LocalStruct2 : UnknownBase<C> { };  // expected-error {{no template named 'UnknownBase'}}<br>   }<br>   struct S;<br>   void h() {<br><br>Modified: cfe/trunk/tools/libclang/CIndex.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/tools/libclang/CIndex.cpp (original)<br>+++ cfe/trunk/tools/libclang/CIndex.cpp Wed May  8 20:31:27 2019<br>@@ -1430,6 +1430,10 @@ bool CursorVisitor::VisitTemplateName(Te<br><br>     return false;<br><br>+  case TemplateName::AssumedTemplate:<br>+    // FIXME: Visit DeclarationName?<br>+    return false;<br>+<br>   case TemplateName::DependentTemplate:<br>     // FIXME: Visit nested-name-specifier.<br>     return false;<br><br>Modified: cfe/trunk/www/cxx_status.html<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=360308&r1=360307&r2=360308&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=360308&r1=360307&r2=360308&view=diff</a><br>==============================================================================<br>--- cfe/trunk/www/cxx_status.html (original)<br>+++ cfe/trunk/www/cxx_status.html Wed May  8 20:31:27 2019<br>@@ -893,7 +893,7 @@ as the draft C++2a standard evolves.<br>     <tr><br>       <td>ADL and function templates that are not visible</td><br>       <td><a href="<a href="http://wg21.link/p0846r0" target="_blank">http://wg21.link/p0846r0</a>">P0846R0</a></td><br>-      <td class="none" align="center">No</td><br>+      <td class="svn" align="center">SVN</td><br>     </tr><br>     <tr><br>       <td><tt>const</tt> mismatch with defaulted copy constructor</td><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" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br></div></div></blockquote></div><br></div></div>_______________________________________________<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>
_______________________________________________<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>