r360308 - [c++20] Implement P0846R0: allow (ADL-only) calls to template-ids whose

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 14 16:08:39 PDT 2019


Interesting. This is a pre-existing bug that started showing up more after
this change. For example, we've always rejected this related example:

typedef __attribute__((__ext_vector_type__(4))) float vector_float4;
template<typename T> struct xyzw {};
vector_float4 foo123(vector_float4 &A, vector_float4 &B) {
  return A.xyzw < B.x && B.y > A.y;
}

and similarly (and more problematically) we reject this after
typo-correcting from something valid to something invalid:

typedef __attribute__((__ext_vector_type__(4))) float vector_float4;
template<typename T> struct xyzv {};
vector_float4 foo123(vector_float4 &A, vector_float4 &B) {
  return A.xyzw < B.x && B.y > A.y; // typo-corrected to xyzv and then
rejected
}

All that is fixed in r368940. However, that change regresses this:

template<typename T> using V4 = T __attribute__((ext_vector_type(4)));
void f(V4<int> v) { v.V4<int>::~V4<int>(); }

... because we no longer look for a template named 'V4' here and instead
interpret 'V4' as a vector swizzle name. But it's not obvious to me whether
that's actually wrong; it seems somewhat more consistent to say that we
behave as if all identifiers are valid "member" names for a vector, but
some of them might name invalid vector components and thus be ill-formed.
(Presumably the alternative would be to allow cases such as the above but
only if V4 is spelled in a way that's not a valid swizzle for the vector,
which seems like an unfortunate choice for extensibility of the swizzle
syntax if nothing else.)

The OpenCL/C++ specification doesn't appear to give any hints as to how to
handle this.

On Tue, 13 Aug 2019 at 19:29, Richard Smith <richard at metafoo.co.uk> wrote:

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


More information about the cfe-commits mailing list