[clang] [Clang] Implement resolution for CWG1835 (PR #92957)
Krystian Stasiowski via cfe-commits
cfe-commits at lists.llvm.org
Tue May 21 12:57:17 PDT 2024
https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/92957
>From 4524db5ae7f3133b51328fbabd1f6188d7d3707b Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at 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 | 9 +--
clang/test/SemaCXX/static-assert-cxx17.cpp | 2 +-
.../SemaTemplate/temp_arg_nontype_cxx20.cpp | 2 +-
15 files changed, 128 insertions(+), 65 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 5894239664c15..805d36fd10544 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6891,7 +6891,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 5eaec2b621e6f..b2fa6da002f98 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 9aa60204bf29d..05f4d756c202c 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())
@@ -1767,12 +1767,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();
@@ -1790,8 +1788,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 14ed9590afc6c..fb48a14f12eb6 100644
--- a/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/clang/lib/Sema/SemaPseudoObject.cpp
@@ -1394,10 +1394,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 */
@@ -1423,10 +1423,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 02d9b64c2b14b..a272b1ecb1f36 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) {
@@ -430,7 +431,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
@@ -449,7 +449,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
@@ -461,14 +468,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();
}
@@ -539,7 +543,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 06ed0843ef504..53ba79f86ce76 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2893,6 +2893,8 @@ class TreeTransform {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
+ if (FirstQualifierInScope)
+ SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
Base = BaseResult.get();
QualType BaseType = Base->getType();
@@ -3581,6 +3583,9 @@ class TreeTransform {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
+ if (FirstQualifierInScope)
+ SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
+
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
OperatorLoc, IsArrow,
SS, TemplateKWLoc,
@@ -3604,6 +3609,9 @@ class TreeTransform {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
+ if (FirstQualifierInScope)
+ SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
+
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
OperatorLoc, IsArrow,
SS, TemplateKWLoc,
@@ -4381,6 +4389,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>();
@@ -16150,6 +16163,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 at -1{{to match this '<'}}
+ // expected-error at -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 at -1{{to match this '<'}}
+ // expected-error at -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 a8f9b705a9866..fe20a9e5dd610 100644
--- a/clang/test/CXX/drs/cwg1xx.cpp
+++ b/clang/test/CXX/drs/cwg1xx.cpp
@@ -518,7 +518,7 @@ namespace cwg136 { // cwg136: 3.4
void q() {
j(A(), A()); // ok, has default argument
}
- extern "C" void k(int, int, int, int); // #cwg136-k
+ extern "C" void k(int, int, int, int); // #cwg136-k
namespace NSA {
struct A {
friend void cwg136::k(int, int, int, int = 0);
@@ -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 at -1 {{no member named 'f' in 'cwg141::B'}}
- // expected-error at -2 +{{}}
(void)b.S<int>::n;
}
template<typename T> struct C {
@@ -628,10 +627,12 @@ namespace cwg141 { // cwg141: 3.1
// expected-error at -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 at -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 at -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 at -1{{static assertion failed due to requirement 'static_cast<const X<int> *>(nullptr)'}}
static_assert((const X<typename T::T>[]){} == nullptr);
// expected-error at -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 at -1{{static assertion failed due to requirement 'sizeof(X<void>) == 0'}} \
// expected-note at -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 574fff484c3a7572b33645de60618d924417ca40 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at 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 =
More information about the cfe-commits
mailing list