forked from OSchip/llvm-project
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. llvm-svn: 295886
This commit is contained in:
parent
835b246d7f
commit
64cb9ca456
|
@ -1437,7 +1437,8 @@ static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
|
|||
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::VisitInitListExpr(const InitListExpr *E) {
|
|||
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, EvalInfo &Info, const Expr *E) {
|
|||
if (!EvaluateVoid(E, Info))
|
||||
return false;
|
||||
} else if (T->isAtomicType()) {
|
||||
if (!EvaluateAtomic(E, Result, Info))
|
||||
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 &Result, EvalInfo &Info, const LValue &This,
|
|||
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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue