Skip to content

Commit 1495e87

Browse files
committed
[Clang][Sema] Earlier resolution of class member access expressions naming member of the current instantiation
1 parent a642eb8 commit 1495e87

File tree

5 files changed

+93
-41
lines changed

5 files changed

+93
-41
lines changed

clang/lib/AST/Expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
103103
}
104104
} else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
105105
if (!ME->isArrow()) {
106-
assert(ME->getBase()->getType()->isRecordType());
106+
assert(ME->getBase()->getType()->getAsRecordDecl());
107107
if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
108108
if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
109109
E = ME->getBase();

clang/lib/Sema/SemaExpr.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
666666
// expressions of certain types in C++.
667667
if (getLangOpts().CPlusPlus &&
668668
(E->getType() == Context.OverloadTy ||
669-
T->isDependentType() ||
669+
// FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied
670+
// to pointer types even if the pointee type is dependent.
671+
(T->isDependentType() && !T->isPointerType()) ||
670672
T->isRecordType()))
671673
return E;
672674

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -624,8 +624,8 @@ namespace {
624624
// classes, one of its base classes.
625625
class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
626626
public:
627-
explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
628-
: Record(RTy->getDecl()) {
627+
explicit RecordMemberExprValidatorCCC(QualType RTy)
628+
: Record(RTy->getAsRecordDecl()) {
629629
// Don't add bare keywords to the consumer since they will always fail
630630
// validation by virtue of not being associated with any decls.
631631
WantTypeSpecifiers = false;
@@ -671,33 +671,55 @@ class RecordMemberExprValidatorCCC final : public CorrectionCandidateCallback {
671671

672672
static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
673673
Expr *BaseExpr,
674-
const RecordType *RTy,
674+
QualType RTy,
675675
SourceLocation OpLoc, bool IsArrow,
676676
CXXScopeSpec &SS, bool HasTemplateArgs,
677677
SourceLocation TemplateKWLoc,
678678
TypoExpr *&TE) {
679+
RecordDecl *RDecl = RTy->getAsRecordDecl();
680+
DeclContext *DC = SemaRef.computeDeclContext(RTy);
681+
// If the object expression is dependent and isn't the current instantiation,
682+
// lookup will not find anything and we must defer until instantiation.
683+
if (!DC) {
684+
R.setNotFoundInCurrentInstantiation();
685+
return false;
686+
}
687+
688+
// FIXME: Should this use Name.isDependentName()?
689+
if (DeclarationName Name = R.getLookupName();
690+
Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
691+
Name.getCXXNameType()->isDependentType()) {
692+
R.setNotFoundInCurrentInstantiation();
693+
return false;
694+
}
695+
679696
SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange();
680-
RecordDecl *RDecl = RTy->getDecl();
681-
if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) &&
682-
SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
697+
if (!RTy->isDependentType() &&
698+
!SemaRef.isThisOutsideMemberFunctionBody(RTy) &&
699+
SemaRef.RequireCompleteType(OpLoc, RTy,
683700
diag::err_typecheck_incomplete_tag,
684701
BaseRange))
685702
return true;
686703

687704
if (HasTemplateArgs || TemplateKWLoc.isValid()) {
688705
// LookupTemplateName doesn't expect these both to exist simultaneously.
689-
QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
706+
QualType ObjectType = SS.isSet() ? QualType() : RTy;
690707

691708
bool MOUS;
692709
return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS,
693710
TemplateKWLoc);
694711
}
695712

696-
DeclContext *DC = RDecl;
697713
if (SS.isSet()) {
698714
// If the member name was a qualified-id, look into the
699715
// nested-name-specifier.
700716
DC = SemaRef.computeDeclContext(SS, false);
717+
// We tried to look into a dependent context that is not the current
718+
// instantiation. Defer lookup until instantiation.
719+
if (!DC) {
720+
R.setNotFoundInCurrentInstantiation();
721+
return false;
722+
}
701723

702724
if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
703725
SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
@@ -717,7 +739,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
717739
// The record definition is complete, now look up the member.
718740
SemaRef.LookupQualifiedName(R, DC, SS);
719741

720-
if (!R.empty())
742+
if (!R.empty() || R.wasNotFoundInCurrentInstantiation())
721743
return false;
722744

723745
DeclarationName Typo = R.getLookupName();
@@ -781,13 +803,15 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
781803
const TemplateArgumentListInfo *TemplateArgs,
782804
const Scope *S,
783805
ActOnMemberAccessExtraArgs *ExtraArgs) {
806+
#if 0
784807
if (BaseType->isDependentType() ||
785808
(SS.isSet() && isDependentScopeSpecifier(SS)) ||
786809
NameInfo.getName().isDependentName())
787810
return ActOnDependentMemberExpr(Base, BaseType,
788811
IsArrow, OpLoc,
789812
SS, TemplateKWLoc, FirstQualifierInScope,
790813
NameInfo, TemplateArgs);
814+
#endif
791815

792816
LookupResult R(*this, NameInfo, LookupMemberName);
793817

@@ -797,7 +821,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
797821
QualType RecordTy = BaseType;
798822
if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType();
799823
if (LookupMemberExprInRecord(
800-
*this, R, nullptr, RecordTy->castAs<RecordType>(), OpLoc, IsArrow,
824+
*this, R, nullptr, RecordTy, OpLoc, IsArrow,
801825
SS, TemplateArgs != nullptr, TemplateKWLoc, TE))
802826
return ExprError();
803827
if (TE)
@@ -990,6 +1014,14 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
9901014
const Scope *S,
9911015
bool SuppressQualifierCheck,
9921016
ActOnMemberAccessExtraArgs *ExtraArgs) {
1017+
1018+
if (R.wasNotFoundInCurrentInstantiation() || (SS.isValid() && !computeDeclContext(SS, false))) {
1019+
return ActOnDependentMemberExpr(BaseExpr, BaseExprType,
1020+
IsArrow, OpLoc,
1021+
SS, TemplateKWLoc, FirstQualifierInScope,
1022+
R.getLookupNameInfo(), TemplateArgs);
1023+
}
1024+
9931025
QualType BaseType = BaseExprType;
9941026
if (IsArrow) {
9951027
assert(BaseType->isPointerType());
@@ -1028,11 +1060,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
10281060
// Rederive where we looked up.
10291061
DeclContext *DC = (SS.isSet()
10301062
? computeDeclContext(SS, false)
1031-
: BaseType->castAs<RecordType>()->getDecl());
1063+
: BaseType->getAsRecordDecl());
10321064

10331065
if (ExtraArgs) {
10341066
ExprResult RetryExpr;
1035-
if (!IsArrow && BaseExpr) {
1067+
if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) {
10361068
SFINAETrap Trap(*this, true);
10371069
ParsedType ObjectType;
10381070
bool MayBePseudoDestructor = false;
@@ -1055,9 +1087,16 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
10551087
}
10561088
}
10571089

1058-
Diag(R.getNameLoc(), diag::err_no_member)
1059-
<< MemberName << DC
1060-
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
1090+
if(DC) {
1091+
Diag(R.getNameLoc(), diag::err_no_member)
1092+
<< MemberName << DC
1093+
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
1094+
} else {
1095+
// FIXME: Is this needed?
1096+
Diag(R.getNameLoc(), diag::err_no_member)
1097+
<< MemberName << BaseExprType
1098+
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
1099+
}
10611100
return ExprError();
10621101
}
10631102

@@ -1287,7 +1326,10 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
12871326
return ExprError();
12881327

12891328
QualType BaseType = BaseExpr.get()->getType();
1329+
1330+
#if 0
12901331
assert(!BaseType->isDependentType());
1332+
#endif
12911333

12921334
DeclarationName MemberName = R.getLookupName();
12931335
SourceLocation MemberLoc = R.getNameLoc();
@@ -1299,29 +1341,32 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
12991341
if (IsArrow) {
13001342
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
13011343
BaseType = Ptr->getPointeeType();
1302-
else if (const ObjCObjectPointerType *Ptr
1344+
else if (!BaseType->isDependentType()) {
1345+
if (const ObjCObjectPointerType *Ptr
13031346
= BaseType->getAs<ObjCObjectPointerType>())
13041347
BaseType = Ptr->getPointeeType();
1305-
else if (BaseType->isRecordType()) {
1306-
// Recover from arrow accesses to records, e.g.:
1307-
// struct MyRecord foo;
1308-
// foo->bar
1309-
// This is actually well-formed in C++ if MyRecord has an
1310-
// overloaded operator->, but that should have been dealt with
1311-
// by now--or a diagnostic message already issued if a problem
1312-
// was encountered while looking for the overloaded operator->.
1313-
if (!S.getLangOpts().CPlusPlus) {
1314-
S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
1315-
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
1316-
<< FixItHint::CreateReplacement(OpLoc, ".");
1348+
else if (BaseType->isRecordType()) {
1349+
// Recover from arrow accesses to records, e.g.:
1350+
// struct MyRecord foo;
1351+
// foo->bar
1352+
// This is actually well-formed in C++ if MyRecord has an
1353+
// overloaded operator->, but that should have been dealt with
1354+
// by now--or a diagnostic message already issued if a problem
1355+
// was encountered while looking for the overloaded operator->.
1356+
if (!S.getLangOpts().CPlusPlus) {
1357+
S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
1358+
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
1359+
<< FixItHint::CreateReplacement(OpLoc, ".");
1360+
}
1361+
IsArrow = false;
1362+
} else if (BaseType->isFunctionType()) {
1363+
goto fail;
1364+
} else {
1365+
S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
1366+
<< BaseType << BaseExpr.get()->getSourceRange();
1367+
return ExprError();
13171368
}
1318-
IsArrow = false;
1319-
} else if (BaseType->isFunctionType()) {
1320-
goto fail;
1321-
} else {
1322-
S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
1323-
<< BaseType << BaseExpr.get()->getSourceRange();
1324-
return ExprError();
1369+
13251370
}
13261371
}
13271372

@@ -1341,9 +1386,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
13411386
}
13421387

13431388
// Handle field access to simple records.
1344-
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
1389+
if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) {
13451390
TypoExpr *TE = nullptr;
1346-
if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS,
1391+
if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow, SS,
13471392
HasTemplateArgs, TemplateKWLoc, TE))
13481393
return ExprError();
13491394

@@ -1781,12 +1826,14 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
17811826
if (Result.isInvalid()) return ExprError();
17821827
Base = Result.get();
17831828

1829+
#if 0
17841830
if (Base->getType()->isDependentType() || Name.isDependentName() ||
17851831
isDependentScopeSpecifier(SS)) {
17861832
return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS,
17871833
TemplateKWLoc, FirstQualifierInScope,
17881834
NameInfo, TemplateArgs);
17891835
}
1836+
#endif
17901837

17911838
ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl};
17921839
ExprResult Res = BuildMemberReferenceExpr(

clang/lib/Sema/SemaOverload.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5744,7 +5744,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
57445744
return ICS;
57455745
}
57465746

5747+
// FIXME: Should this check getAsRecordDecl instead?
5748+
#if 0
57475749
assert(FromType->isRecordType());
5750+
#endif
57485751

57495752
QualType ClassType = S.Context.getTypeDeclType(ActingContext);
57505753
// C++98 [class.dtor]p2:

clang/test/SemaTemplate/dependent-names.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
1+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
22

33
typedef double A;
44
template<typename T> class B {
@@ -334,7 +334,7 @@ int arr[sizeof(Sub)];
334334
namespace PR11421 {
335335
template < unsigned > struct X {
336336
static const unsigned dimension = 3;
337-
template<unsigned dim=dimension>
337+
template<unsigned dim=dimension>
338338
struct Y: Y<dim> { }; // expected-error{{circular inheritance between 'Y<dim>' and 'Y<dim>'}}
339339
};
340340
typedef X<3> X3;

0 commit comments

Comments
 (0)