<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>