r182541 - PR14772: Support constant expression evaluation for _Atomic types.
Richard Smith
richard-llvm at metafoo.co.uk
Wed May 22 17:30:41 PDT 2013
Author: rsmith
Date: Wed May 22 19:30:41 2013
New Revision: 182541
URL: http://llvm.org/viewvc/llvm-project?rev=182541&view=rev
Log:
PR14772: Support constant expression evaluation for _Atomic types.
* Treat _Atomic(T) as a literal type if T is a literal type.
* Evaluate expressions of this type properly.
* Fix a lurking bug where we built completely bogus ASTs for converting to
_Atomic types in C++ in some cases, caught by the tests for this change.
Modified:
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/Sema/SemaExprCXX.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=182541&r1=182540&r2=182541&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed May 22 19:30:41 2013
@@ -915,6 +915,7 @@ 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);
//===----------------------------------------------------------------------===//
// Misc utilities
@@ -3702,8 +3703,13 @@ public:
default:
break;
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic: {
+ APValue AtomicVal;
+ if (!EvaluateAtomic(E->getSubExpr(), AtomicVal, Info))
+ return false;
+ return DerivedSuccess(AtomicVal, E);
+ }
+
case CK_NoOp:
case CK_UserDefinedConversion:
return StmtVisitorTy::Visit(E->getSubExpr());
@@ -6469,6 +6475,7 @@ bool IntExprEvaluator::VisitCastExpr(con
case CK_IntegralComplexToFloatingComplex:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
+ case CK_NonAtomicToAtomic:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -6484,7 +6491,6 @@ bool IntExprEvaluator::VisitCastExpr(con
case CK_UserDefinedConversion:
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
case CK_NoOp:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
@@ -6937,11 +6943,11 @@ bool ComplexExprEvaluator::VisitCastExpr
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
+ case CK_NonAtomicToAtomic:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
case CK_NoOp:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
@@ -7198,6 +7204,46 @@ bool ComplexExprEvaluator::VisitInitList
}
//===----------------------------------------------------------------------===//
+// Atomic expression evaluation, essentially just handling the NonAtomicToAtomic
+// implicit conversion.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class AtomicExprEvaluator :
+ public ExprEvaluatorBase<AtomicExprEvaluator, bool> {
+ APValue &Result;
+public:
+ AtomicExprEvaluator(EvalInfo &Info, APValue &Result)
+ : ExprEvaluatorBaseTy(Info), Result(Result) {}
+
+ bool Success(const APValue &V, const Expr *E) {
+ Result = V;
+ return true;
+ }
+
+ bool ZeroInitialization(const Expr *E) {
+ ImplicitValueInitExpr VIE(
+ E->getType()->castAs<AtomicType>()->getValueType());
+ return Evaluate(Result, Info, &VIE);
+ }
+
+ bool VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+ case CK_NonAtomicToAtomic:
+ return Evaluate(Result, Info, E->getSubExpr());
+ }
+ }
+};
+} // end anonymous namespace
+
+static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isAtomicType());
+ return AtomicExprEvaluator(Info, Result).Visit(E);
+}
+
+//===----------------------------------------------------------------------===//
// Void expression evaluation, primarily for a cast to void on the LHS of a
// comma operator
//===----------------------------------------------------------------------===//
@@ -7234,56 +7280,60 @@ static bool EvaluateVoid(const Expr *E,
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
// In C, function designators are not lvalues, but we evaluate them as if they
// are.
- if (E->isGLValue() || E->getType()->isFunctionType()) {
+ QualType T = E->getType();
+ if (E->isGLValue() || T->isFunctionType()) {
LValue LV;
if (!EvaluateLValue(E, LV, Info))
return false;
LV.moveInto(Result);
- } else if (E->getType()->isVectorType()) {
+ } else if (T->isVectorType()) {
if (!EvaluateVector(E, Result, Info))
return false;
- } else if (E->getType()->isIntegralOrEnumerationType()) {
+ } else if (T->isIntegralOrEnumerationType()) {
if (!IntExprEvaluator(Info, Result).Visit(E))
return false;
- } else if (E->getType()->hasPointerRepresentation()) {
+ } else if (T->hasPointerRepresentation()) {
LValue LV;
if (!EvaluatePointer(E, LV, Info))
return false;
LV.moveInto(Result);
- } else if (E->getType()->isRealFloatingType()) {
+ } else if (T->isRealFloatingType()) {
llvm::APFloat F(0.0);
if (!EvaluateFloat(E, F, Info))
return false;
Result = APValue(F);
- } else if (E->getType()->isAnyComplexType()) {
+ } else if (T->isAnyComplexType()) {
ComplexValue C;
if (!EvaluateComplex(E, C, Info))
return false;
C.moveInto(Result);
- } else if (E->getType()->isMemberPointerType()) {
+ } else if (T->isMemberPointerType()) {
MemberPtr P;
if (!EvaluateMemberPointer(E, P, Info))
return false;
P.moveInto(Result);
return true;
- } else if (E->getType()->isArrayType()) {
+ } else if (T->isArrayType()) {
LValue LV;
LV.set(E, Info.CurrentCall->Index);
if (!EvaluateArray(E, LV, Info.CurrentCall->Temporaries[E], Info))
return false;
Result = Info.CurrentCall->Temporaries[E];
- } else if (E->getType()->isRecordType()) {
+ } else if (T->isRecordType()) {
LValue LV;
LV.set(E, Info.CurrentCall->Index);
if (!EvaluateRecord(E, LV, Info.CurrentCall->Temporaries[E], Info))
return false;
Result = Info.CurrentCall->Temporaries[E];
- } else if (E->getType()->isVoidType()) {
+ } else if (T->isVoidType()) {
if (!Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_nonliteral)
<< E->getType();
if (!EvaluateVoid(E, Info))
return false;
+ } else if (T->isAtomicType()) {
+ if (!EvaluateAtomic(E, Result, Info))
+ return false;
} else if (Info.getLangOpts().CPlusPlus11) {
Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType();
return false;
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=182541&r1=182540&r2=182541&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Wed May 22 19:30:41 2013
@@ -1196,6 +1196,10 @@ bool Type::isLiteralType(ASTContext &Ctx
return true;
}
+ // We treat _Atomic T as a literal type if T is a literal type.
+ if (const AtomicType *AT = BaseTy->getAs<AtomicType>())
+ return AT->getValueType()->isLiteralType(Ctx);
+
// If this type hasn't been deduced yet, then conservatively assume that
// it'll work out to be a literal type.
if (isa<AutoType>(BaseTy->getCanonicalTypeInternal()))
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=182541&r1=182540&r2=182541&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed May 22 19:30:41 2013
@@ -2555,6 +2555,14 @@ Sema::PerformImplicitConversion(Expr *Fr
FromType = From->getType();
}
+ // If we're converting to an atomic type, first convert to the corresponding
+ // non-atomic type.
+ QualType ToAtomicType;
+ if (const AtomicType *ToAtomic = ToType->getAs<AtomicType>()) {
+ ToAtomicType = ToType;
+ ToType = ToAtomic->getValueType();
+ }
+
// Perform the first implicit conversion.
switch (SCS.First) {
case ICK_Identity:
@@ -2864,7 +2872,7 @@ Sema::PerformImplicitConversion(Expr *Fr
<< ToType.getNonReferenceType();
break;
- }
+ }
default:
llvm_unreachable("Improper third standard conversion");
@@ -2872,11 +2880,13 @@ Sema::PerformImplicitConversion(Expr *Fr
// If this conversion sequence involved a scalar -> atomic conversion, perform
// that conversion now.
- if (const AtomicType *ToAtomic = ToType->getAs<AtomicType>())
- if (Context.hasSameType(ToAtomic->getValueType(), From->getType()))
- From = ImpCastExprToType(From, ToType, CK_NonAtomicToAtomic, VK_RValue, 0,
- CCK).take();
-
+ if (!ToAtomicType.isNull()) {
+ assert(Context.hasSameType(
+ ToAtomicType->castAs<AtomicType>()->getValueType(), From->getType()));
+ From = ImpCastExprToType(From, ToAtomicType, CK_NonAtomicToAtomic,
+ VK_RValue, 0, CCK).take();
+ }
+
return Owned(From);
}
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=182541&r1=182540&r2=182541&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Wed May 22 19:30:41 2013
@@ -1138,6 +1138,31 @@ namespace ComplexConstexpr {
static_assert(&__imag test6 == &__real test6 + 1, "");
}
+// _Atomic(T) is exactly like T for the purposes of constant expression
+// evaluation..
+namespace Atomic {
+ constexpr _Atomic int n = 3;
+
+ struct S { _Atomic(double) d; };
+ constexpr S s = { 0.5 };
+ constexpr double d1 = s.d;
+ constexpr double d2 = n;
+ constexpr _Atomic double d3 = n;
+
+ constexpr _Atomic(int) n2 = d3;
+ static_assert(d1 == 0.5, "");
+ static_assert(d3 == 3.0, "");
+
+ namespace PR16056 {
+ struct TestVar {
+ _Atomic(int) value;
+ constexpr TestVar(int value) : value(value) {}
+ };
+ constexpr TestVar testVar{-1};
+ static_assert(testVar.value == -1, "");
+ }
+}
+
namespace InstantiateCaseStmt {
template<int x> constexpr int f() { return x; }
template<int x> int g(int c) { switch(c) { case f<x>(): return 1; } return 0; }
More information about the cfe-commits
mailing list