Skip to content

Commit 4524db5

Browse files
committed
[WIP][Clang] Implement resolution for CWG1835
1 parent 46d8bb0 commit 4524db5

File tree

15 files changed

+128
-65
lines changed

15 files changed

+128
-65
lines changed

clang/include/clang/Sema/DeclSpec.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class CXXScopeSpec {
7575
SourceRange Range;
7676
NestedNameSpecifierLocBuilder Builder;
7777
ArrayRef<TemplateParameterList *> TemplateParamLists;
78+
NamedDecl *FoundFirstQualifierInScope;
7879

7980
public:
8081
SourceRange getRange() const { return Range; }
@@ -91,6 +92,13 @@ class CXXScopeSpec {
9192
return TemplateParamLists;
9293
}
9394

95+
void setFoundFirstQualifierInScope(NamedDecl *Found) {
96+
FoundFirstQualifierInScope = Found;
97+
}
98+
NamedDecl *getFirstQualifierFoundInScope() const {
99+
return FoundFirstQualifierInScope;
100+
}
101+
94102
/// Retrieve the representation of the nested-name-specifier.
95103
NestedNameSpecifier *getScopeRep() const {
96104
return Builder.getRepresentation();

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6891,7 +6891,7 @@ class Sema final : public SemaBase {
68916891
const TemplateArgumentListInfo *TemplateArgs);
68926892

68936893
ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
6894-
tok::TokenKind OpKind, CXXScopeSpec &SS,
6894+
bool IsArrow, CXXScopeSpec &SS,
68956895
SourceLocation TemplateKWLoc,
68966896
UnqualifiedId &Member, Decl *ObjCImpDecl);
68976897

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
720720
return nullptr;
721721
}
722722
CXXScopeSpec SS;
723-
if (ParseOptionalCXXScopeSpecifier(SS, /*ParsedType=*/nullptr,
723+
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
724724
/*ObectHasErrors=*/false,
725725
/*EnteringConttext=*/false,
726726
/*MayBePseudoDestructor=*/nullptr,

clang/lib/Parse/ParseExpr.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,6 +2254,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
22542254
}
22552255
break;
22562256
}
2257+
22572258
ParseOptionalCXXScopeSpecifier(
22582259
SS, ObjectType, LHS.get() && LHS.get()->containsErrors(),
22592260
/*EnteringContext=*/false, &MayBePseudoDestructor);
@@ -2328,10 +2329,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
23282329
}
23292330

23302331
if (!LHS.isInvalid())
2331-
LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc,
2332-
OpKind, SS, TemplateKWLoc, Name,
2333-
CurParsedObjCImpl ? CurParsedObjCImpl->Dcl
2334-
: nullptr);
2332+
LHS = Actions.ActOnMemberAccessExpr(
2333+
getCurScope(), LHS.get(), OpLoc, OpKind == tok::arrow, SS,
2334+
TemplateKWLoc, Name,
2335+
CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : nullptr);
23352336
if (!LHS.isInvalid()) {
23362337
if (Tok.is(tok::less))
23372338
checkPotentialAngleBracket(LHS);

clang/lib/Sema/SemaCXXScopeSpec.cpp

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -397,22 +397,30 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
397397
while (NNS->getPrefix())
398398
NNS = NNS->getPrefix();
399399

400-
if (NNS->getKind() != NestedNameSpecifier::Identifier)
401-
return nullptr;
402-
403-
LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(),
404-
LookupNestedNameSpecifierName);
400+
const IdentifierInfo *II = NNS->getAsIdentifier();
401+
if (!II) {
402+
if (const auto *DTST =
403+
dyn_cast_if_present<DependentTemplateSpecializationType>(
404+
NNS->getAsType()))
405+
II = DTST->getIdentifier();
406+
else
407+
return nullptr;
408+
}
409+
assert(II && "Missing first qualifier in scope");
410+
LookupResult Found(*this, II, SourceLocation(),
411+
NNS->getAsIdentifier() ? LookupNestedNameSpecifierName
412+
: LookupOrdinaryName);
405413
LookupName(Found, S);
406414
assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
407415

408416
if (!Found.isSingleResult())
409417
return nullptr;
410418

411419
NamedDecl *Result = Found.getFoundDecl();
412-
if (isAcceptableNestedNameSpecifier(Result))
413-
return Result;
420+
// if (isAcceptableNestedNameSpecifier(Result))
421+
return Result;
414422

