summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBill Wendling <isanbard@gmail.com>2014-08-04 18:31:55 +0000
committerBill Wendling <isanbard@gmail.com>2014-08-04 18:31:55 +0000
commit9626e0eda7e85e55c9b48bf8b359598da6d39c16 (patch)
treeb6db3a96d318f11bda8bcdeb475b44b2ca79e006
parent31c3814ef301549599411769eec7a2a73ece112b (diff)
------------------------------------------------------------------------
git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_35@214744 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Sema/Initialization.h8
-rw-r--r--lib/AST/ExprConstant.cpp5
-rw-r--r--lib/CodeGen/CGExprAgg.cpp10
-rw-r--r--lib/CodeGen/CGExprConstant.cpp19
-rw-r--r--lib/Sema/SemaInit.cpp55
-rw-r--r--test/CodeGen/c11atomics.c5
-rw-r--r--test/CodeGenCXX/atomicinit.cpp56
-rw-r--r--test/SemaCXX/atomic-type.cpp29
8 files changed, 172 insertions, 15 deletions
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index 4465850799..9f342b2407 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -663,6 +663,8 @@ public:
SK_QualificationConversionXValue,
/// \brief Perform a qualification conversion, producing an lvalue.
SK_QualificationConversionLValue,
+ /// \brief Perform a conversion adding _Atomic to a type.
+ SK_AtomicConversion,
/// \brief Perform a load from a glvalue, producing an rvalue.
SK_LValueToRValue,
/// \brief Perform an implicit conversion sequence.
@@ -999,7 +1001,11 @@ public:
/// given type.
void AddQualificationConversionStep(QualType Ty,
ExprValueKind Category);
-
+
+ /// \brief Add a new step that performs conversion from non-atomic to atomic
+ /// type.
+ void AddAtomicConversionStep(QualType Ty);
+
/// \brief Add a new step that performs a load of the given type.
///
/// Although the term "LValueToRValue" is conventional, this applies to both
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index b1d2265872..7d7ca9924c 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1352,6 +1352,11 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
return false;
}
+ // We allow _Atomic(T) to be initialized from anything that T can be
+ // initialized from.
+ if (const AtomicType *AT = Type->getAs<AtomicType>())
+ Type = AT->getValueType();
+
// Core issue 1454: For a literal constant expression of array or class type,
// each subobject of its value shall have been initialized by a constant
// expression.
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index b1406cdd7c..4cf94c033b 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -1137,6 +1137,16 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
return;
}
+ if (E->getType()->isAtomicType()) {
+ // An _Atomic(T) object can be list-initialized from an expression
+ // of the same type.
+ assert(E->getNumInits() == 1 &&
+ CGF.getContext().hasSameUnqualifiedType(E->getInit(0)->getType(),
+ E->getType()) &&
+ "unexpected list initialization for atomic object");
+ return Visit(E->getInit(0));
+ }
+
assert(E->getType()->isRecordType() && "Only support structs/unions here!");
// Do struct initialization; this code just sets each individual member
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index b2f08c32d9..b508dcb446 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -1045,6 +1045,25 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
QualType DestType,
CodeGenFunction *CGF) {
+ // For an _Atomic-qualified constant, we may need to add tail padding.
+ if (auto *AT = DestType->getAs<AtomicType>()) {
+ QualType InnerType = AT->getValueType();
+ auto *Inner = EmitConstantValue(Value, InnerType, CGF);
+
+ uint64_t InnerSize = Context.getTypeSize(InnerType);
+ uint64_t OuterSize = Context.getTypeSize(DestType);
+ if (InnerSize == OuterSize)
+ return Inner;
+
+ assert(InnerSize < OuterSize && "emitted over-large constant for atomic");
+ llvm::Constant *Elts[] = {
+ Inner,
+ llvm::ConstantAggregateZero::get(
+ llvm::ArrayType::get(Int8Ty, (OuterSize - InnerSize) / 8))
+ };
+ return llvm::ConstantStruct::getAnon(Elts);
+ }
+
switch (Value.getKind()) {
case APValue::Uninitialized:
llvm_unreachable("Constant expressions should be initialized.");
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 3aa46ea1df..06ca9aed6a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2767,6 +2767,7 @@ void InitializationSequence::Step::Destroy() {
case SK_QualificationConversionRValue:
case SK_QualificationConversionXValue:
case SK_QualificationConversionLValue:
+ case SK_AtomicConversion:
case SK_LValueToRValue:
case SK_ListInitialization:
case SK_UnwrapInitList:
@@ -2919,6 +2920,13 @@ void InitializationSequence::AddQualificationConversionStep(QualType Ty,
Steps.push_back(S);
}
+void InitializationSequence::AddAtomicConversionStep(QualType Ty) {
+ Step S;
+ S.Kind = SK_AtomicConversion;
+ S.Type = Ty;
+ Steps.push_back(S);
+}
+
void InitializationSequence::AddLValueToRValueStep(QualType Ty) {
assert(!Ty.hasQualifiers() && "rvalues may not have qualifiers");
@@ -4174,12 +4182,11 @@ static void TryDefaultInitialization(Sema &S,
/// which enumerates all conversion functions and performs overload resolution
/// to select the best.
static void TryUserDefinedConversion(Sema &S,
- const InitializedEntity &Entity,
+ QualType DestType,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence,
bool TopLevelOfInitList) {
- QualType DestType = Entity.getType();
assert(!DestType->isReferenceType() && "References are handled elsewhere");
QualType SourceType = Initializer->getType();
assert((DestType->isRecordType() || SourceType->isRecordType()) &&
@@ -4596,7 +4603,6 @@ void InitializationSequence::InitializeFrom(Sema &S,
Initializer) ||
S.ConversionToObjCStringLiteralCheck(DestType, Initializer))
Args[0] = Initializer;
-
}
if (!isa<InitListExpr>(Initializer))
SourceType = Initializer->getType();
@@ -4741,7 +4747,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
(Context.hasSameUnqualifiedType(SourceType, DestType) ||
S.IsDerivedFrom(SourceType, DestType))))
TryConstructorInitialization(S, Entity, Kind, Args,
- Entity.getType(), *this);
+ DestType, *this);
// - Otherwise (i.e., for the remaining copy-initialization cases),
// user-defined conversion sequences that can convert from the source
// type to the destination type or (when a conversion function is
@@ -4749,7 +4755,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
// 13.3.1.4, and the best one is chosen through overload resolution
// (13.3).
else
- TryUserDefinedConversion(S, Entity, Kind, Initializer, *this,
+ TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
TopLevelOfInitList);
return;
}
@@ -4763,9 +4769,22 @@ void InitializationSequence::InitializeFrom(Sema &S,
// - Otherwise, if the source type is a (possibly cv-qualified) class
// type, conversion functions are considered.
if (!SourceType.isNull() && SourceType->isRecordType()) {
- TryUserDefinedConversion(S, Entity, Kind, Initializer, *this,
+ // For a conversion to _Atomic(T) from either T or a class type derived
+ // from T, initialize the T object then convert to _Atomic type.
+ bool NeedAtomicConversion = false;
+ if (const AtomicType *Atomic = DestType->getAs<AtomicType>()) {
+ if (Context.hasSameUnqualifiedType(SourceType, Atomic->getValueType()) ||
+ S.IsDerivedFrom(SourceType, Atomic->getValueType())) {
+ DestType = Atomic->getValueType();
+ NeedAtomicConversion = true;
+ }
+ }
+
+ TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
TopLevelOfInitList);
MaybeProduceObjCObject(S, *this, Entity);
+ if (!Failed() && NeedAtomicConversion)
+ AddAtomicConversionStep(Entity.getType());
return;
}
@@ -4774,16 +4793,16 @@ void InitializationSequence::InitializeFrom(Sema &S,
// conversions (Clause 4) will be used, if necessary, to convert the
// initializer expression to the cv-unqualified version of the
// destination type; no user-defined conversions are considered.
-
+
ImplicitConversionSequence ICS
- = S.TryImplicitConversion(Initializer, Entity.getType(),
+ = S.TryImplicitConversion(Initializer, DestType,
/*SuppressUserConversions*/true,
/*AllowExplicitConversions*/ false,
/*InOverloadResolution*/ false,
/*CStyle=*/Kind.isCStyleOrFunctionalCast(),
allowObjCWritebackConversion);
-
- if (ICS.isStandard() &&
+
+ if (ICS.isStandard() &&
ICS.Standard.Second == ICK_Writeback_Conversion) {
// Objective-C ARC writeback conversion.
@@ -4804,7 +4823,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0));
}
- AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+ AddPassByIndirectCopyRestoreStep(DestType, ShouldCopy);
} else if (ICS.isBad()) {
DeclAccessPair dap;
if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) {
@@ -4816,7 +4835,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
else
SetFailed(InitializationSequence::FK_ConversionFailed);
} else {
- AddConversionSequenceStep(ICS, Entity.getType(), TopLevelOfInitList);
+ AddConversionSequenceStep(ICS, DestType, TopLevelOfInitList);
MaybeProduceObjCObject(S, *this, Entity);
}
@@ -5772,6 +5791,7 @@ InitializationSequence::Perform(Sema &S,
case SK_QualificationConversionLValue:
case SK_QualificationConversionXValue:
case SK_QualificationConversionRValue:
+ case SK_AtomicConversion:
case SK_LValueToRValue:
case SK_ConversionSequence:
case SK_ConversionSequenceNoNarrowing:
@@ -6062,6 +6082,13 @@ InitializationSequence::Perform(Sema &S,
break;
}
+ case SK_AtomicConversion: {
+ assert(CurInit.get()->isRValue() && "cannot convert glvalue to atomic");
+ CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
+ CK_NonAtomicToAtomic, VK_RValue);
+ break;
+ }
+
case SK_LValueToRValue: {
assert(CurInit.get()->isGLValue() && "cannot load from a prvalue");
CurInit = ImplicitCastExpr::Create(S.Context, Step->Type,
@@ -7012,6 +7039,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "qualification conversion (lvalue)";
break;
+ case SK_AtomicConversion:
+ OS << "non-atomic-to-atomic conversion";
+ break;
+
case SK_LValueToRValue:
OS << "load (lvalue to rvalue)";
break;
diff --git a/test/CodeGen/c11atomics.c b/test/CodeGen/c11atomics.c
index 5c761b1374..f4c9522cbd 100644
--- a/test/CodeGen/c11atomics.c
+++ b/test/CodeGen/c11atomics.c
@@ -12,6 +12,9 @@
// they're sufficiently rare that it's not worth making sure that the semantics
// are correct.
+// CHECK: @testStructGlobal = global {{.*}} { i16 1, i16 2, i16 3, i16 4 }
+// CHECK: @testPromotedStructGlobal = global {{.*}} { %{{.*}} { i16 1, i16 2, i16 3 }, [2 x i8] zeroinitializer }
+
typedef int __attribute__((vector_size(16))) vector;
_Atomic(_Bool) b;
@@ -224,6 +227,7 @@ void testComplexFloat(_Atomic(_Complex float) *fp) {
}
typedef struct { short x, y, z, w; } S;
+_Atomic S testStructGlobal = (S){1, 2, 3, 4};
// CHECK: define arm_aapcscc void @testStruct([[S:.*]]*
void testStruct(_Atomic(S) *fp) {
// CHECK: [[FP:%.*]] = alloca [[S]]*, align 4
@@ -272,6 +276,7 @@ void testStruct(_Atomic(S) *fp) {
}
typedef struct { short x, y, z; } PS;
+_Atomic PS testPromotedStructGlobal = (PS){1, 2, 3};
// CHECK: define arm_aapcscc void @testPromotedStruct([[APS:.*]]*
void testPromotedStruct(_Atomic(PS) *fp) {
// CHECK: [[FP:%.*]] = alloca [[APS]]*, align 4
diff --git a/test/CodeGenCXX/atomicinit.cpp b/test/CodeGenCXX/atomicinit.cpp
index ee2e9e4cf2..f453194468 100644
--- a/test/CodeGenCXX/atomicinit.cpp
+++ b/test/CodeGenCXX/atomicinit.cpp
@@ -1,4 +1,10 @@
-// RUN: %clang_cc1 %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 -std=c++11 | FileCheck %s
+
+// CHECK-DAG: @_ZN7PR180978constant1aE = global {{.*}} { i16 1, i8 6, i8 undef }, align 4
+// CHECK-DAG: @_ZN7PR180978constant1bE = global {{.*}} { i16 2, i8 6, i8 undef }, align 4
+// CHECK-DAG: @_ZN7PR180978constant1cE = global {{.*}} { i16 3, i8 6, i8 undef }, align 4
+// CHECK-DAG: @_ZN7PR180978constant1yE = global {{.*}} { {{.*}} { i16 4, i8 6, i8 undef }, i32 5 }, align 4
+
struct A {
_Atomic(int) i;
A(int j);
@@ -46,3 +52,51 @@ struct AtomicBoolMember {
// CHECK-NEXT: ret void
AtomicBoolMember::AtomicBoolMember(bool b) : ab(b) { }
+namespace PR18097 {
+ namespace dynamic {
+ struct X {
+ X(int);
+ short n;
+ char c;
+ };
+
+ // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
+ // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* @_ZN7PR180977dynamic1aE, i32 1)
+ _Atomic(X) a = X(1);
+
+ // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
+ // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* @_ZN7PR180977dynamic1bE, i32 2)
+ _Atomic(X) b(X(2));
+
+ // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
+ // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* @_ZN7PR180977dynamic1cE, i32 3)
+ _Atomic(X) c{X(3)};
+
+ struct Y {
+ _Atomic(X) a;
+ _Atomic(int) b;
+ };
+ // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
+ // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* getelementptr inbounds ({{.*}}* @_ZN7PR180977dynamic1yE, i32 0, i32 0), i32 4)
+ // CHECK: store i32 5, i32* getelementptr inbounds ({{.*}}* @_ZN7PR180977dynamic1yE, i32 0, i32 1)
+ Y y = { X(4), 5 };
+ }
+
+ // CHECKs at top of file.
+ namespace constant {
+ struct X {
+ constexpr X(int n) : n(n) {}
+ short n;
+ char c = 6;
+ };
+ _Atomic(X) a = X(1);
+ _Atomic(X) b(X(2));
+ _Atomic(X) c{X(3)};
+
+ struct Y {
+ _Atomic(X) a;
+ _Atomic(int) b;
+ };
+ Y y = { X(4), 5 };
+ }
+}
diff --git a/test/SemaCXX/atomic-type.cpp b/test/SemaCXX/atomic-type.cpp
index f522d92f39..ae18eab5b4 100644
--- a/test/SemaCXX/atomic-type.cpp
+++ b/test/SemaCXX/atomic-type.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -verify -pedantic %s
+// RUN: %clang_cc1 -verify -pedantic %s -std=c++98
+// RUN: %clang_cc1 -verify -pedantic %s -std=c++11
template<typename T> struct atomic {
_Atomic(T) value;
@@ -56,3 +57,29 @@ typedef _Atomic(int &) atomic_reference_to_int; // expected-error {{_Atomic cann
struct S {
_Atomic union { int n; }; // expected-warning {{anonymous union cannot be '_Atomic'}}
};
+
+namespace copy_init {
+ struct X {
+ X(int);
+ int n;
+ };
+ _Atomic(X) y = X(0);
+ _Atomic(X) z(X(0));
+ void f() { y = X(0); }
+
+ _Atomic(X) e1(0); // expected-error {{cannot initialize}}
+#if __cplusplus >= 201103L
+ _Atomic(X) e2{0}; // expected-error {{illegal initializer}}
+ _Atomic(X) a{X(0)};
+#endif
+
+ struct Y {
+ _Atomic(X) a;
+ _Atomic(int) b;
+ };
+ Y y1 = { X(0), 4 };
+ Y y2 = { 0, 4 }; // expected-error {{cannot initialize}}
+ // FIXME: It's not really clear if we should allow these. Generally, C++11
+ // allows extraneous braces around initializers.
+ Y y3 = { { X(0) }, { 4 } }; // expected-error 2{{illegal initializer type}}
+}