зеркало из https://github.com/microsoft/clang-1.git
Fix lifetime issue for backing APValue of OpaqueValueExpr in recursive
constexpr function evaluation, and corresponding ASan / valgrind issue in tests, by storing the corresponding value with the relevant stack frame. This also prevents re-evaluation of the source of the underlying OpaqueValueExpr, which makes a major performance difference for certain contrived code (see testcase update). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159189 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
66a5bf923c
Коммит
e92b1f4917
|
@ -366,9 +366,6 @@ namespace {
|
|||
// Note that we intentionally use std::map here so that references
|
||||
// to values are stable.
|
||||
typedef std::map<const OpaqueValueExpr*, APValue> MapTy;
|
||||
/// OpaqueValues - Values used as the common expression in a
|
||||
/// BinaryConditionalOperator.
|
||||
MapTy OpaqueValues;
|
||||
|
||||
/// BottomFrame - The frame in which evaluation started. This must be
|
||||
/// initialized after CurrentCall and CallStackDepth.
|
||||
|
@ -398,12 +395,6 @@ namespace {
|
|||
EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
|
||||
CheckingPotentialConstantExpression(false) {}
|
||||
|
||||
const APValue *getOpaqueValue(const OpaqueValueExpr *e) const {
|
||||
MapTy::const_iterator i = OpaqueValues.find(e);
|
||||
if (i == OpaqueValues.end()) return 0;
|
||||
return &i->second;
|
||||
}
|
||||
|
||||
void setEvaluatingDecl(const VarDecl *VD, APValue &Value) {
|
||||
EvaluatingDecl = VD;
|
||||
EvaluatingDeclValue = &Value;
|
||||
|
@ -2364,32 +2355,6 @@ public:
|
|||
bool VisitSizeOfPackExpr(const SizeOfPackExpr *) { return false; }
|
||||
};
|
||||
|
||||
class OpaqueValueEvaluation {
|
||||
EvalInfo &info;
|
||||
OpaqueValueExpr *opaqueValue;
|
||||
|
||||
public:
|
||||
OpaqueValueEvaluation(EvalInfo &info, OpaqueValueExpr *opaqueValue,
|
||||
Expr *value)
|
||||
: info(info), opaqueValue(opaqueValue) {
|
||||
|
||||
// If evaluation fails, fail immediately.
|
||||
if (!Evaluate(info.OpaqueValues[opaqueValue], info, value)) {
|
||||
this->opaqueValue = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasError() const { return opaqueValue == 0; }
|
||||
|
||||
~OpaqueValueEvaluation() {
|
||||
// FIXME: For a recursive constexpr call, an outer stack frame might have
|
||||
// been using this opaque value too, and will now have to re-evaluate the
|
||||
// source expression.
|
||||
if (opaqueValue) info.OpaqueValues.erase(opaqueValue);
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -2532,9 +2497,10 @@ public:
|
|||
}
|
||||
|
||||
RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
|
||||
// Cache the value of the common expression.
|
||||
OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon());
|
||||
if (opaque.hasError())
|
||||
// Evaluate and cache the common expression. We treat it as a temporary,
|
||||
// even though it's not quite the same thing.
|
||||
if (!Evaluate(Info.CurrentCall->Temporaries[E->getOpaqueValue()],
|
||||
Info, E->getCommon()))
|
||||
return false;
|
||||
|
||||
return HandleConditionalOperator(E);
|
||||
|
@ -2568,8 +2534,8 @@ public:
|
|||
}
|
||||
|
||||
RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
|
||||
const APValue *Value = Info.getOpaqueValue(E);
|
||||
if (!Value) {
|
||||
APValue &Value = Info.CurrentCall->Temporaries[E];
|
||||
if (Value.isUninit()) {
|
||||
const Expr *Source = E->getSourceExpr();
|
||||
if (!Source)
|
||||
return Error(E);
|
||||
|
@ -2579,7 +2545,7 @@ public:
|
|||
}
|
||||
return StmtVisitorTy::Visit(Source);
|
||||
}
|
||||
return DerivedSuccess(*Value, E);
|
||||
return DerivedSuccess(Value, E);
|
||||
}
|
||||
|
||||
RetTy VisitCallExpr(const CallExpr *E) {
|
||||
|
|
|
@ -1213,6 +1213,17 @@ namespace RecursiveOpaqueExpr {
|
|||
|
||||
constexpr int arr2[] = { 1, 0, 0, 3, 0, 2, 0, 4, 0, 5 };
|
||||
static_assert(LastNonzero(begin(arr2), end(arr2)) == 5, "");
|
||||
|
||||
constexpr int arr3[] = {
|
||||
1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
static_assert(LastNonzero(begin(arr3), end(arr3)) == 2, "");
|
||||
}
|
||||
|
||||
namespace VLASizeof {
|
||||
|
|
Загрузка…
Ссылка в новой задаче