415-
return nullptr;
423+
// return nullptr;
416424
}
417425

418426
namespace {
@@ -493,12 +501,15 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
493501
// x->B::f, and we are looking into the type of the object.
494502
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
495503
LookupCtx = computeDeclContext(ObjectType);
496-
isDependent = ObjectType->isDependentType();
497-
} else if (SS.isSet()) {
504+
isDependent = !LookupCtx && ObjectType->isDependentType();
505+
} else if (SS.isNotEmpty()) {
498506
// This nested-name-specifier occurs after another nested-name-specifier,
499507
// so look into the context associated with the prior nested-name-specifier.
500508
LookupCtx = computeDeclContext(SS, EnteringContext);
501-
isDependent = isDependentScopeSpecifier(SS);
509+
isDependent = !LookupCtx && isDependentScopeSpecifier(SS);
510+
// The declaration context must be complete.
511+
if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx))
512+
return true;
502513
Found.setContextRange(SS.getRange());
503514
}
504515

@@ -509,14 +520,28 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
509520
// expression or the declaration context associated with a prior
510521
// nested-name-specifier.
511522

512-
// The declaration context must be complete.
513-
if (!LookupCtx->isDependentContext() &&
514-
RequireCompleteDeclContext(SS, LookupCtx))
515-
return true;
516-
517523
LookupQualifiedName(Found, LookupCtx);
518524

519-
if (!ObjectType.isNull() && Found.empty()) {
525+
isDependent |= Found.wasNotFoundInCurrentInstantiation();
526+
}
527+
528+
bool LookupFirstQualifierInScope =
529+
Found.empty() && !ObjectType.isNull() && !isDependent;
530+
531+
// FIXME: We should still do the lookup if the object expression is dependent,
532+
// but instead of using them we should store them via
533+
// setFirstQualifierFoundInScope and pretend we found nothing.
534+
if (SS.isEmpty() && (ObjectType.isNull() || LookupFirstQualifierInScope)) {
535+
if (S)
536+
LookupName(Found, S);
537+
else if (LookupFirstQualifierInScope && SS.getFirstQualifierFoundInScope())
538+
Found.addDecl(SS.getFirstQualifierFoundInScope());
539+
540+
if (!ObjectType.isNull())
541+
ObjectTypeSearchedInScope = true;
542+
}
543+
#if 0
544+
if (!ObjectType.isNull() && Found.empty() && !isDependent) {
520545
// C++ [basic.lookup.classref]p4:
521546
// If the id-expression in a class member access is a qualified-id of
522547
// the form
@@ -548,6 +573,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
548573
// Perform unqualified name lookup in the current scope.
549574
LookupName(Found, S);
550575
}
576+
#endif
551577

552578
if (Found.isAmbiguous())
553579
return true;

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
10541054
if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) {
10551055
CXXScopeSpec TempSS(SS);
10561056
RetryExpr = ActOnMemberAccessExpr(
1057-
ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS,
1057+
ExtraArgs->S, RetryExpr.get(), OpLoc, /*IsArrow=*/true, TempSS,
10581058
TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl);
10591059
}
10601060
if (Trap.hasErrorOccurred())
@@ -1767,12 +1767,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
17671767
/// decl; this is an ugly hack around the fact that Objective-C
17681768
/// \@implementations aren't properly put in the context chain
17691769
ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
1770-
SourceLocation OpLoc,
1771-
tok::TokenKind OpKind,
1770+
SourceLocation OpLoc, bool IsArrow,
17721771
CXXScopeSpec &SS,
17731772
SourceLocation TemplateKWLoc,
1774-
UnqualifiedId &Id,
1775-
Decl *ObjCImpDecl) {
1773+
UnqualifiedId &Id, Decl *ObjCImpDecl) {
17761774
if (SS.isSet() && SS.isInvalid())
17771775
return ExprError();
17781776

@@ -1790,8 +1788,6 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
17901788
DecomposeUnqualifiedId(Id, TemplateArgsBuffer,
17911789
NameInfo, TemplateArgs);
17921790

1793-
bool IsArrow = (OpKind == tok::arrow);
1794-
17951791
if (getLangOpts().HLSL && IsArrow)
17961792
return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 2);
17971793

clang/lib/Sema/SemaPseudoObject.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,10 +1394,10 @@ ExprResult MSPropertyOpBuilder::buildGet() {
13941394
GetterName.setIdentifier(II, RefExpr->getMemberLoc());
13951395
CXXScopeSpec SS;
13961396
SS.Adopt(RefExpr->getQualifierLoc());
1397-
ExprResult GetterExpr =
1398-
S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
1399-
RefExpr->isArrow() ? tok::arrow : tok::period, SS,
1400-
SourceLocation(), GetterName, nullptr);
1397+
ExprResult GetterExpr = S.ActOnMemberAccessExpr(
1398+
S.getCurScope(), InstanceBase, /*OpLoc=*/SourceLocation(),
1399+
RefExpr->isArrow(), SS, /*TemplateKWLoc=*/SourceLocation(), GetterName,
1400+
/*ObjCImpDecl=*/nullptr);
14011401
if (GetterExpr.isInvalid()) {
14021402
S.Diag(RefExpr->getMemberLoc(),
14031403
diag::err_cannot_find_suitable_accessor) << 0 /* getter */
@@ -1423,10 +1423,10 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl,
14231423
SetterName.setIdentifier(II, RefExpr->getMemberLoc());
14241424
CXXScopeSpec SS;
14251425
SS.Adopt(RefExpr->getQualifierLoc());
1426-
ExprResult SetterExpr =
1427-
S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
1428-
RefExpr->isArrow() ? tok::arrow : tok::period, SS,
1429-
SourceLocation(), SetterName, nullptr);
1426+
ExprResult SetterExpr = S.ActOnMemberAccessExpr(
1427+
S.getCurScope(), InstanceBase, /*OpLoc=*/SourceLocation(),
1428+
RefExpr->isArrow(), SS, /*TemplateKWLoc=*/SourceLocation(), SetterName,
1429+
/*ObjCImpDecl=*/nullptr);
14301430
if (SetterExpr.isInvalid()) {
14311431
S.Diag(RefExpr->getMemberLoc(),
14321432
diag::err_cannot_find_suitable_accessor) << 1 /* setter */

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
214214
&AssumedTemplate,
215215
/*AllowTypoCorrection=*/!Disambiguation))
216216
return TNK_Non_template;
217+
217218
MemberOfUnknownSpecialization = R.wasNotFoundInCurrentInstantiation();
218219

219220
if (AssumedTemplate != AssumedTemplateKind::None) {
@@ -430,7 +431,6 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
430431
}
431432

432433
bool ObjectTypeSearchedInScope = false;
433-
bool AllowFunctionTemplatesInLookup = true;
434434
if (LookupCtx) {
435435
// Perform "qualified" name lookup into the declaration context we
436436
// 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,
449449
IsDependent |= Found.wasNotFoundInCurrentInstantiation();
450450
}
451451

