r360308 - [c++20] Implement P0846R0: allow (ADL-only) calls to template-ids whose
Alex L via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 13 18:08:55 PDT 2019
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.
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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20190813/b8190906/attachment-0001.html>
More information about the cfe-commits
mailing list