Author: rsmith Date: Wed Feb 22 16:09:50 2017 New Revision: 295886 URL: http://llvm.org/viewvc/llvm-project?rev=295886&view=rev Log: PR32034: Evaluate _Atomic(T) in-place when T is a class or array type.
This is necessary in order for the evaluation of an _Atomic initializer for those types to have an associated object, which an initializer for class or array type needs. Modified: cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=295886&r1=295885&r2=295886&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Feb 22 16:09:50 2017 @@ -1437,7 +1437,8 @@ static bool EvaluateIntegerOrLValue(cons EvalInfo &Info); static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); -static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info); +static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result, + EvalInfo &Info); static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result); //===----------------------------------------------------------------------===// @@ -4743,7 +4744,10 @@ public: case CK_AtomicToNonAtomic: { APValue AtomicVal; - if (!EvaluateAtomic(E->getSubExpr(), AtomicVal, Info)) + // This does not need to be done in place even for class/array types: + // atomic-to-non-atomic conversion implies copying the object + // representation. + if (!Evaluate(AtomicVal, Info, E->getSubExpr())) return false; return DerivedSuccess(AtomicVal, E); } @@ -9689,10 +9693,11 @@ bool ComplexExprEvaluator::VisitInitList namespace { class AtomicExprEvaluator : public ExprEvaluatorBase<AtomicExprEvaluator> { + const LValue *This; APValue &Result; public: - AtomicExprEvaluator(EvalInfo &Info, APValue &Result) - : ExprEvaluatorBaseTy(Info), Result(Result) {} + AtomicExprEvaluator(EvalInfo &Info, const LValue *This, APValue &Result) + : ExprEvaluatorBaseTy(Info), This(This), Result(Result) {} bool Success(const APValue &V, const Expr *E) { Result = V; @@ -9702,7 +9707,10 @@ public: bool ZeroInitialization(const Expr *E) { ImplicitValueInitExpr VIE( E->getType()->castAs<AtomicType>()->getValueType()); - return Evaluate(Result, Info, &VIE); + // For atomic-qualified class (and array) types in C++, initialize the + // _Atomic-wrapped subobject directly, in-place. + return This ? EvaluateInPlace(Result, Info, *This, &VIE) + : Evaluate(Result, Info, &VIE); } bool VisitCastExpr(const CastExpr *E) { @@ -9710,15 +9718,17 @@ public: default: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_NonAtomicToAtomic: - return Evaluate(Result, Info, E->getSubExpr()); + return This ? EvaluateInPlace(Result, Info, *This, E->getSubExpr()) + : Evaluate(Result, Info, E->getSubExpr()); } } }; } // end anonymous namespace -static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info) { +static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result, + EvalInfo &Info) { assert(E->isRValue() && E->getType()->isAtomicType()); - return AtomicExprEvaluator(Info, Result).Visit(E); + return AtomicExprEvaluator(Info, This, Result).Visit(E); } //===----------------------------------------------------------------------===// @@ -9823,8 +9833,17 @@ static bool Evaluate(APValue &Result, Ev if (!EvaluateVoid(E, Info)) return false; } else if (T->isAtomicType()) { - if (!EvaluateAtomic(E, Result, Info)) - return false; + QualType Unqual = T.getAtomicUnqualifiedType(); + if (Unqual->isArrayType() || Unqual->isRecordType()) { + LValue LV; + LV.set(E, Info.CurrentCall->Index); + APValue &Value = Info.CurrentCall->createTemporary(E, false); + if (!EvaluateAtomic(E, &LV, Value, Info)) + return false; + } else { + if (!EvaluateAtomic(E, nullptr, Result, Info)) + return false; + } } else if (Info.getLangOpts().CPlusPlus11) { Info.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType(); return false; @@ -9849,10 +9868,16 @@ static bool EvaluateInPlace(APValue &Res if (E->isRValue()) { // Evaluate arrays and record types in-place, so that later initializers can // refer to earlier-initialized members of the object. - if (E->getType()->isArrayType()) + QualType T = E->getType(); + if (T->isArrayType()) return EvaluateArray(E, This, Result, Info); - else if (E->getType()->isRecordType()) + else if (T->isRecordType()) return EvaluateRecord(E, This, Result, Info); + else if (T->isAtomicType()) { + QualType Unqual = T.getAtomicUnqualifiedType(); + if (Unqual->isArrayType() || Unqual->isRecordType()) + return EvaluateAtomic(E, &This, Result, Info); + } } // For any other type, in-place evaluation is unimportant. Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=295886&r1=295885&r2=295886&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original) +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Wed Feb 22 16:09:50 2017 @@ -1280,6 +1280,15 @@ namespace Atomic { constexpr TestVar testVar{-1}; static_assert(testVar.value == -1, ""); } + + namespace PR32034 { + struct A {}; + struct B { _Atomic(A) a; }; + constexpr int n = (B(), B(), 0); + + struct C { constexpr C() {} void *self = this; }; + constexpr _Atomic(C) c = C(); + } } namespace InstantiateCaseStmt { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits