diff options
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 74 |
1 files changed, 63 insertions, 11 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 467fb82b8d0..19eaf55ba43 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1001,6 +1001,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) { const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E); return CLE->isFileScope() && CLE->isLValue(); } + case Expr::MaterializeTemporaryExprClass: + // A materialized temporary might have been lifetime-extended to static + // storage duration. + return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() == SD_Static; // A string literal has static storage duration. case Expr::StringLiteralClass: case Expr::PredefinedExprClass: @@ -1182,7 +1186,10 @@ const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { } static bool IsLiteralLValue(const LValue &Value) { - return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex; + if (Value.CallIndex) + return false; + const Expr *E = Value.Base.dyn_cast<const Expr*>(); + return E && !isa<MaterializeTemporaryExpr>(E); } static bool IsWeakLValue(const LValue &Value) { @@ -2279,11 +2286,44 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); if (!Frame) { - Info.Diag(E); - return CompleteObject(); - } + if (const MaterializeTemporaryExpr *MTE = + dyn_cast<MaterializeTemporaryExpr>(Base)) { + assert(MTE->getStorageDuration() == SD_Static && + "should have a frame for a non-global materialized temporary"); + + // Per C++1y [expr.const]p2: + // an lvalue-to-rvalue conversion [is not allowed unless it applies to] + // - a [...] glvalue of integral or enumeration type that refers to + // a non-volatile const object [...] + // [...] + // - a [...] glvalue of literal type that refers to a non-volatile + // object whose lifetime began within the evaluation of e. + // + // C++11 misses the 'began within the evaluation of e' check and + // instead allows all temporaries, including things like: + // int &&r = 1; + // int x = ++r; + // constexpr int k = r; + // Therefore we use the C++1y rules in C++11 too. + const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>(); + const ValueDecl *ED = MTE->getExtendingDecl(); + if (!(BaseType.isConstQualified() && + BaseType->isIntegralOrEnumerationType()) && + !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) { + Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK; + Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here); + return CompleteObject(); + } - BaseVal = &Frame->Temporaries[Base]; + BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); + assert(BaseVal && "got reference to unevaluated temporary"); + } else { + Info.Diag(E); + return CompleteObject(); + } + } else { + BaseVal = &Frame->Temporaries[Base]; + } // Volatile temporary objects cannot be accessed in constant expressions. if (BaseType.isVolatileQualified()) { @@ -3940,6 +3980,8 @@ public: // * Any Expr, with a CallIndex indicating the function in which the temporary // was evaluated, for cases where the MaterializeTemporaryExpr is missing // from the AST (FIXME). +// * A MaterializeTemporaryExpr that has static storage duration, with no +// CallIndex, for a lifetime-extended temporary. // plus an offset in bytes. //===----------------------------------------------------------------------===// namespace { @@ -4045,9 +4087,19 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( if (!EvaluateIgnoredValue(Info, CommaLHSs[I])) return false; + // A materialized temporary with static storage duration can appear within the + // result of a constant expression evaluation, so we need to preserve its + // value for use outside this evaluation. + APValue *Value; + if (E->getStorageDuration() == SD_Static) { + Value = Info.Ctx.getMaterializedTemporaryValue(E, true); + Result.set(E); + } else { + Value = &Info.CurrentCall->Temporaries[E]; + Result.set(E, Info.CurrentCall->Index); + } + // Materialize the temporary itself. - APValue *Value = &Info.CurrentCall->Temporaries[E]; - Result.set(E, Info.CurrentCall->Index); if (!EvaluateInPlace(*Value, Info, Result, Inner)) return false; @@ -7608,10 +7660,10 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx, } } - bool Expr::EvalResult::isGlobalLValue() const { - assert(Val.isLValue()); - return IsGlobalLValue(Val.getLValueBase()); - } +bool Expr::EvalResult::isGlobalLValue() const { + assert(Val.isLValue()); + return IsGlobalLValue(Val.getLValueBase()); +} /// isIntegerConstantExpr - this recursive routine will test if an expression is |