llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-modules Author: Krystian Stasiowski (sdkrystian) <details> <summary>Changes</summary> This reapplies #<!-- -->92957 and #<!-- -->98547 with the following changes: - We only apply the resolution to CWG1835 in C++23 and later, and - We issue a diagnostic when its application results in a missing template keyword that breaks whatever construct that follows the intended template name. e.g. ```cpp template<int I> struct A { int x; }; template<int I> struct B : A<I> { void f() { this->A<I>::f(); // with -std=c++20 and earlier: no error // with -std=c++23 and later: // error: no member named 'f' in the global namespace // error: missing 'template' keyword prior to dependent template name 'A' } }; ``` Only applying the resolution in C++23 and later conveniently gets around [a bug in GCC releases prior to 11.1](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94799) that prohibits the use of `template` prior to the _nested-name-specifier_ in a class member access expression as the affected versions do not support C++23. --- Patch is 167.88 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/100425.diff 47 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+3) - (modified) clang/include/clang/AST/ExprCXX.h (+49-43) - (modified) clang/include/clang/AST/Stmt.h (+8-7) - (modified) clang/include/clang/AST/UnresolvedSet.h (+4) - (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+1-3) - (modified) clang/include/clang/Parse/Parser.h (+7-10) - (modified) clang/include/clang/Sema/DeclSpec.h (+8) - (modified) clang/include/clang/Sema/Lookup.h (+6-2) - (modified) clang/include/clang/Sema/Sema.h (+38-42) - (modified) clang/lib/AST/ASTImporter.cpp (+9-3) - (modified) clang/lib/AST/ExprCXX.cpp (+39-27) - (modified) clang/lib/AST/ItaniumMangle.cpp (+15-24) - (modified) clang/lib/Parse/ParseExpr.cpp (+4-6) - (modified) clang/lib/Parse/ParseExprCXX.cpp (+54-50) - (modified) clang/lib/Parse/ParseOpenMP.cpp (+1-3) - (modified) clang/lib/Parse/ParseTemplate.cpp (+40) - (modified) clang/lib/Sema/SemaCXXScopeSpec.cpp (+95-104) - (modified) clang/lib/Sema/SemaCoroutine.cpp (+2-2) - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+23-24) - (modified) clang/lib/Sema/SemaExpr.cpp (+1-1) - (modified) clang/lib/Sema/SemaExprMember.cpp (+33-42) - (modified) clang/lib/Sema/SemaOverload.cpp (+5-7) - (modified) clang/lib/Sema/SemaStmtAsm.cpp (+5-3) - (modified) clang/lib/Sema/SemaTemplate.cpp (+111-114) - (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+7-10) - (modified) clang/lib/Sema/TreeTransform.h (+131-198) - (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+32-31) - (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+25-18) - (modified) clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp (+9-5) - (modified) clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp (+9-5) - (added) clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3-example3.cpp (+27) - (added) clang/test/CXX/basic/basic.lookup/basic.lookup.qual/basic.lookup.qual.general/p3.cpp (+98) - (modified) clang/test/CXX/drs/cwg1xx.cpp (+12-10) - (added) clang/test/CXX/temp/temp.names/p3-23.cpp (+237) - (modified) clang/test/CXX/temp/temp.res/p3.cpp (+1-1) - (modified) clang/test/FixIt/fixit.cpp (+2-2) - (modified) clang/test/Misc/warning-flags.c (+1-1) - (modified) clang/test/Parser/cxx2a-concepts-requires-expr.cpp (+1-1) - (modified) clang/test/SemaCXX/cxx0x-noexcept-expression.cpp (+3-3) - (modified) clang/test/SemaCXX/nested-name-spec.cpp (+4-4) - (modified) clang/test/SemaCXX/pseudo-destructors.cpp (+16-11) - (modified) clang/test/SemaTemplate/dependent-base-classes.cpp (+10-10) - (modified) clang/test/SemaTemplate/dependent-template-recover.cpp (+6-6) - (modified) clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp (+1-1) - (modified) clang/test/SemaTemplate/template-id-expr.cpp (+7-7) - (modified) clang/test/SemaTemplate/typename-specifier-3.cpp (+1-1) - (modified) libcxx/include/regex (+1-1) ``````````diff diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a34f109ba21ce..1ffc759f7e4b8 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -313,6 +313,9 @@ Resolutions to C++ Defect Reports - Clang now considers ``noexcept(typeid(expr))`` more carefully, instead of always assuming that ``std::bad_typeid`` can be thrown. (`CWG2191: Incorrect result for noexcept(typeid(v)) <https://cplusplus.github.io/CWG/issues/2191.html>`_). +- Clang now correctly implements lookup for the terminal name of a member-qualified nested-name-specifier. + (`CWG1835: Dependent member lookup before < <https://cplusplus.github.io/CWG/issues/1835.html>`_). + C Language Changes ------------------ diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index c2feac525c1ea..edaea6fe27cc3 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -3676,9 +3676,9 @@ class CXXUnresolvedConstructExpr final /// an implicit access if a qualifier is provided. class CXXDependentScopeMemberExpr final : public Expr, - private llvm::TrailingObjects<CXXDependentScopeMemberExpr, - ASTTemplateKWAndArgsInfo, - TemplateArgumentLoc, NamedDecl *> { + private llvm::TrailingObjects< + CXXDependentScopeMemberExpr, NestedNameSpecifierLoc, DeclAccessPair, + ASTTemplateKWAndArgsInfo, TemplateArgumentLoc> { friend class ASTStmtReader; friend class ASTStmtWriter; friend TrailingObjects; @@ -3691,17 +3691,15 @@ class CXXDependentScopeMemberExpr final /// implicit accesses. QualType BaseType; - /// The nested-name-specifier that precedes the member name, if any. - /// FIXME: This could be in principle store as a trailing object. - /// However the performance impact of doing so should be investigated first. - NestedNameSpecifierLoc QualifierLoc; - /// The member to which this member expression refers, which /// can be name, overloaded operator, or destructor. /// /// FIXME: could also be a template-id DeclarationNameInfo MemberNameInfo; + /// The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + // CXXDependentScopeMemberExpr is followed by several trailing objects, // some of which optional. They are in order: // @@ -3721,8 +3719,16 @@ class CXXDependentScopeMemberExpr final return CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo; } - bool hasFirstQualifierFoundInScope() const { - return CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope; + unsigned getNumUnqualifiedLookups() const { + return CXXDependentScopeMemberExprBits.NumUnqualifiedLookups; + } + + unsigned numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const { + return hasQualifier(); + } + + unsigned numTrailingObjects(OverloadToken<DeclAccessPair>) const { + return getNumUnqualifiedLookups(); } unsigned numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { @@ -3733,33 +3739,32 @@ class CXXDependentScopeMemberExpr final return getNumTemplateArgs(); } - unsigned numTrailingObjects(OverloadToken<NamedDecl *>) const { - return hasFirstQualifierFoundInScope(); - } - CXXDependentScopeMemberExpr(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierFoundInScope, + ArrayRef<DeclAccessPair> UnqualifiedLookups, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs); - CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasTemplateKWAndArgsInfo, - bool HasFirstQualifierFoundInScope); + CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasQualifier, + unsigned NumUnqualifiedLookups, + bool HasTemplateKWAndArgsInfo); public: static CXXDependentScopeMemberExpr * Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope, + SourceLocation TemplateKWLoc, + ArrayRef<DeclAccessPair> UnqualifiedLookups, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs); static CXXDependentScopeMemberExpr * - CreateEmpty(const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo, - unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope); + CreateEmpty(const ASTContext &Ctx, bool HasQualifier, + unsigned NumUnqualifiedLookups, bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); /// True if this is an implicit access, i.e. one in which the /// member being accessed was not written in the source. The source @@ -3784,34 +3789,35 @@ class CXXDependentScopeMemberExpr final bool isArrow() const { return CXXDependentScopeMemberExprBits.IsArrow; } /// Retrieve the location of the '->' or '.' operator. - SourceLocation getOperatorLoc() const { - return CXXDependentScopeMemberExprBits.OperatorLoc; + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// Determines whether this member expression had a nested-name-specifier + /// prior to the name of the member, e.g., x->Base::foo. + bool hasQualifier() const { + return CXXDependentScopeMemberExprBits.HasQualifier; } - /// Retrieve the nested-name-specifier that qualifies the member name. - NestedNameSpecifier *getQualifier() const { - return QualifierLoc.getNestedNameSpecifier(); + /// If the member name was qualified, retrieves the nested-name-specifier + /// that precedes the member name, with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { + if (!hasQualifier()) + return NestedNameSpecifierLoc(); + return *getTrailingObjects<NestedNameSpecifierLoc>(); } - /// Retrieve the nested-name-specifier that qualifies the member - /// name, with source location information. - NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + /// If the member name was qualified, retrieves the + /// nested-name-specifier that precedes the member name. Otherwise, returns + /// NULL. + NestedNameSpecifier *getQualifier() const { + return getQualifierLoc().getNestedNameSpecifier(); + } - /// Retrieve the first part of the nested-name-specifier that was - /// found in the scope of the member access expression when the member access - /// was initially parsed. - /// - /// This function only returns a useful result when member access expression - /// uses a qualified member name, e.g., "x.Base::f". Here, the declaration - /// returned by this function describes what was found by unqualified name - /// lookup for the identifier "Base" within the scope of the member access - /// expression itself. At template instantiation time, this information is - /// combined with the results of name lookup into the type of the object - /// expression itself (the class type of x). - NamedDecl *getFirstQualifierFoundInScope() const { - if (!hasFirstQualifierFoundInScope()) - return nullptr; - return *getTrailingObjects<NamedDecl *>(); + /// Retrieve the declarations found by unqualified lookup for the first + /// component name of the nested-name-specifier, if any. + ArrayRef<DeclAccessPair> unqualified_lookups() const { + if (!getNumUnqualifiedLookups()) + return std::nullopt; + return {getTrailingObjects<DeclAccessPair>(), getNumUnqualifiedLookups()}; } /// Retrieve the name of the member that this expression refers to. diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 9cd7a364cd3f1..257a61c97c9c6 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1020,18 +1020,19 @@ class alignas(void *) Stmt { LLVM_PREFERRED_TYPE(bool) unsigned IsArrow : 1; + /// True if this member expression used a nested-name-specifier to + /// refer to the member, e.g., "x->Base::f". + LLVM_PREFERRED_TYPE(bool) + unsigned HasQualifier : 1; + /// Whether this member expression has info for explicit template /// keyword and arguments. LLVM_PREFERRED_TYPE(bool) unsigned HasTemplateKWAndArgsInfo : 1; - /// See getFirstQualifierFoundInScope() and the comment listing - /// the trailing objects. - LLVM_PREFERRED_TYPE(bool) - unsigned HasFirstQualifierFoundInScope : 1; - - /// The location of the '->' or '.' operator. - SourceLocation OperatorLoc; + /// Number of declarations found by unqualified lookup for the + /// first component name of the nested-name-specifier. + unsigned NumUnqualifiedLookups; }; class OverloadExprBitfields { diff --git a/clang/include/clang/AST/UnresolvedSet.h b/clang/include/clang/AST/UnresolvedSet.h index 1369725ab4e96..ef44499ce5926 100644 --- a/clang/include/clang/AST/UnresolvedSet.h +++ b/clang/include/clang/AST/UnresolvedSet.h @@ -97,6 +97,10 @@ class UnresolvedSetImpl { decls().push_back(DeclAccessPair::make(D, AS)); } + void addAllDecls(ArrayRef<DeclAccessPair> Other) { + append(iterator(Other.begin()), iterator(Other.end())); + } + /// Replaces the given declaration with the new one, once. /// /// \return true if the set changed diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 12aab09f28556..0bd2e35bf2e31 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -895,9 +895,7 @@ def missing_template_arg_list_after_template_kw : Extension< "keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>, DefaultError; -def err_missing_dependent_template_keyword : Error< - "use 'template' keyword to treat '%0' as a dependent template name">; -def warn_missing_dependent_template_keyword : ExtWarn< +def ext_missing_dependent_template_keyword : ExtWarn< "use 'template' keyword to treat '%0' as a dependent template name">; def ext_extern_template : Extension< diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 126fea0aef2a7..134bb1b3534e7 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1906,6 +1906,7 @@ class Parser : public CodeCompletionHandler { } bool diagnoseUnknownTemplateId(ExprResult TemplateName, SourceLocation Less); + bool isMissingTemplateKeywordBeforeScope(); void checkPotentialAngleBracket(ExprResult &PotentialTemplateName); bool checkPotentialAngleBracketDelimiter(const AngleBracketTracker::Loc &, const Token &OpToken); @@ -1966,7 +1967,7 @@ class Parser : public CodeCompletionHandler { //===--------------------------------------------------------------------===// // C++ Expressions ExprResult tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, - Token &Replacement); + Token *Replacement = nullptr); ExprResult tryParseCXXPackIndexingExpression(ExprResult PackIdExpression); ExprResult ParseCXXPackIndexingExpression(ExprResult PackIdExpression); @@ -3372,15 +3373,11 @@ class Parser : public CodeCompletionHandler { BaseResult ParseBaseSpecifier(Decl *ClassDecl); AccessSpecifier getAccessSpecifierIfPresent() const; - bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, - ParsedType ObjectType, - bool ObjectHadErrors, - SourceLocation TemplateKWLoc, - IdentifierInfo *Name, - SourceLocation NameLoc, - bool EnteringContext, - UnqualifiedId &Id, - bool AssumeTemplateId); + bool ParseUnqualifiedIdTemplateId( + CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, + SourceLocation TemplateKWLoc, SourceLocation TildeLoc, + IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext, + UnqualifiedId &Id, bool AssumeTemplateId); bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, ParsedType ObjectType, UnqualifiedId &Result); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 425b6e2a0b30c..9c22c35535ede 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -75,6 +75,7 @@ class CXXScopeSpec { SourceRange Range; NestedNameSpecifierLocBuilder Builder; ArrayRef<TemplateParameterList *> TemplateParamLists; + ArrayRef<DeclAccessPair> UnqualifiedLookups; public: SourceRange getRange() const { return Range; } @@ -91,6 +92,13 @@ class CXXScopeSpec { return TemplateParamLists; } + void setUnqualifiedLookups(ArrayRef<DeclAccessPair> Found) { + UnqualifiedLookups = Found; + } + ArrayRef<DeclAccessPair> getUnqualifiedLookups() const { + return UnqualifiedLookups; + } + /// Retrieve the representation of the nested-name-specifier. NestedNameSpecifier *getScopeRep() const { return Builder.getRepresentation(); diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h index b0a08a05ac6a0..6b765ef3c980f 100644 --- a/clang/include/clang/Sema/Lookup.h +++ b/clang/include/clang/Sema/Lookup.h @@ -483,11 +483,15 @@ class LookupResult { ResultKind = Found; } + void addAllDecls(ArrayRef<DeclAccessPair> Other) { + Decls.addAllDecls(Other); + ResultKind = Found; + } + /// Add all the declarations from another set of lookup /// results. void addAllDecls(const LookupResult &Other) { - Decls.append(Other.Decls.begin(), Other.Decls.end()); - ResultKind = Found; + addAllDecls(Other.Decls.pairs()); } /// Determine whether no result was found because we could not diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 48dff1b76cc57..a86decb67bca1 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2803,7 +2803,8 @@ class Sema final : public SemaBase { /// (e.g., Base::), perform name lookup for that identifier as a /// nested-name-specifier within the given scope, and return the result of /// that name lookup. - NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); + bool LookupFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS, + UnresolvedSetImpl &R); /// Keeps information about an identifier in a nested-name-spec. /// @@ -2843,9 +2844,6 @@ class Sema final : public SemaBase { /// \param EnteringContext If true, enter the context specified by the /// nested-name-specifier. /// \param SS Optional nested name specifier preceding the identifier. - /// \param ScopeLookupResult Provides the result of name lookup within the - /// scope of the nested-name-specifier that was computed at template - /// definition time. /// \param ErrorRecoveryLookup Specifies if the method is called to improve /// error recovery and what kind of recovery is performed. /// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':' @@ -2854,11 +2852,6 @@ class Sema final : public SemaBase { /// not '::'. /// \param OnlyNamespace If true, only considers namespaces in lookup. /// - /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in - /// that it contains an extra parameter \p ScopeLookupResult, which provides - /// the result of name lookup within the scope of the nested-name-specifier - /// that was computed at template definition time. - /// /// If ErrorRecoveryLookup is true, then this call is used to improve error /// recovery. This means that it should not emit diagnostics, it should /// just return true on failure. It also means it should only return a valid @@ -2867,7 +2860,6 @@ class Sema final : public SemaBase { /// specifier. bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, - NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, bool *IsCorrectedToColon = nullptr, bool OnlyNamespace = false); @@ -8567,11 +8559,12 @@ class Sema final : public SemaBase { const TemplateArgumentListInfo *TemplateArgs, bool IsDefiniteInstance, const Scope *S); - ExprResult ActOnDependentMemberExpr( - Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs); + ExprResult + ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OpLoc, const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); /// The main callback when the parser finds something like /// expression . [nested-name-specifier] identifier @@ -8627,15 +8620,14 @@ class Sema final : public SemaBase { ExprResult BuildMemberReferenceExpr( Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, + const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - NamedDecl *FirstQualifierInScope, LookupResult &R, + SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, bool SuppressQualifierCheck = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); @@ -11123,15 +11115,14 @@ class Sema final : public SemaBase { QualType ObjectType, bool EnteringContext, RequiredTemplateKind RequiredTemplate = SourceLocation(), AssumedTemplateKind *ATK = nullptr, - bool AllowTypoCorrection = true); + bool AllowTypoCorrection = true, bool MayBeNNS = false); - TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, - bool hasTemplateKeyword, - const UnqualifiedId &Name, - ParsedType ObjectType, bool EnteringContext, - TemplateTy &Template, - bool &MemberOfUnknownSpecialization, - bool Disambiguation = false); + TemplateNameKind + isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, + const UnqualifiedId &Name, ParsedType ObjectType, + bool EnteringContext, TemplateTy &Template, + bool &MemberOfUnknownSpecialization, + bool Disambiguation = false, bool MayBeNNS = false); /// Try to resolve an undeclared templa... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/100425 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits