Skip to content

Commit 1bbad59

Browse files
committed
For DR712: store on a MemberExpr whether it constitutes an odr-use.
llvm-svn: 363087
1 parent 715f7a1 commit 1bbad59

File tree

13 files changed

+99
-49
lines changed

13 files changed

+99
-49
lines changed

clang/include/clang/AST/Expr.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2780,7 +2780,8 @@ class MemberExpr final
27802780

27812781
MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
27822782
ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo,
2783-
QualType T, ExprValueKind VK, ExprObjectKind OK);
2783+
QualType T, ExprValueKind VK, ExprObjectKind OK,
2784+
NonOdrUseReason NOUR);
27842785
MemberExpr(EmptyShell Empty)
27852786
: Expr(MemberExprClass, Empty), Base(), MemberDecl() {}
27862787

@@ -2792,18 +2793,19 @@ class MemberExpr final
27922793
DeclAccessPair FoundDecl,
27932794
DeclarationNameInfo MemberNameInfo,
27942795
const TemplateArgumentListInfo *TemplateArgs,
2795-
QualType T, ExprValueKind VK, ExprObjectKind OK);
2796+
QualType T, ExprValueKind VK, ExprObjectKind OK,
2797+
NonOdrUseReason NOUR);
27962798

27972799
/// Create an implicit MemberExpr, with no location, qualifier, template
2798-
/// arguments, and so on.
2800+
/// arguments, and so on. Suitable only for non-static member access.
27992801
static MemberExpr *CreateImplicit(const ASTContext &C, Expr *Base,
28002802
bool IsArrow, ValueDecl *MemberDecl,
28012803
QualType T, ExprValueKind VK,
28022804
ExprObjectKind OK) {
28032805
return Create(C, Base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
28042806
SourceLocation(), MemberDecl,
28052807
DeclAccessPair::make(MemberDecl, MemberDecl->getAccess()),
2806-
DeclarationNameInfo(), nullptr, T, VK, OK);
2808+
DeclarationNameInfo(), nullptr, T, VK, OK, NOUR_None);
28072809
}
28082810

28092811
static MemberExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier,
@@ -2957,6 +2959,12 @@ class MemberExpr final
29572959
return LO.AppleKext || !hasQualifier();
29582960
}
29592961

2962+
/// Is this expression a non-odr-use reference, and if so, why?
2963+
/// This is only meaningful if the named member is a static member.
2964+
NonOdrUseReason isNonOdrUse() const {
2965+
return static_cast<NonOdrUseReason>(MemberExprBits.NonOdrUseReason);
2966+
}
2967+
29602968
static bool classof(const Stmt *T) {
29612969
return T->getStmtClass() == MemberExprClass;
29622970
}

clang/include/clang/AST/Stmt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,11 @@ class alignas(void *) Stmt {
479479
/// was resolved from an overloaded set having size greater than 1.
480480
unsigned HadMultipleCandidates : 1;
481481

482+
/// Value of type NonOdrUseReason indicating why this MemberExpr does
483+
/// not constitute an odr-use of the named declaration. Meaningful only
484+
/// when naming a static member.
485+
unsigned NonOdrUseReason : 2;
486+
482487
/// This is the location of the -> or . in the expression.
483488
SourceLocation OperatorLoc;
484489
};

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4305,6 +4305,10 @@ class Sema {
43054305
bool isAddressOfOperand,
43064306
const TemplateArgumentListInfo *TemplateArgs);
43074307

4308+
/// If \p D cannot be odr-used in the current expression evaluation context,
4309+
/// return a reason explaining why. Otherwise, return NOUR_None.
4310+
NonOdrUseReason getNonOdrUseReasonInCurrentContext(ValueDecl *D);
4311+
43084312
DeclRefExpr *BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
43094313
SourceLocation Loc,
43104314
const CXXScopeSpec *SS = nullptr);

clang/lib/AST/ASTImporter.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7113,10 +7113,11 @@ ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
71137113
ResInfo = &ToTAInfo;
71147114
}
71157115

7116-
return MemberExpr::Create(
7117-
Importer.getToContext(), ToBase, E->isArrow(), ToOperatorLoc,
7118-
ToQualifierLoc, ToTemplateKeywordLoc, ToMemberDecl, ToFoundDecl,
7119-
ToMemberNameInfo, ResInfo, ToType, E->getValueKind(), E->getObjectKind());
7116+
return MemberExpr::Create(Importer.getToContext(), ToBase, E->isArrow(),
7117+
ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc,
7118+
ToMemberDecl, ToFoundDecl, ToMemberNameInfo,
7119+
ResInfo, ToType, E->getValueKind(),
7120+
E->getObjectKind(), E->isNonOdrUse());
71207121
}
71217122

71227123
ExpectedStmt

clang/lib/AST/Expr.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,7 +1541,8 @@ UnaryExprOrTypeTraitExpr::UnaryExprOrTypeTraitExpr(
15411541
MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
15421542
ValueDecl *MemberDecl,
15431543
const DeclarationNameInfo &NameInfo, QualType T,
1544-
ExprValueKind VK, ExprObjectKind OK)
1544+
ExprValueKind VK, ExprObjectKind OK,
1545+
NonOdrUseReason NOUR)
15451546
: Expr(MemberExprClass, T, VK, OK, Base->isTypeDependent(),
15461547
Base->isValueDependent(), Base->isInstantiationDependent(),
15471548
Base->containsUnexpandedParameterPack()),
@@ -1553,6 +1554,7 @@ MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
15531554
MemberExprBits.HasQualifierOrFoundDecl = false;
15541555
MemberExprBits.HasTemplateKWAndArgsInfo = false;
15551556
MemberExprBits.HadMultipleCandidates = false;
1557+
MemberExprBits.NonOdrUseReason = NOUR;
15561558
MemberExprBits.OperatorLoc = OperatorLoc;
15571559
}
15581560

@@ -1561,7 +1563,7 @@ MemberExpr *MemberExpr::Create(
15611563
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
15621564
ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
15631565
DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs,
1564-
QualType T, ExprValueKind VK, ExprObjectKind OK) {
1566+
QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) {
15651567
bool HasQualOrFound = QualifierLoc || FoundDecl.getDecl() != MemberDecl ||
15661568
FoundDecl.getAccess() != MemberDecl->getAccess();
15671569
bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
@@ -1572,8 +1574,8 @@ MemberExpr *MemberExpr::Create(
15721574
TemplateArgs ? TemplateArgs->size() : 0);
15731575

15741576
void *Mem = C.Allocate(Size, alignof(MemberExpr));
1575-
MemberExpr *E = new (Mem)
1576-
MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl, NameInfo, T, VK, OK);
1577+
MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
1578+
NameInfo, T, VK, OK, NOUR);
15771579

