https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/92957
>From 616b2cf138f9b4a1f3a23db404f77c0603ad61e1 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Tue, 21 May 2024 13:15:24 -0400 Subject: [PATCH 1/2] [WIP][Clang] Implement resolution for CWG1835 --- clang/include/clang/Sema/DeclSpec.h | 8 +++ clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Parse/ParseDeclCXX.cpp | 2 +- clang/lib/Parse/ParseExpr.cpp | 9 +-- clang/lib/Sema/SemaCXXScopeSpec.cpp | 60 +++++++++++++------ clang/lib/Sema/SemaExprMember.cpp | 10 +--- clang/lib/Sema/SemaPseudoObject.cpp | 16 ++--- clang/lib/Sema/SemaTemplate.cpp | 22 ++++--- clang/lib/Sema/TreeTransform.h | 15 +++++ .../basic.lookup.classref/p1-cxx11.cpp | 16 +++-- .../basic.lookup/basic.lookup.classref/p1.cpp | 16 +++-- .../class.derived/class.member.lookup/p8.cpp | 4 +- clang/test/CXX/drs/cwg1xx.cpp | 7 ++- clang/test/SemaCXX/static-assert-cxx17.cpp | 2 +- .../SemaTemplate/temp_arg_nontype_cxx20.cpp | 2 +- 15 files changed, 127 insertions(+), 64 deletions(-) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 23bc780e04979..c6d87ca1683a8 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; + NamedDecl *FoundFirstQualifierInScope; public: SourceRange getRange() const { return Range; } @@ -91,6 +92,13 @@ class CXXScopeSpec { return TemplateParamLists; } + void setFoundFirstQualifierInScope(NamedDecl *Found) { + FoundFirstQualifierInScope = Found; + } + NamedDecl *getFirstQualifierFoundInScope() const { + return FoundFirstQualifierInScope; + } + /// Retrieve the representation of the nested-name-specifier. NestedNameSpecifier *getScopeRep() const { return Builder.getRepresentation(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e6296868000c5..08e32d92b69a2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6920,7 +6920,7 @@ class Sema final : public SemaBase { const TemplateArgumentListInfo *TemplateArgs); ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc, - tok::TokenKind OpKind, CXXScopeSpec &SS, + bool IsArrow, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Member, Decl *ObjCImpDecl); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 9a4a777f575b2..884e7ea8ee2de 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -720,7 +720,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( return nullptr; } CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, /*ParsedType=*/nullptr, + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, /*ObectHasErrors=*/false, /*EnteringConttext=*/false, /*MayBePseudoDestructor=*/nullptr, diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index eb7447fa038e4..b3c25f88b403d 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -2254,6 +2254,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } break; } + ParseOptionalCXXScopeSpecifier( SS, ObjectType, LHS.get() && LHS.get()->containsErrors(), /*EnteringContext=*/false, &MayBePseudoDestructor); @@ -2328,10 +2329,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } if (!LHS.isInvalid()) - LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc, - OpKind, SS, TemplateKWLoc, Name, - CurParsedObjCImpl ? CurParsedObjCImpl->Dcl - : nullptr); + LHS = Actions.ActOnMemberAccessExpr( + getCurScope(), LHS.get(), OpLoc, OpKind == tok::arrow, SS, + TemplateKWLoc, Name, + CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : nullptr); if (!LHS.isInvalid()) { if (Tok.is(tok::less)) checkPotentialAngleBracket(LHS); diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index c405fbc0aa421..6efa8925d1446 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -397,11 +397,19 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { while (NNS->getPrefix()) NNS = NNS->getPrefix(); - if (NNS->getKind() != NestedNameSpecifier::Identifier) - return nullptr; - - LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(), - LookupNestedNameSpecifierName); + const IdentifierInfo *II = NNS->getAsIdentifier(); + if (!II) { + if (const auto *DTST = + dyn_cast_if_present<DependentTemplateSpecializationType>( + NNS->getAsType())) + II = DTST->getIdentifier(); + else + return nullptr; + } + assert(II && "Missing first qualifier in scope"); + LookupResult Found(*this, II, SourceLocation(), + NNS->getAsIdentifier() ? LookupNestedNameSpecifierName + : LookupOrdinaryName); LookupName(Found, S); assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet"); @@ -409,10 +417,10 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { return nullptr; NamedDecl *Result = Found.getFoundDecl(); - if (isAcceptableNestedNameSpecifier(Result)) - return Result; + // if (isAcceptableNestedNameSpecifier(Result)) + return Result; - return nullptr; + // return nullptr; } namespace { @@ -493,12 +501,15 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); - isDependent = ObjectType->isDependentType(); - } else if (SS.isSet()) { + isDependent = !LookupCtx && ObjectType->isDependentType(); + } else if (SS.isNotEmpty()) { // This nested-name-specifier occurs after another nested-name-specifier, // so look into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); - isDependent = isDependentScopeSpecifier(SS); + isDependent = !LookupCtx && isDependentScopeSpecifier(SS); + // The declaration context must be complete. + if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) + return true; Found.setContextRange(SS.getRange()); } @@ -509,14 +520,28 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, // expression or the declaration context associated with a prior // nested-name-specifier. - // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && - RequireCompleteDeclContext(SS, LookupCtx)) - return true; - LookupQualifiedName(Found, LookupCtx); - if (!ObjectType.isNull() && Found.empty()) { + isDependent |= Found.wasNotFoundInCurrentInstantiation(); + } + + bool LookupFirstQualifierInScope = + Found.empty() && !ObjectType.isNull() && !isDependent; + + // FIXME: We should still do the lookup if the object expression is dependent, + // but instead of using them we should store them via + // setFirstQualifierFoundInScope and pretend we found nothing. + if (SS.isEmpty() && (ObjectType.isNull() || LookupFirstQualifierInScope)) { + if (S) + LookupName(Found, S); + else if (LookupFirstQualifierInScope && SS.getFirstQualifierFoundInScope()) + Found.addDecl(SS.getFirstQualifierFoundInScope()); + + if (!ObjectType.isNull()) + ObjectTypeSearchedInScope = true; + } +#if 0 + if (!ObjectType.isNull() && Found.empty() && !isDependent) { // C++ [basic.lookup.classref]p4: // If the id-expression in a class member access is a qualified-id of // the form @@ -548,6 +573,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, // Perform unqualified name lookup in the current scope. LookupName(Found, S); } +#endif if (Found.isAmbiguous()) return true; diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 3ae1af26d0096..6dbb0b4c398c4 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1054,7 +1054,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) { CXXScopeSpec TempSS(SS); RetryExpr = ActOnMemberAccessExpr( - ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS, + ExtraArgs->S, RetryExpr.get(), OpLoc, /*IsArrow=*/true, TempSS, TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl); } if (Trap.hasErrorOccurred()) @@ -1768,12 +1768,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, /// decl; this is an ugly hack around the fact that Objective-C /// \@implementations aren't properly put in the context chain ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, + SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - UnqualifiedId &Id, - Decl *ObjCImpDecl) { + UnqualifiedId &Id, Decl *ObjCImpDecl) { if (SS.isSet() && SS.isInvalid()) return ExprError(); @@ -1791,8 +1789,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs); - bool IsArrow = (OpKind == tok::arrow); - if (getLangOpts().HLSL && IsArrow) return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 2); diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index fdb584ceb8105..86c303e67bc1d 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -1395,10 +1395,10 @@ ExprResult MSPropertyOpBuilder::buildGet() { GetterName.setIdentifier(II, RefExpr->getMemberLoc()); CXXScopeSpec SS; SS.Adopt(RefExpr->getQualifierLoc()); - ExprResult GetterExpr = - S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(), - RefExpr->isArrow() ? tok::arrow : tok::period, SS, - SourceLocation(), GetterName, nullptr); + ExprResult GetterExpr = S.ActOnMemberAccessExpr( + S.getCurScope(), InstanceBase, /*OpLoc=*/SourceLocation(), + RefExpr->isArrow(), SS, /*TemplateKWLoc=*/SourceLocation(), GetterName, + /*ObjCImpDecl=*/nullptr); if (GetterExpr.isInvalid()) { S.Diag(RefExpr->getMemberLoc(), diag::err_cannot_find_suitable_accessor) << 0 /* getter */ @@ -1424,10 +1424,10 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl, SetterName.setIdentifier(II, RefExpr->getMemberLoc()); CXXScopeSpec SS; SS.Adopt(RefExpr->getQualifierLoc()); - ExprResult SetterExpr = - S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(), - RefExpr->isArrow() ? tok::arrow : tok::period, SS, - SourceLocation(), SetterName, nullptr); + ExprResult SetterExpr = S.ActOnMemberAccessExpr( + S.getCurScope(), InstanceBase, /*OpLoc=*/SourceLocation(), + RefExpr->isArrow(), SS, /*TemplateKWLoc=*/SourceLocation(), SetterName, + /*ObjCImpDecl=*/nullptr); if (SetterExpr.isInvalid()) { S.Diag(RefExpr->getMemberLoc(), diag::err_cannot_find_suitable_accessor) << 1 /* setter */ diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 3e3ed77de710e..d9a2875538449 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -214,6 +214,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, &AssumedTemplate, /*AllowTypoCorrection=*/!Disambiguation)) return TNK_Non_template; + MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation(); if (AssumedTemplate != AssumedTemplateKind::None) { @@ -433,7 +434,6 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, } bool ObjectTypeSearchedInScope = false; - bool AllowFunctionTemplatesInLookup = true; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access @@ -452,7 +452,14 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } - if (SS.isEmpty() && (ObjectType.isNull() || Found.empty())) { + bool LookupFirstQualifierInScope = + Found.getLookupKind() != LookupMemberName && Found.empty() && + !ObjectType.isNull() && !IsDependent; + + // FIXME: We should still do the lookup if the object expression is dependent, + // but instead of using them we should store them via + // setFirstQualifierFoundInScope and pretend we found nothing. + if (SS.isEmpty() && (ObjectType.isNull() || LookupFirstQualifierInScope)) { // C++ [basic.lookup.classref]p1: // In a class member access expression (5.2.5), if the . or -> token is // immediately followed by an identifier followed by a <, the @@ -464,14 +471,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, // template. if (S) LookupName(Found, S); + else if (LookupFirstQualifierInScope && SS.getFirstQualifierFoundInScope()) + Found.addDecl(SS.getFirstQualifierFoundInScope()); - if (!ObjectType.isNull()) { - // FIXME: We should filter out all non-type templates here, particularly - // variable templates and concepts. But the exclusion of alias templates - // and template template parameters is a wording defect. - AllowFunctionTemplatesInLookup = false; + if (!ObjectType.isNull()) ObjectTypeSearchedInScope = true; - } IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } @@ -542,7 +546,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, NamedDecl *ExampleLookupResult = Found.empty() ? nullptr : Found.getRepresentativeDecl(); - FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup); + FilterAcceptableTemplateNames(Found); if (Found.empty()) { if (IsDependent) { Found.setNotFoundInCurrentInstantiation(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index efba99b85b0fb..c037f93bbbc3f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2894,6 +2894,8 @@ class TreeTransform { CXXScopeSpec SS; SS.Adopt(QualifierLoc); + if (FirstQualifierInScope) + SS.setFoundFirstQualifierInScope(FirstQualifierInScope); Base = BaseResult.get(); QualType BaseType = Base->getType(); @@ -3582,6 +3584,9 @@ class TreeTransform { CXXScopeSpec SS; SS.Adopt(QualifierLoc); + if (FirstQualifierInScope) + SS.setFoundFirstQualifierInScope(FirstQualifierInScope); + return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, OperatorLoc, IsArrow, SS, TemplateKWLoc, @@ -3605,6 +3610,9 @@ class TreeTransform { CXXScopeSpec SS; SS.Adopt(QualifierLoc); + if (FirstQualifierInScope) + SS.setFoundFirstQualifierInScope(FirstQualifierInScope); + return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, OperatorLoc, IsArrow, SS, TemplateKWLoc, @@ -4383,6 +4391,8 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( insertNNS(NNS); CXXScopeSpec SS; + if (FirstQualifierInScope) + SS.setFoundFirstQualifierInScope(FirstQualifierInScope); while (!Qualifiers.empty()) { NestedNameSpecifierLoc Q = Qualifiers.pop_back_val(); NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier(); @@ -5180,6 +5190,9 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope( TypeLocBuilder TLB; QualType Result; + if (UnqualLookup) + SS.setFoundFirstQualifierInScope(UnqualLookup); + if (isa<TemplateSpecializationType>(T)) { TemplateSpecializationTypeLoc SpecTL = TL.castAs<TemplateSpecializationTypeLoc>(); @@ -16173,6 +16186,8 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, UnqualifiedId TemplateName; TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; + if (FirstQualifierInScope) + SS.setFoundFirstQualifierInScope(FirstQualifierInScope); getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, TemplateName, ParsedType::make(ObjectType), /*EnteringContext=*/false, Template, diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp index 1afea99e8895c..476745537f691 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp @@ -55,15 +55,21 @@ namespace PR11856 { template<typename T> T *end(T*); - class X { }; + struct X { }; + struct Y { + int end; + }; template <typename T> void Foo2() { T it1; - if (it1->end < it1->end) { - } + if (it1->end < it1->end) { } X *x; - if (x->end < 7) { // expected-error{{no member named 'end' in 'PR11856::X'}} - } + if (x->end < 7) { } // expected-error{{expected '>'}} + // expected-note@-1{{to match this '<'}} + // expected-error@-2{{expected unqualified-id}} + + Y *y; + if (y->end < 7) { } } } diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp index e3599db18350b..cabf3f73830bc 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp @@ -86,15 +86,21 @@ namespace PR11856 { template<typename T> T *end(T*); - class X { }; + struct X { }; + struct Y { + int end; + }; template <typename T> void Foo2() { T it1; - if (it1->end < it1->end) { - } + if (it1->end < it1->end) { } X *x; - if (x->end < 7) { // expected-error{{no member named 'end' in 'PR11856::X'}} - } + if (x->end < 7) { } // expected-error{{expected '>'}} + // expected-note@-1{{to match this '<'}} + // expected-error@-2{{expected unqualified-id}} + + Y *y; + if (y->end < 7) { } } } diff --git a/clang/test/CXX/class.derived/class.member.lookup/p8.cpp b/clang/test/CXX/class.derived/class.member.lookup/p8.cpp index 78e83c0ab4566..e9a57f739cc35 100644 --- a/clang/test/CXX/class.derived/class.member.lookup/p8.cpp +++ b/clang/test/CXX/class.derived/class.member.lookup/p8.cpp @@ -47,8 +47,8 @@ template<typename T> void DerivedT<T>::Inner() { Derived1T<T>::Foo(); Derived2T<T>::Member = 42; - this->Derived1T<T>::Foo(); - this->Derived2T<T>::Member = 42; + this->Derived1T<T>::Foo(); // expected-error{{use 'template' keyword to treat 'Derived1T' as a dependent template name}} + this->Derived2T<T>::Member = 42; // expected-error{{use 'template' keyword to treat 'Derived2T' as a dependent template name}} this->Foo(); // expected-error{{non-static member 'Foo' found in multiple base-class subobjects of type 'BaseT<int>'}} } diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp index b39cc21fa4917..ea38bff0d8d34 100644 --- a/clang/test/CXX/drs/cwg1xx.cpp +++ b/clang/test/CXX/drs/cwg1xx.cpp @@ -618,7 +618,6 @@ namespace cwg141 { // cwg141: 3.1 // FIXME: we issue a useful diagnostic first, then some bogus ones. b.f<int>(); // expected-error@-1 {{no member named 'f' in 'cwg141::B'}} - // expected-error@-2 +{{}} (void)b.S<int>::n; } template<typename T> struct C { @@ -628,10 +627,12 @@ namespace cwg141 { // cwg141: 3.1 // expected-error@-1 {{use 'template' keyword to treat 'f' as a dependent template name}} } void h() { - (void)t.S<int>::n; // ok + (void)t.S<int>::n; + // expected-error@-1 {{use 'template' keyword to treat 'S' as a dependent template name}} } void i() { - (void)t.S<int>(); // ok! + (void)t.S<int>(); + // expected-error@-1 {{use 'template' keyword to treat 'S' as a dependent template name}} } }; void h() { C<B>().h(); } // ok diff --git a/clang/test/SemaCXX/static-assert-cxx17.cpp b/clang/test/SemaCXX/static-assert-cxx17.cpp index 41a7b025d0eb7..754f4ae5f1d38 100644 --- a/clang/test/SemaCXX/static-assert-cxx17.cpp +++ b/clang/test/SemaCXX/static-assert-cxx17.cpp @@ -96,7 +96,7 @@ void foo6() { // expected-error@-1{{static assertion failed due to requirement 'static_cast<const X<int> *>(nullptr)'}} static_assert((const X<typename T::T>[]){} == nullptr); // expected-error@-1{{static assertion failed due to requirement '(const X<int>[0]){} == nullptr'}} - static_assert(sizeof(X<decltype(X<typename T::T>().X<typename T::T>::~X())>) == 0); + static_assert(sizeof(X<decltype(X<typename T::T>().template X<typename T::T>::~X())>) == 0); // expected-error@-1{{static assertion failed due to requirement 'sizeof(X<void>) == 0'}} \ // expected-note@-1 {{evaluates to '8 == 0'}} static_assert(constexpr_return_false<typename T::T, typename T::U>()); diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp index ad73daa8e214c..7768d2f03ac5b 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp @@ -115,7 +115,7 @@ namespace CopyCounting { static_assert(f(X<A{}>()) == 0); template<A a> struct Y { void f(); }; - template<A a> void g(Y<a> y) { y.Y<a>::f(); } + template<A a> void g(Y<a> y) { y.template Y<a>::f(); } void h() { constexpr A a; g<a>(Y<a>{}); } template<A a> struct Z { >From 3bb8802c0c3136b144d9cf126e7eccb40dbf6b91 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Tue, 21 May 2024 15:57:06 -0400 Subject: [PATCH 2/2] [FOLD] add comment --- clang/lib/Sema/SemaCXXScopeSpec.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 6efa8925d1446..f70ba1ecfa17c 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -397,6 +397,8 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { while (NNS->getPrefix()) NNS = NNS->getPrefix(); + // FIXME: This is a rather nasty hack! Ideally we should get the results + // from LookupTemplateName/BuildCXXNestedNameSpecifier. const IdentifierInfo *II = NNS->getAsIdentifier(); if (!II) { if (const auto *DTST = _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits