Skip to content

Commit 715f7a1

Browse files
committed
For DR712: store on a DeclRefExpr whether it constitutes an odr-use.
Begin restructuring to support the forms of non-odr-use reference permitted by DR712. llvm-svn: 363086
1 parent ef2d6d9 commit 715f7a1

28 files changed

+484
-168
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1226,10 +1226,15 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
12261226

12271227
void setInit(Expr *I);
12281228

1229-
/// Determine whether this variable's value can be used in a
1229+
/// Determine whether this variable's value might be usable in a
12301230
/// constant expression, according to the relevant language standard.
12311231
/// This only checks properties of the declaration, and does not check
12321232
/// whether the initializer is in fact a constant expression.
1233+
bool mightBeUsableInConstantExpressions(ASTContext &C) const;
1234+
1235+
/// Determine whether this variable's value can be used in a
1236+
/// constant expression, according to the relevant language standard,
1237+
/// including checking whether it was initialized by a constant expression.
12331238
bool isUsableInConstantExpressions(ASTContext &C) const;
12341239

12351240
EvaluatedStmt *ensureEvaluatedStmt() const;

clang/include/clang/AST/Expr.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,7 +1115,7 @@ class DeclRefExpr final
11151115
bool RefersToEnlosingVariableOrCapture,
11161116
const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
11171117
const TemplateArgumentListInfo *TemplateArgs, QualType T,
1118-
ExprValueKind VK);
1118+
ExprValueKind VK, NonOdrUseReason NOUR);
11191119

11201120
/// Construct an empty declaration reference expression.
11211121
explicit DeclRefExpr(EmptyShell Empty) : Expr(DeclRefExprClass, Empty) {}
@@ -1128,22 +1128,25 @@ class DeclRefExpr final
11281128
DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
11291129
bool RefersToEnclosingVariableOrCapture, QualType T,
11301130
ExprValueKind VK, SourceLocation L,
1131-
const DeclarationNameLoc &LocInfo = DeclarationNameLoc());
1131+
const DeclarationNameLoc &LocInfo = DeclarationNameLoc(),
1132+
NonOdrUseReason NOUR = NOUR_None);
11321133

11331134
static DeclRefExpr *
11341135
Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc,
11351136
SourceLocation TemplateKWLoc, ValueDecl *D,
11361137
bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc,
11371138
QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr,
1138-
const TemplateArgumentListInfo *TemplateArgs = nullptr);
1139+
const TemplateArgumentListInfo *TemplateArgs = nullptr,
1140+
NonOdrUseReason NOUR = NOUR_None);
11391141

11401142
static DeclRefExpr *
11411143
Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc,
11421144
SourceLocation TemplateKWLoc, ValueDecl *D,
11431145
bool RefersToEnclosingVariableOrCapture,
11441146
const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK,
11451147
NamedDecl *FoundD = nullptr,
1146-
const TemplateArgumentListInfo *TemplateArgs = nullptr);
1148+
const TemplateArgumentListInfo *TemplateArgs = nullptr,
1149+
NonOdrUseReason NOUR = NOUR_None);
11471150

11481151
/// Construct an empty declaration reference expression.
11491152
static DeclRefExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier,
@@ -1274,6 +1277,11 @@ class DeclRefExpr final
12741277
DeclRefExprBits.HadMultipleCandidates = V;
12751278
}
12761279

1280+
/// Is this expression a non-odr-use reference, and if so, why?
1281+
NonOdrUseReason isNonOdrUse() const {
1282+
return static_cast<NonOdrUseReason>(DeclRefExprBits.NonOdrUseReason);
1283+
}
1284+
12771285
/// Does this DeclRefExpr refer to an enclosing local or a captured
12781286
/// variable?
12791287
bool refersToEnclosingVariableOrCapture() const {

clang/include/clang/AST/Stmt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ class alignas(void *) Stmt {
351351
unsigned HasFoundDecl : 1;
352352
unsigned HadMultipleCandidates : 1;
353353
unsigned RefersToEnclosingVariableOrCapture : 1;
354+
unsigned NonOdrUseReason : 2;
354355

355356
/// The location of the declaration name itself.
356357
SourceLocation Loc;

clang/include/clang/Basic/Specifiers.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,20 @@ namespace clang {
148148
OK_ObjCSubscript
149149
};
150150

151+
/// The reason why a DeclRefExpr does not constitute an odr-use.
152+
enum NonOdrUseReason {
153+
/// This is an odr-use.
154+
NOUR_None = 0,
155+
/// This name appears in an unevaluated operand.
156+
NOUR_Unevaluated,
157+
/// This name appears as a potential result of an lvalue-to-rvalue
158+
/// conversion that is a constant expression.
159+
NOUR_Constant,
160+
/// This name appears as a potential result of a discarded value
161+
/// expression.
162+
NOUR_Discarded,
163+
};
164+
151165
/// Describes the kind of template specialization that a
152166
/// particular template specialization declaration represents.
153167
enum TemplateSpecializationKind {

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4185,7 +4185,7 @@ class Sema {
41854185
void MarkCaptureUsedInEnclosingContext(VarDecl *Capture, SourceLocation Loc,
41864186
unsigned CapturingScopeIndex);
41874187

4188-
void UpdateMarkingForLValueToRValue(Expr *E);
4188+
ExprResult CheckLValueToRValueConversionOperand(Expr *E);
41894189
void CleanupVarDeclMarking();
41904190

41914191
enum TryCaptureKind {

clang/include/clang/Sema/SemaInternal.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,6 @@ FTIHasNonVoidParameters(const DeclaratorChunk::FunctionTypeInfo &FTI) {
3838
return FTI.NumParams && !FTIHasSingleVoidParameter(FTI);
3939
}
4040

41-
// This requires the variable to be non-dependent and the initializer
42-
// to not be value dependent.
43-
inline bool IsVariableAConstantExpression(VarDecl *Var, ASTContext &Context) {
44-
const VarDecl *DefVD = nullptr;
45-
return !isa<ParmVarDecl>(Var) &&
46-
Var->isUsableInConstantExpressions(Context) &&
47-
Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE();
48-
}
49-
5041
// Helper function to check whether D's attributes match current CUDA mode.
5142
// Decls with mismatched attributes and related diagnostics may have to be
5243
// ignored during this CUDA compilation pass.

clang/lib/AST/ASTImporter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6189,7 +6189,7 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
61896189
auto *ToE = DeclRefExpr::Create(
61906190
Importer.getToContext(), ToQualifierLoc, ToTemplateKeywordLoc, ToDecl,
61916191
E->refersToEnclosingVariableOrCapture(), ToLocation, ToType,
6192-
E->getValueKind(), ToFoundD, ToResInfo);
6192+
E->getValueKind(), ToFoundD, ToResInfo, E->isNonOdrUse());
61936193
if (E->hadMultipleCandidates())
61946194
ToE->setHadMultipleCandidates(true);
61956195
return ToE;

clang/lib/AST/Decl.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2245,12 +2245,16 @@ void VarDecl::setInit(Expr *I) {
22452245
Init = I;
22462246
}
22472247

2248-
bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
2248+
bool VarDecl::mightBeUsableInConstantExpressions(ASTContext &C) const {
22492249
const LangOptions &Lang = C.getLangOpts();
22502250

22512251
if (!Lang.CPlusPlus)
22522252
return false;
22532253

2254+
// Function parameters are never usable in constant expressions.
2255+
if (isa<ParmVarDecl>(this))
2256+
return false;
2257+
22542258
// In C++11, any variable of reference type can be used in a constant
22552259
// expression if it is initialized by a constant expression.
22562260
if (Lang.CPlusPlus11 && getType()->isReferenceType())
@@ -2272,6 +2276,22 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
22722276
return Lang.CPlusPlus11 && isConstexpr();
22732277
}
22742278

2279+
bool VarDecl::isUsableInConstantExpressions(ASTContext &Context) const {
2280+
// C++2a [expr.const]p3:
2281+
// A variable is usable in constant expressions after its initializing
2282+
// declaration is encountered...
2283+
const VarDecl *DefVD = nullptr;
2284+
const Expr *Init = getAnyInitializer(DefVD);
2285+
if (!Init || Init->isValueDependent())
2286+
return false;
2287+
// ... if it is a constexpr variable, or it is of reference type or of
2288+
// const-qualified integral or enumeration type, ...
2289+
if (!DefVD->mightBeUsableInConstantExpressions(Context))
2290+
return false;
2291+
// ... and its initializer is a constant initializer.
2292+
return DefVD->checkInitIsICE();
2293+
}
2294+
22752295
/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
22762296
/// form, which contains extra information on the evaluated value of the
22772297
/// initializer.

clang/lib/AST/Expr.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,8 @@ void DeclRefExpr::computeDependence(const ASTContext &Ctx) {
344344
DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
345345
bool RefersToEnclosingVariableOrCapture, QualType T,
346346
ExprValueKind VK, SourceLocation L,
347-
const DeclarationNameLoc &LocInfo)
347+
const DeclarationNameLoc &LocInfo,
348+
NonOdrUseReason NOUR)
348349
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
349350
D(D), DNLoc(LocInfo) {
350351
DeclRefExprBits.HasQualifier = false;
@@ -353,6 +354,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
353354
DeclRefExprBits.HadMultipleCandidates = false;
354355
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
355356
RefersToEnclosingVariableOrCapture;
357+
DeclRefExprBits.NonOdrUseReason = NOUR;
356358
DeclRefExprBits.Loc = L;
357359
computeDependence(Ctx);
358360
}
@@ -363,7 +365,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
363365
bool RefersToEnclosingVariableOrCapture,
364366
const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
365367
const TemplateArgumentListInfo *TemplateArgs,
366-
QualType T, ExprValueKind VK)
368+
QualType T, ExprValueKind VK, NonOdrUseReason NOUR)
367369
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
368370
D(D), DNLoc(NameInfo.getInfo()) {
369371
DeclRefExprBits.Loc = NameInfo.getLoc();
@@ -384,6 +386,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
384386
= (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0;
385387
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
386388
RefersToEnclosingVariableOrCapture;
389+
DeclRefExprBits.NonOdrUseReason = NOUR;
387390
if (TemplateArgs) {
388391
bool Dependent = false;
389392
bool InstantiationDependent = false;
@@ -405,30 +408,27 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
405408

406409
DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
407410
NestedNameSpecifierLoc QualifierLoc,
408-
SourceLocation TemplateKWLoc,
409-
ValueDecl *D,
411+
SourceLocation TemplateKWLoc, ValueDecl *D,
410412
bool RefersToEnclosingVariableOrCapture,
411-
SourceLocation NameLoc,
412-
QualType T,
413-
ExprValueKind VK,
414-
NamedDecl *FoundD,
415-
const TemplateArgumentListInfo *TemplateArgs) {
413+
SourceLocation NameLoc, QualType T,
414+
ExprValueKind VK, NamedDecl *FoundD,
415+
const TemplateArgumentListInfo *TemplateArgs,
416+
NonOdrUseReason NOUR) {
416417
return Create(Context, QualifierLoc, TemplateKWLoc, D,
417418
RefersToEnclosingVariableOrCapture,
418419
DeclarationNameInfo(D->getDeclName(), NameLoc),
419-
T, VK, FoundD, TemplateArgs);
420+
T, VK, FoundD, TemplateArgs, NOUR);
420421
}
421422

422423
DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
423424
NestedNameSpecifierLoc QualifierLoc,
424-
SourceLocation TemplateKWLoc,
425-
ValueDecl *D,
425+
SourceLocation TemplateKWLoc, ValueDecl *D,
426426
bool RefersToEnclosingVariableOrCapture,
427427
const DeclarationNameInfo &NameInfo,
428-
QualType T,
429-
ExprValueKind VK,
428+
QualType T, ExprValueKind VK,
430429
NamedDecl *FoundD,
431-
const TemplateArgumentListInfo *TemplateArgs) {
430+
const TemplateArgumentListInfo *TemplateArgs,
431+
NonOdrUseReason NOUR) {
432432
// Filter out cases where the found Decl is the same as the value refenenced.
433433
if (D == FoundD)
434434
FoundD = nullptr;
@@ -443,8 +443,8 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
443443

444444
void *Mem = Context.Allocate(Size, alignof(DeclRefExpr));
445445
return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D,
446-
RefersToEnclosingVariableOrCapture,
447-
NameInfo, FoundD, TemplateArgs, T, VK);
446+
RefersToEnclosingVariableOrCapture, NameInfo,
447+
FoundD, TemplateArgs, T, VK, NOUR);
448448
}
449449

450450
DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context,

clang/lib/AST/JSONNodeDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,12 @@ void JSONNodeDumper::VisitDeclRefExpr(const DeclRefExpr *DRE) {
805805
if (DRE->getDecl() != DRE->getFoundDecl())
806806
JOS.attribute("foundReferencedDecl",
807807
createBareDeclRef(DRE->getFoundDecl()));
808+
switch (DRE->isNonOdrUse()) {
809+
case NOUR_None: break;
810+
case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break;
811+
case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break;
812+
case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break;
813+
}
808814
}
809815

810816
void JSONNodeDumper::VisitPredefinedExpr(const PredefinedExpr *PE) {

0 commit comments

Comments
 (0)