15781580
if (HasQualOrFound) {
15791581
// FIXME: Wrong. We should be looking at the member declaration we found.

clang/lib/AST/JSONNodeDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,12 @@ void JSONNodeDumper::VisitMemberExpr(const MemberExpr *ME) {
843843
JOS.attribute("name", VD && VD->getDeclName() ? VD->getNameAsString() : "");
844844
JOS.attribute("isArrow", ME->isArrow());
845845
JOS.attribute("referencedMemberDecl", createPointerRepresentation(VD));
846+
switch (ME->isNonOdrUse()) {
847+
case NOUR_None: break;
848+
case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break;
849+
case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break;
850+
case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break;
851+
}
846852
}
847853

848854
void JSONNodeDumper::VisitCXXNewExpr(const CXXNewExpr *NE) {

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,12 @@ void TextNodeDumper::VisitUnaryExprOrTypeTraitExpr(
825825
void TextNodeDumper::VisitMemberExpr(const MemberExpr *Node) {
826826
OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl();
827827
dumpPointer(Node->getMemberDecl());
828+
switch (Node->isNonOdrUse()) {
829+
case NOUR_None: break;
830+
case NOUR_Unevaluated: OS << " non_odr_use_unevaluated"; break;
831+
case NOUR_Constant: OS << " non_odr_use_constant"; break;
832+
case NOUR_Discarded: OS << " non_odr_use_discarded"; break;
833+
}
828834
}
829835

830836
void TextNodeDumper::VisitExtVectorElementExpr(

clang/lib/Analysis/BodyFarm.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
220220
SourceLocation(), MemberDecl, FoundDecl,
221221
DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),
222222
/* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind,
223-
OK_Ordinary);
223+
OK_Ordinary, NOUR_None);
224224
}
225225

226226
ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,17 +1492,11 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
14921492
static DeclRefExpr *tryToConvertMemberExprToDeclRefExpr(CodeGenFunction &CGF,
14931493
const MemberExpr *ME) {
14941494
if (auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
1495-
// FIXME: Copy this from the MemberExpr once we store it there.
1496-
NonOdrUseReason NOUR = NOUR_None;
1497-
if (VD->getType()->isReferenceType() &&
1498-
VD->isUsableInConstantExpressions(CGF.getContext()))
1499-
NOUR = NOUR_Constant;
1500-
15011495
// Try to emit static variable member expressions as DREs.
15021496
return DeclRefExpr::Create(
15031497
CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
15041498
/*RefersToEnclosingVariableOrCapture=*/false, ME->getExprLoc(),
1505-
ME->getType(), ME->getValueKind(), nullptr, nullptr, NOUR);
1499+
ME->getType(), ME->getValueKind(), nullptr, nullptr, ME->isNonOdrUse());
15061500
}
15071501
return nullptr;
15081502
}

clang/lib/Sema/SemaExpr.cpp

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,6 +1785,27 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
17851785
TemplateArgs);
17861786
}
17871787

1788+
NonOdrUseReason Sema::getNonOdrUseReasonInCurrentContext(ValueDecl *D) {
1789+
// A declaration named in an unevaluated operand never constitutes an odr-use.
1790+
if (isUnevaluatedContext())
1791+
return NOUR_Unevaluated;
1792+
1793+
// C++2a [basic.def.odr]p4:
1794+
// A variable x whose name appears as a potentially-evaluated expression e
1795+
// is odr-used by e unless [...] x is a reference that is usable in
1796+
// constant expressions.
1797+
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
1798+
if (VD->getType()->isReferenceType() &&
1799+
!(getLangOpts().OpenMP && isOpenMPCapturedDecl(D)) &&
1800+
VD->isUsableInConstantExpressions(Context))
1801+
return NOUR_Constant;
1802+
}
1803+
1804+
// All remaining non-variable cases constitute an odr-use. For variables, we
1805+
// need to wait and see how the expression is used.
1806+
return NOUR_None;
1807+
}
1808+
17881809
/// BuildDeclRefExpr - Build an expression that references a
17891810
/// declaration that does not require a closure capture.
17901811
DeclRefExpr *
@@ -1797,19 +1818,9 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
17971818
isa<VarDecl>(D) &&
17981819
NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
17991820

1800-
NonOdrUseReason NOUR;
1801-
if (isUnevaluatedContext())
1802-
NOUR = NOUR_Unevaluated;
1803-
else if (isa<VarDecl>(D) && D->getType()->isReferenceType() &&
1804-
!(getLangOpts().OpenMP && isOpenMPCapturedDecl(D)) &&
1805-
cast<VarDecl>(D)->isUsableInConstantExpressions(Context))
1806-
NOUR = NOUR_Constant;
1807-
else
1808-
NOUR = NOUR_None;
1809-
1810-
DeclRefExpr *E = DeclRefExpr::Create(Context, NNS, TemplateKWLoc, D,
1811-
RefersToCapturedVariable, NameInfo, Ty,
1812-
VK, FoundD, TemplateArgs, NOUR);
1821+
DeclRefExpr *E = DeclRefExpr::Create(
1822+
Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,
1823+
VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D));
18131824
MarkDeclRefReferenced(E);
18141825

