diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 31840694da27..1ae219781c69 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1088,31 +1088,6 @@ public: } }; - /// Introduces zero or more scopes for parsing. The scopes will all be exited - /// when the object is destroyed. - class MultiParseScope { - Parser &Self; - unsigned NumScopes = 0; - - MultiParseScope(const MultiParseScope&) = delete; - - public: - MultiParseScope(Parser &Self) : Self(Self) {} - void Enter(unsigned ScopeFlags) { - Self.EnterScope(ScopeFlags); - ++NumScopes; - } - void Exit() { - while (NumScopes) { - Self.ExitScope(); - --NumScopes; - } - } - ~MultiParseScope() { - Exit(); - } - }; - /// EnterScope - Start a new scope. void EnterScope(unsigned ScopeFlags); @@ -3265,7 +3240,7 @@ private: DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none); - bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth, + bool ParseTemplateParameters(unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index b7260f15fe1b..9b8f1415a1e3 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -322,21 +322,8 @@ public: /// declared in. bool isDeclScope(const Decl *D) const { return DeclsInScope.count(D) != 0; } - /// Get the entity corresponding to this scope. - DeclContext *getEntity() const { - return isTemplateParamScope() ? nullptr : Entity; - } - - /// Get the DeclContext in which to continue unqualified lookup after a - /// lookup in this scope. - DeclContext *getLookupEntity() const { return Entity; } - - void setEntity(DeclContext *E) { - assert(!isTemplateParamScope() && - "entity associated with template param scope"); - Entity = E; - } - void setLookupEntity(DeclContext *E) { Entity = E; } + DeclContext *getEntity() const { return Entity; } + void setEntity(DeclContext *E) { Entity = E; } /// Determine whether any unrecoverable errors have occurred within this /// scope. Note that this may return false even if the scope contains invalid diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 50ad0255f838..2aab53f4fa90 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -241,7 +241,7 @@ TemplateDecl *Decl::getDescribedTemplate() const { } bool Decl::isTemplated() const { - // A declaration is templated if it is a template or a template pattern, or + // A declaration is dependent if it is a template or a template pattern, or // is within (lexcially for a friend, semantically otherwise) a dependent // context. // FIXME: Should local extern declarations be treated like friends? diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index aa35200c33b6..48277dc85466 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1258,16 +1258,17 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( }; // FIXME: Consider allowing this as an extension for GCC compatibiblity. - MultiParseScope TemplateParamScope(*this); - if (Tok.is(tok::less)) { + const bool HasExplicitTemplateParams = Tok.is(tok::less); + ParseScope TemplateParamScope(this, Scope::TemplateParamScope, + /*EnteredScope=*/HasExplicitTemplateParams); + if (HasExplicitTemplateParams) { Diag(Tok, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_lambda_template_parameter_list : diag::ext_lambda_template_parameter_list); SmallVector TemplateParams; SourceLocation LAngleLoc, RAngleLoc; - if (ParseTemplateParameters(TemplateParamScope, - CurTemplateDepthTracker.getDepth(), + if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), TemplateParams, LAngleLoc, RAngleLoc)) { Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); return ExprError(); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 847c513b5baa..16aecffa494a 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -67,7 +67,8 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( assert(Tok.isOneOf(tok::kw_export, tok::kw_template) && "Token does not start a template declaration."); - MultiParseScope TemplateParamScopes(*this); + // Enter template-parameter scope. + ParseScope TemplateParmScope(this, Scope::TemplateParamScope); // Tell the action that names should be checked in the context of // the declaration to come. @@ -115,8 +116,7 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; SmallVector TemplateParams; - if (ParseTemplateParameters(TemplateParamScopes, - CurTemplateDepthTracker.getDepth(), + if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), TemplateParams, LAngleLoc, RAngleLoc)) { // Skip until the semi-colon or a '}'. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); @@ -150,6 +150,9 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); } while (Tok.isOneOf(tok::kw_export, tok::kw_template)); + unsigned NewFlags = getCurScope()->getFlags() & ~Scope::TemplateParamScope; + ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization); + // Parse the actual template declaration. if (Tok.is(tok::kw_concept)) return ParseConceptDefinition( @@ -427,9 +430,8 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, /// /// \returns true if an error occurred, false otherwise. bool Parser::ParseTemplateParameters( - MultiParseScope &TemplateScopes, unsigned Depth, - SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, - SourceLocation &RAngleLoc) { + unsigned Depth, SmallVectorImpl &TemplateParams, + SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) { // Get the template parameter list. if (!TryConsumeToken(tok::less, LAngleLoc)) { Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; @@ -438,11 +440,8 @@ bool Parser::ParseTemplateParameters( // Try to parse the template parameter list. bool Failed = false; - // FIXME: Missing greatergreatergreater support. - if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) { - TemplateScopes.Enter(Scope::TemplateParamScope); + if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) Failed = ParseTemplateParameterList(Depth, TemplateParams); - } if (Tok.is(tok::greatergreater)) { // No diagnostic required here: a template-parameter-list can only be @@ -851,9 +850,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { SmallVector TemplateParams; SourceLocation LAngleLoc, RAngleLoc; { - MultiParseScope TemplateParmScope(*this); - if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams, - LAngleLoc, RAngleLoc)) { + ParseScope TemplateParmScope(this, Scope::TemplateParamScope); + if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc, + RAngleLoc)) { return nullptr; } } @@ -1631,7 +1630,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { Sema::ContextRAII GlobalSavedContext( Actions, Actions.Context.getTranslationUnitDecl()); - MultiParseScope Scopes(*this); + SmallVector TemplateParamScopeStack; // Get the list of DeclContexts to reenter. For inline methods, we only want // to push the DeclContext of the outermost class. This matches the way the @@ -1656,12 +1655,13 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { // Reenter template scopes from outermost to innermost. for (ContainingDC CDC : reverse(DeclContextsToReenter)) { - Scopes.Enter(Scope::TemplateParamScope); + TemplateParamScopeStack.push_back( + new ParseScope(this, Scope::TemplateParamScope)); unsigned NumParamLists = Actions.ActOnReenterTemplateScope( getCurScope(), cast(CDC.getDC())); CurTemplateDepthTracker.addDepth(NumParamLists); if (CDC.shouldPushDC()) { - Scopes.Enter(Scope::DeclScope); + TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); Actions.PushDeclContext(Actions.getCurScope(), CDC.getDC()); } } @@ -1709,6 +1709,13 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { } else Actions.ActOnFinishFunctionBody(LPT.D, nullptr); } + + // Exit scopes. + FnScope.Exit(); + SmallVectorImpl::reverse_iterator I = + TemplateParamScopeStack.rbegin(); + for (; I != TemplateParamScopeStack.rend(); ++I) + delete *I; } /// Lex a delayed template function for late parsing. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 1d046c776709..2bf16d138d5a 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1358,50 +1358,6 @@ void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) { CurContext = DC; S->setEntity(DC); - - if (!S->getParent()->isTemplateParamScope()) - return; - - // Also set the corresponding entities for all immediately-enclosing template - // parameter scopes. - // - // C++20 [temp.local]p7: - // In the definition of a member of a class template that appears outside - // of the class template definition, the name of a member of the class - // template hides the name of a template-parameter of any enclosing class - // templates (but not a template-parameter of the member if the member is a - // class or function template). - // C++20 [temp.local]p9: - // In the definition of a class template or in the definition of a member - // of such a template that appears outside of the template definition, for - // each non-dependent base class (13.8.2.1), if the name of the base class - // or the name of a member of the base class is the same as the name of a - // template-parameter, the base class name or member name hides the - // template-parameter name (6.4.10). - // - // This means that a template parameter scope should be searched immediately - // after searching the DeclContext for which it is a template parameter - // scope. For example, for - // template template template - // void N::A::B::f(...) - // we search V then B (and base classes) then U then A (and base - // classes) then T then N then ::. - unsigned ScopeDepth = getTemplateDepth(S); - for (Scope *OuterS = S->getParent(); OuterS && OuterS->isTemplateParamScope(); - OuterS = OuterS->getParent(), --ScopeDepth) { - auto *SearchDCAfterScope = DC; - for (; DC; DC = DC->getLookupParent()) { - if (auto *TD = cast(DC)->getDescribedTemplate()) { - unsigned DCDepth = TD->getTemplateParameters()->getDepth() + 1; - if (DCDepth > ScopeDepth) - continue; - if (ScopeDepth == DCDepth) - SearchDCAfterScope = DC = DC->getLookupParent(); - break; - } - } - OuterS->setLookupEntity(SearchDCAfterScope); - } } void Sema::ExitDeclaratorContext(Scope *S) { diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 5757eaf3fac0..06a4dfa0a636 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1153,14 +1153,73 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) { return false; } -/// Find the outer declaration context from this scope. This indicates the -/// context that we should search up to (exclusive) before considering the -/// parent of the specified scope. -static DeclContext *findOuterContext(Scope *S) { - for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) - if (DeclContext *DC = OuterS->getLookupEntity()) - return DC; - return nullptr; +// Find the next outer declaration context from this scope. This +// routine actually returns the semantic outer context, which may +// differ from the lexical context (encoded directly in the Scope +// stack) when we are parsing a member of a class template. In this +// case, the second element of the pair will be true, to indicate that +// name lookup should continue searching in this semantic context when +// it leaves the current template parameter scope. +static std::pair findOuterContext(Scope *S) { + DeclContext *DC = S->getEntity(); + DeclContext *Lexical = nullptr; + for (Scope *OuterS = S->getParent(); OuterS; + OuterS = OuterS->getParent()) { + if (OuterS->getEntity()) { + Lexical = OuterS->getEntity(); + break; + } + } + + // C++ [temp.local]p8: + // In the definition of a member of a class template that appears + // outside of the namespace containing the class template + // definition, the name of a template-parameter hides the name of + // a member of this namespace. + // + // Example: + // + // namespace N { + // class C { }; + // + // template class B { + // void f(T); + // }; + // } + // + // template void N::B::f(C) { + // C b; // C is the template parameter, not N::C + // } + // + // In this example, the lexical context we return is the + // TranslationUnit, while the semantic context is the namespace N. + if (!Lexical || !DC || !S->getParent() || + !S->getParent()->isTemplateParamScope()) + return std::make_pair(Lexical, false); + + // Find the outermost template parameter scope. + // For the example, this is the scope for the template parameters of + // template. + Scope *OutermostTemplateScope = S->getParent(); + while (OutermostTemplateScope->getParent() && + OutermostTemplateScope->getParent()->isTemplateParamScope()) + OutermostTemplateScope = OutermostTemplateScope->getParent(); + + // Find the namespace context in which the original scope occurs. In + // the example, this is namespace N. + DeclContext *Semantic = DC; + while (!Semantic->isFileContext()) + Semantic = Semantic->getParent(); + + // Find the declaration context just outside of the template + // parameter scope. This is the context in which the template is + // being lexically declaration (a namespace context). In the + // example, this is the global scope. + if (Lexical->isFileContext() && !Lexical->Equals(Semantic) && + Lexical->Encloses(Semantic)) + return std::make_pair(Semantic, true); + + return std::make_pair(Lexical, false); } namespace { @@ -1227,11 +1286,13 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { UnqualUsingDirectiveSet UDirs(*this); bool VisitedUsingDirectives = false; bool LeftStartingScope = false; + DeclContext *OutsideOfTemplateParamDC = nullptr; // When performing a scope lookup, we want to find local extern decls. FindLocalExternScope FindLocals(R); for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { + DeclContext *Ctx = S->getEntity(); bool SearchNamespaceScope = true; // Check whether the IdResolver has anything in this scope. for (; I != IEnd && S->isDeclScope(*I); ++I) { @@ -1263,8 +1324,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (!SearchNamespaceScope) { R.resolveKind(); if (S->isClassScope()) - if (CXXRecordDecl *Record = - dyn_cast_or_null(S->getEntity())) + if (CXXRecordDecl *Record = dyn_cast_or_null(Ctx)) R.setNamingClass(Record); return true; } @@ -1278,8 +1338,24 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { return false; } - if (DeclContext *Ctx = S->getLookupEntity()) { - DeclContext *OuterCtx = findOuterContext(S); + if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && + S->getParent() && !S->getParent()->isTemplateParamScope()) { + // We've just searched the last template parameter scope and + // found nothing, so look into the contexts between the + // lexical and semantic declaration contexts returned by + // findOuterContext(). This implements the name lookup behavior + // of C++ [temp.local]p8. + Ctx = OutsideOfTemplateParamDC; + OutsideOfTemplateParamDC = nullptr; + } + + if (Ctx) { + DeclContext *OuterCtx; + bool SearchAfterTemplateScope; + std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); + if (SearchAfterTemplateScope) + OutsideOfTemplateParamDC = OuterCtx; + for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing @@ -1404,9 +1480,25 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { return true; } - DeclContext *Ctx = S->getLookupEntity(); + DeclContext *Ctx = S->getEntity(); + if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && + S->getParent() && !S->getParent()->isTemplateParamScope()) { + // We've just searched the last template parameter scope and + // found nothing, so look into the contexts between the + // lexical and semantic declaration contexts returned by + // findOuterContext(). This implements the name lookup behavior + // of C++ [temp.local]p8. + Ctx = OutsideOfTemplateParamDC; + OutsideOfTemplateParamDC = nullptr; + } + if (Ctx) { - DeclContext *OuterCtx = findOuterContext(S); + DeclContext *OuterCtx; + bool SearchAfterTemplateScope; + std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); + if (SearchAfterTemplateScope) + OutsideOfTemplateParamDC = OuterCtx; + for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing @@ -3903,12 +3995,14 @@ private: } } - DeclContext *Entity = S->getLookupEntity(); - if (Entity) { + // FIXME: C++ [temp.local]p8 + DeclContext *Entity = nullptr; + if (S->getEntity()) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point // where we hit the context stored in the next outer scope. - DeclContext *OuterCtx = findOuterContext(S); + Entity = S->getEntity(); + DeclContext *OuterCtx = findOuterContext(S).first; // FIXME for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 6bf46f273a02..073b4e818a24 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -51,7 +51,8 @@ unsigned Sema::getTemplateDepth(Scope *S) const { // Each template parameter scope represents one level of template parameter // depth. - for (Scope *TempParamScope = S->getTemplateParamParent(); TempParamScope; + for (Scope *TempParamScope = S->getTemplateParamParent(); + TempParamScope && !Depth; TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) { ++Depth; } diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp index ff90ee82d4d4..2c762237037d 100644 --- a/clang/test/CXX/drs/dr4xx.cpp +++ b/clang/test/CXX/drs/dr4xx.cpp @@ -690,7 +690,7 @@ namespace dr457 { // dr457: yes }; } -namespace dr458 { // dr458: 11 +namespace dr458 { // dr458: no struct A { int T; int f(); @@ -706,9 +706,9 @@ namespace dr458 { // dr458: 11 int A::f() { return T; } - template // expected-note {{declared here}} + template int A::g() { - return T; // expected-error {{'T' does not refer to a value}} + return T; // FIXME: this is invalid, it finds the template parameter } template @@ -719,9 +719,9 @@ namespace dr458 { // dr458: 11 int B::g() { return T; } - template template // expected-note {{declared here}} + template template int B::h() { - return T; // expected-error {{'T' does not refer to a value}} + return T; // FIXME: this is invalid, it finds the template parameter } } diff --git a/clang/test/CXX/temp/temp.res/temp.local/p8.cpp b/clang/test/CXX/temp/temp.res/temp.local/p8.cpp index c2b4c1950ea5..fecfed06f109 100644 --- a/clang/test/CXX/temp/temp.res/temp.local/p8.cpp +++ b/clang/test/CXX/temp/temp.res/temp.local/p8.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics namespace N { enum { C }; @@ -51,63 +52,3 @@ void N::Y::f(D) { D d; } -// Ensure we properly interleave the searches within classes and template parameter lists. -namespace SearchClassBetweenTemplateParameterLists { - int AA, BB; // none of the below lookups should ever consider these - - template struct A { - using AA = void; - template struct B { - using BB = void; - void f(U); - void g(U); - void h(T); - void i(T); - template void j(V); - template void k(U); - }; - }; - - // Search order for the below is: - // 1) template parameter scope of the function itself (if any) - // 2) class of which function is a member - // 3) template parameter scope of inner class - // 4) class of which class is a member - // 5) template parameter scope of outer class - - // OK, 'AA' found in (3) - template template - void A::B::f(AA) { - AA aa; - } - - // error, 'BB' found in (2) - template template - void A::B::g(BB) { // expected-error {{does not match}} - BB bb; // expected-error {{incomplete type}} - } - - // error, 'AA' found in (4) - template template - void A::B::h(AA) { // expected-error {{does not match}} - AA aa; // expected-error {{incomplete type}} - } - - // error, 'BB' found in (2) - template template - void A::B::i(BB) { // expected-error {{does not match}} - BB bb; // expected-error {{incomplete type}} - } - - // OK, 'BB' found in (1) - template template template - void A::B::j(BB) { - BB bb; - } - - // error, 'BB' found in (2) - template template template - void A::B::k(V) { // expected-error {{does not match}} - BB bb; // expected-error {{incomplete type}} - } -} diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp index 3240d5351fc5..0f4edc4d1f34 100644 --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -601,25 +601,17 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType { #if __cplusplus > 201402L friend constexpr auto T::operator()(int) const; friend constexpr T::operator ExpectedTypeT() const noexcept; - - template - friend constexpr void U::operator()(T&) const; - // FIXME: This should not match; the return type is specified as behaving - // "as if it were a decltype-specifier denoting the return type of - // [operator()]", which is not equivalent to this alias template. - template - friend constexpr U::operator ExpectedTypeU() const noexcept; #else friend auto T::operator()(int) const; friend T::operator ExpectedTypeT() const; - - template - friend void U::operator()(T&) const; - // FIXME: This should not match, as above. - template - friend U::operator ExpectedTypeU() const; #endif + // FIXME: The first of these should match. The second should not. + template + friend void U::operator()(T&) const; // expected-error {{does not match}} + template + friend U::operator ExpectedTypeU() const; // expected-error {{does not match}} + private: int n; }; diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 22755e4b20ea..4abdc0fa2639 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -2789,7 +2789,7 @@ of class templates 458 C++11 Hiding of member template parameters by other members - Clang 11 + No 459 @@ -12307,7 +12307,7 @@ and POD class 2082 CD4 Referring to parameters in unevaluated operands of default arguments - Clang 11 + Unknown 2083 @@ -13891,7 +13891,7 @@ and POD class 2346 DRWP Local variables in default arguments - Clang 11 + Unknown 2347