case SK_QualificationConversionRValue:
case SK_QualificationConversionXValue:
case SK_QualificationConversionLValue:
+ case SK_AtomicConversion:
case SK_LValueToRValue:
case SK_ListInitialization:
case SK_UnwrapInitList:
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");
/// 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()) &&
Initializer) ||
S.ConversionToObjCStringLiteralCheck(DestType, Initializer))
Args[0] = Initializer;
-
}
if (!isa<InitListExpr>(Initializer))
SourceType = Initializer->getType();
(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
// 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;
}
// - 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;
}
// 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.
AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0));
}
- AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+ AddPassByIndirectCopyRestoreStep(DestType, ShouldCopy);
} else if (ICS.isBad()) {
DeclAccessPair dap;
if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) {
else
SetFailed(InitializationSequence::FK_ConversionFailed);
} else {
- AddConversionSequenceStep(ICS, Entity.getType(), TopLevelOfInitList);
+ AddConversionSequenceStep(ICS, DestType, TopLevelOfInitList);
MaybeProduceObjCObject(S, *this, Entity);
}
case SK_QualificationConversionLValue:
case SK_QualificationConversionXValue:
case SK_QualificationConversionRValue:
+ case SK_AtomicConversion:
case SK_LValueToRValue:
case SK_ConversionSequence:
case SK_ConversionSequenceNoNarrowing:
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,
OS << "qualification conversion (lvalue)";
break;
+ case SK_AtomicConversion:
+ OS << "non-atomic-to-atomic conversion";
+ break;
+
case SK_LValueToRValue:
OS << "load (lvalue to rvalue)";
break;
-// 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);
// 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 };
+ }
+}