From e92b1f4917bfb669a09d220dc979fc3676df4da8 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 26 Jun 2012 08:12:11 +0000 Subject: [PATCH] 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 --- lib/AST/ExprConstant.cpp | 48 ++++------------------ test/SemaCXX/constant-expression-cxx11.cpp | 11 +++++ 2 files changed, 18 insertions(+), 41 deletions(-) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index b16ba8fb52..d81151dc1a 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -366,9 +366,6 @@ namespace { // Note that we intentionally use std::map here so that references // to values are stable. typedef std::map 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) { diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 263e8411b4..066136dd84 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -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 { -- 2.50.1