summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-04 04:00:45 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-04 04:00:45 +0000
commit37be3363b54b5bf30e3c76ab48c8206da45dcd0e (patch)
tree88a30faa6fe6250b9eca1ee6b035c853fb7eba3f /clang/lib/AST/ExprConstant.cpp
parent1e393064fa2732e721524f95a12348b0fd981167 (diff)
downloadbcm5719-llvm-37be3363b54b5bf30e3c76ab48c8206da45dcd0e.tar.gz
bcm5719-llvm-37be3363b54b5bf30e3c76ab48c8206da45dcd0e.zip
Disallow the operand of __builtin_constant_p from modifying enclosing
state when it's encountered while evaluating a constexpr function. We attempt to follow GCC trunk's behavior here, but it is somewhat inscrutible, so our behavior is only approximately the same for now. Specifically, we only permit modification of objects whose lifetime began within the operand of the __builtin_constant_p. GCC appears to have effectively the same restriction, but also some unknown restriction based on where and how the local state of the constexpr function is mentioned within the operand (see added testcases). llvm-svn: 359958
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r--clang/lib/AST/ExprConstant.cpp43
1 files changed, 28 insertions, 15 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6b3f4dcefa6..11e753c0771 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -716,6 +716,10 @@ namespace {
EvaluatingObject(Decl, {CallIndex, Version}));
}
+ /// If we're currently speculatively evaluating, the outermost call stack
+ /// depth at which we can mutate state, otherwise 0.
+ unsigned SpeculativeEvaluationDepth = 0;
+
/// The current array initialization index, if we're performing array
/// initialization.
uint64_t ArrayInitIndex = -1;
@@ -728,9 +732,6 @@ namespace {
/// fold (not just why it's not strictly a constant expression)?
bool HasFoldFailureDiagnostic;
- /// Whether or not we're currently speculatively evaluating.
- bool IsSpeculativelyEvaluating;
-
/// Whether or not we're in a context where the front end requires a
/// constant value.
bool InConstantContext;
@@ -795,7 +796,7 @@ namespace {
BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false), IsSpeculativelyEvaluating(false),
+ HasFoldFailureDiagnostic(false),
InConstantContext(false), EvalMode(Mode) {}
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
@@ -823,14 +824,20 @@ namespace {
return false;
}
- CallStackFrame *getCallFrame(unsigned CallIndex) {
- assert(CallIndex && "no call index in getCallFrame");
+ std::pair<CallStackFrame *, unsigned>
+ getCallFrameAndDepth(unsigned CallIndex) {
+ assert(CallIndex && "no call index in getCallFrameAndDepth");
// We will eventually hit BottomFrame, which has Index 1, so Frame can't
// be null in this loop.
+ unsigned Depth = CallStackDepth;
CallStackFrame *Frame = CurrentCall;
- while (Frame->Index > CallIndex)
+ while (Frame->Index > CallIndex) {
Frame = Frame->Caller;
- return (Frame->Index == CallIndex) ? Frame : nullptr;
+ --Depth;
+ }
+ if (Frame->Index == CallIndex)
+ return {Frame, Depth};
+ return {nullptr, 0};
}
bool nextStep(const Stmt *S) {
@@ -1111,12 +1118,12 @@ namespace {
class SpeculativeEvaluationRAII {
EvalInfo *Info = nullptr;
Expr::EvalStatus OldStatus;
- bool OldIsSpeculativelyEvaluating;
+ unsigned OldSpeculativeEvaluationDepth;
void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
Info = Other.Info;
OldStatus = Other.OldStatus;
- OldIsSpeculativelyEvaluating = Other.OldIsSpeculativelyEvaluating;
+ OldSpeculativeEvaluationDepth = Other.OldSpeculativeEvaluationDepth;
Other.Info = nullptr;
}
@@ -1125,7 +1132,7 @@ namespace {
return;
Info->EvalStatus = OldStatus;
- Info->IsSpeculativelyEvaluating = OldIsSpeculativelyEvaluating;
+ Info->SpeculativeEvaluationDepth = OldSpeculativeEvaluationDepth;
}
public:
@@ -1134,9 +1141,9 @@ namespace {
SpeculativeEvaluationRAII(
EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
: Info(&Info), OldStatus(Info.EvalStatus),
- OldIsSpeculativelyEvaluating(Info.IsSpeculativelyEvaluating) {
+ OldSpeculativeEvaluationDepth(Info.SpeculativeEvaluationDepth) {
Info.EvalStatus.Diag = NewDiag;
- Info.IsSpeculativelyEvaluating = true;
+ Info.SpeculativeEvaluationDepth = Info.CallStackDepth + 1;
}
SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete;
@@ -3138,8 +3145,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
CallStackFrame *Frame = nullptr;
+ unsigned Depth = 0;
if (LVal.getLValueCallIndex()) {
- Frame = Info.getCallFrame(LVal.getLValueCallIndex());
+ std::tie(Frame, Depth) =
+ Info.getCallFrameAndDepth(LVal.getLValueCallIndex());
if (!Frame) {
Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1)
<< AK << LVal.Base.is<const ValueDecl*>();
@@ -3330,7 +3339,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// to be read here (but take care with 'mutable' fields).
if ((Frame && Info.getLangOpts().CPlusPlus14 &&
Info.EvalStatus.HasSideEffects) ||
- (AK != AK_Read && Info.IsSpeculativelyEvaluating))
+ (AK != AK_Read && Depth < Info.SpeculativeEvaluationDepth))
return CompleteObject();
return CompleteObject(BaseVal, BaseType, LifetimeStartedInEvaluation);
@@ -7823,6 +7832,10 @@ static bool EvaluateBuiltinConstantPForLValue(const APValue &LV) {
/// EvaluateBuiltinConstantP - Evaluate __builtin_constant_p as similarly to
/// GCC as we can manage.
static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
+ // This evaluation is not permitted to have side-effects, so evaluate it in
+ // a speculative evaluation context.
+ SpeculativeEvaluationRAII SpeculativeEval(Info);
+
// Constant-folding is always enabled for the operand of __builtin_constant_p
// (even when the enclosing evaluation context otherwise requires a strict
// language-specific constant expression).
OpenPOWER on IntegriCloud