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