452-
if (SS.isEmpty() && (ObjectType.isNull() || Found.empty())) {
452+
bool LookupFirstQualifierInScope =
453+
Found.getLookupKind() != LookupMemberName && Found.empty() &&
454+
!ObjectType.isNull() && !IsDependent;
455+
456+
// FIXME: We should still do the lookup if the object expression is dependent,
457+
// but instead of using them we should store them via
458+
// setFirstQualifierFoundInScope and pretend we found nothing.
459+
if (SS.isEmpty() && (ObjectType.isNull() || LookupFirstQualifierInScope)) {
453460
// C++ [basic.lookup.classref]p1:
454461
// In a class member access expression (5.2.5), if the . or -> token is
455462
// immediately followed by an identifier followed by a <, the
@@ -461,14 +468,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
461468
// template.
462469
if (S)
463470
LookupName(Found, S);
471+
else if (LookupFirstQualifierInScope && SS.getFirstQualifierFoundInScope())
472+
Found.addDecl(SS.getFirstQualifierFoundInScope());
464473

465-
if (!ObjectType.isNull()) {
466-
// FIXME: We should filter out all non-type templates here, particularly
467-
// variable templates and concepts. But the exclusion of alias templates
468-
// and template template parameters is a wording defect.
469-
AllowFunctionTemplatesInLookup = false;
474+
if (!ObjectType.isNull())
470475
ObjectTypeSearchedInScope = true;
471-
}
472476

473477
IsDependent |= Found.wasNotFoundInCurrentInstantiation();
474478
}
@@ -539,7 +543,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS,
539543

540544
NamedDecl *ExampleLookupResult =
541545
Found.empty() ? nullptr : Found.getRepresentativeDecl();
542-
FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
546+
FilterAcceptableTemplateNames(Found);
543547
if (Found.empty()) {
544548
if (IsDependent) {
545549
Found.setNotFoundInCurrentInstantiation();

clang/lib/Sema/TreeTransform.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,6 +2893,8 @@ class TreeTransform {
28932893

28942894
CXXScopeSpec SS;
28952895
SS.Adopt(QualifierLoc);
2896+
if (FirstQualifierInScope)
2897+
SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
28962898

28972899
Base = BaseResult.get();
28982900
QualType BaseType = Base->getType();
@@ -3581,6 +3583,9 @@ class TreeTransform {
35813583
CXXScopeSpec SS;
35823584
SS.Adopt(QualifierLoc);
35833585

3586+
if (FirstQualifierInScope)
3587+
SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
3588+
35843589
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
35853590
OperatorLoc, IsArrow,
35863591
SS, TemplateKWLoc,
@@ -3604,6 +3609,9 @@ class TreeTransform {
36043609
CXXScopeSpec SS;
36053610
SS.Adopt(QualifierLoc);
36063611

3612+
if (FirstQualifierInScope)
3613+
SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
3614+
36073615
return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType,
36083616
OperatorLoc, IsArrow,
36093617
SS, TemplateKWLoc,
@@ -4381,6 +4389,8 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
43814389
insertNNS(NNS);
43824390

43834391
CXXScopeSpec SS;
4392+
if (FirstQualifierInScope)
4393+
SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
43844394
while (!Qualifiers.empty()) {
43854395
NestedNameSpecifierLoc Q = Qualifiers.pop_back_val();
43864396
NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier();
@@ -5180,6 +5190,9 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
51805190
TypeLocBuilder TLB;
51815191
QualType Result;
51825192

5193+
if (UnqualLookup)
5194+
SS.setFoundFirstQualifierInScope(UnqualLookup);
5195+
51835196
if (isa<TemplateSpecializationType>(T)) {
51845197
TemplateSpecializationTypeLoc SpecTL =
51855198
TL.castAs<TemplateSpecializationTypeLoc>();
@@ -16150,6 +16163,8 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
1615016163
UnqualifiedId TemplateName;
1615116164
TemplateName.setIdentifier(&Name, NameLoc);
1615216165
Sema::TemplateTy Template;
16166+
if (FirstQualifierInScope)
16167+
SS.setFoundFirstQualifierInScope(FirstQualifierInScope);
1615316168
getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc,
1615416169
TemplateName, ParsedType::make(ObjectType),
1615516170
/*EnteringContext=*/false, Template,

clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,21 @@ namespace PR11856 {
5555

5656
template<typename T> T *end(T*);
5757

58-
class X { };
58+
struct X { };
59+
struct Y {
60+
int end;
61+
};
5962
template <typename T>
6063
void Foo2() {
6164
T it1;
62-
if (it1->end < it1->end) {
63-
}
65+
if (it1->end < it1->end) { }
6466

6567
X *x;
66-
if (x->end < 7) { // expected-error{{no member named 'end' in 'PR11856::X'}}
67-
}
68+
if (x->end < 7) { } // expected-error{{expected '>'}}
69+
// expected-note@-1{{to match this '<'}}
70+
// expected-error@-2{{expected unqualified-id}}
71+
72+
Y *y;
73+
if (y->end < 7) { }
6874
}
6975
}

clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,21 @@ namespace PR11856 {
8686

8787
template<typename T> T *end(T*);
8888

89-
class X { };
89+
struct X { };
90+
struct Y {
91+
int end;
92+
};
9093
template <typename T>
9194
void Foo2() {
9295
T it1;
93-
if (it1->end < it1->end) {
94-
}
96+
if (it1->end < it1->end) { }
9597

9698
X *x;
97-
if (x->end < 7) { // expected-error{{no member named 'end' in 'PR11856::X'}}
98-
}
99+
if (x->end < 7) { } // expected-error{{expected '>'}}
100+
// expected-note@-1{{to match this '<'}}
101+
// expected-error@-2{{expected unqualified-id}}
102+
103+
Y *y;
104+
if (y->end < 7) { }
99105
}
100106
}

0 commit comments

Comments
 (0)