18151826
if (getLangOpts().ObjCWeak && isa<VarDecl>(D) &&
@@ -15924,13 +15935,21 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
1592415935
// FIXME: Recurse to the left-hand side.
1592515936
break;
1592615937

15927-
// FIXME: Track whether a MemberExpr constitutes an odr-use; bail out here
15928-
// if we've already marked it.
15929-
if (IsPotentialResultOdrUsed(ME->getMemberDecl()))
15938+
if (ME->isNonOdrUse() || IsPotentialResultOdrUsed(ME->getMemberDecl()))
1593015939
break;
1593115940

15932-
// FIXME: Rebuild as a non-odr-use MemberExpr.
15941+
// Rebuild as a non-odr-use MemberExpr.
1593315942
MarkNotOdrUsed();
15943+
TemplateArgumentListInfo TemplateArgStorage, *TemplateArgs = nullptr;
15944+
if (ME->hasExplicitTemplateArgs()) {
15945+
ME->copyTemplateArgumentsInto(TemplateArgStorage);
15946+
TemplateArgs = &TemplateArgStorage;
15947+
}
15948+
return MemberExpr::Create(
15949+
S.Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),
15950+
ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(),
15951+
ME->getFoundDecl(), ME->getMemberNameInfo(), TemplateArgs,
15952+
ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR);
1593415953
return ExprEmpty();
1593515954
}
1593615955

@@ -16193,11 +16212,19 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
1619316212
// Sema::CheckLValueToRValueConversionOperand deals with the second part.
1619416213
// FIXME: To get the third bullet right, we need to delay this even for
1619516214
// variables that are not usable in constant expressions.
16196-
DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E);
16215+
16216+
// If we already know this isn't an odr-use, there's nothing more to do.
16217+
if (DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
16218+
if (DRE->isNonOdrUse())
16219+
return;
16220+
if (MemberExpr *ME = dyn_cast_or_null<MemberExpr>(E))
16221+
if (ME->isNonOdrUse())
16222+
return;
16223+
1619716224
switch (OdrUse) {
1619816225
case OdrUseContext::None:
16199-
assert((!DRE || DRE->isNonOdrUse() == NOUR_Unevaluated) &&
16200-
"missing non-odr-use marking for unevaluated operand");
16226+
assert((!E || isa<FunctionParmPackExpr>(E)) &&
16227+
"missing non-odr-use marking for unevaluated decl ref");
1620116228
break;
1620216229

1620316230
case OdrUseContext::FormallyOdrUsed:
@@ -16206,9 +16233,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
1620616233
break;
1620716234

1620816235
case OdrUseContext::Used:
16209-
// If we already know this isn't an odr-use, there's nothing more to do.
16210-
if (DRE && DRE->isNonOdrUse())
16211-
break;
1621216236
// If we might later find that this expression isn't actually an odr-use,
1621316237
// delay the marking.
1621416238
if (E && Var->isUsableInConstantExpressions(SemaRef.Context))
@@ -16218,9 +16242,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
1621816242
break;
1621916243

1622016244
case OdrUseContext::Dependent:
16221-
// If we already know this isn't an odr-use, there's nothing more to do.
16222-
if (DRE && DRE->isNonOdrUse())
16223-
break;
1622416245
// If this is a dependent context, we don't need to mark variables as
1622516246
// odr-used, but we may still need to track them for lambda capture.
1622616247
// FIXME: Do we also need to do this inside dependent typeid expressions

0 commit comments

Comments
 (0)