Compute standard conversion sequences for conversions to atomic

types. The second and third conversions in the sequence are based on
the conversion for the underlying type, so that we get sensible
overloading behavior for, e.g., _Atomic(int) vs. _Atomic(float).

As part of this, actually implement the lvalue-to-rvalue conversion
for atomic types. There is probably a pile of code in SemaExpr that
can now be deleted, but I haven't tracked it down yet.

llvm-svn: 154596
This commit is contained in:
Douglas Gregor 2012-04-12 17:51:55 +00:00
parent 30c3de97a9
commit c79862f017
3 changed files with 76 additions and 11 deletions

View File

@ -374,10 +374,6 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
QualType T = E->getType();
assert(!T.isNull() && "r-value conversion on typeless expression?");
// We can't do lvalue-to-rvalue on atomics yet.
if (T->isAtomicType())
return Owned(E);
// We don't want to throw lvalue-to-rvalue casts on top of
// expressions of certain types in C++.
if (getLangOpts().CPlusPlus &&
@ -413,6 +409,15 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
E, 0, VK_RValue));
// C11 6.3.2.1p2:
// ... if the lvalue has atomic type, the value has the non-atomic version
// of the type of the lvalue ...
if (const AtomicType *Atomic = T->getAs<AtomicType>()) {
T = Atomic->getValueType().getUnqualifiedType();
Res = Owned(ImplicitCastExpr::Create(Context, T, CK_AtomicToNonAtomic,
Res.get(), 0, VK_RValue));
}
return Res;
}

View File

@ -1294,6 +1294,11 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType,
return false;
}
static bool isAtomicConversion(Sema &S, Expr *From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle);
/// IsStandardConversion - Determines whether there is a standard
/// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the
/// expression From to the type ToType. Standard conversion sequences
@ -1389,6 +1394,12 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) {
SCS.First = ICK_Lvalue_To_Rvalue;
// C11 6.3.2.1p2:
// ... if the lvalue has atomic type, the value has the non-atomic version
// of the type of the lvalue ...
if (const AtomicType *Atomic = FromType->getAs<AtomicType>())
FromType = Atomic->getValueType();
// If T is a non-class type, the type of the rvalue is the
// cv-unqualified version of T. Otherwise, the type of the rvalue
// is T (C++ 4.1p1). C++ can't get here with class types; in C, we
@ -1520,13 +1531,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
SCS, CStyle)) {
SCS.Second = ICK_TransparentUnionConversion;
FromType = ToType;
} else if (const AtomicType *ToAtomicType = ToType->getAs<AtomicType>()) {
// Allow conversion to _Atomic types. These are C11 and are provided as an
// extension in C++ mode.
if (S.Context.hasSameUnqualifiedType(ToAtomicType->getValueType(),
FromType))
SCS.Second = ICK_Identity;
FromType = ToType;
} else if (isAtomicConversion(S, From, ToType, InOverloadResolution, SCS,
CStyle)) {
// isAtomicConversion has updated the standard conversion sequence
// appropriately.
return true;
} else {
// No second conversion required.
SCS.Second = ICK_Identity;
@ -2765,6 +2774,34 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
}
/// \brief - Determine whether this is a conversion from a scalar type to an
/// atomic type.
///
/// If successful, updates \c SCS's second and third steps in the conversion
/// sequence to finish the conversion.
static bool isAtomicConversion(Sema &S, Expr *From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle) {
const AtomicType *ToAtomic = ToType->getAs<AtomicType>();
if (!ToAtomic)
return false;
StandardConversionSequence InnerSCS;
if (!IsStandardConversion(S, From, ToAtomic->getValueType(),
InOverloadResolution, InnerSCS,
CStyle, /*AllowObjCWritebackConversion=*/false))
return false;
SCS.Second = InnerSCS.Second;
SCS.setToType(1, InnerSCS.getToType(1));
SCS.Third = InnerSCS.Third;
SCS.QualificationIncludesObjCLifetime
= InnerSCS.QualificationIncludesObjCLifetime;
SCS.setToType(2, InnerSCS.getToType(2));
return true;
}
static bool isFirstArgumentCompatibleWithType(ASTContext &Context,
CXXConstructorDecl *Constructor,
QualType Type) {

View File

@ -10,3 +10,26 @@ template<typename T> struct user {
};
user<int> u;
// Test overloading behavior of atomics.
struct A { };
int &ovl1(_Atomic(int));
long &ovl1(_Atomic(long));
float &ovl1(_Atomic(float));
double &ovl1(_Atomic(A const *const *));
short &ovl1(_Atomic(A **));
void test_overloading(int i, float f, _Atomic(int) ai, _Atomic(float) af,
long l, _Atomic(long) al, A const *const *acc,
A const ** ac, A **a) {
int& ir1 = ovl1(i);
int& ir2 = ovl1(ai);
long& lr1 = ovl1(l);
long& lr2 = ovl1(al);
float &fr1 = ovl1(f);
float &fr2 = ovl1(af);
double &dr1 = ovl1(acc);
double &dr2 = ovl1(ac);
short &sr1 = ovl1(a);
}