From: Douglas Gregor Date: Thu, 12 Apr 2012 17:51:55 +0000 (+0000) Subject: Compute standard conversion sequences for conversions to atomic X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f7ecc3016e6309a092493070d071489516b273c0;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154596 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7748b8c8a6..104134cdb0 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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()) { + T = Atomic->getValueType().getUnqualifiedType(); + Res = Owned(ImplicitCastExpr::Create(Context, T, CK_AtomicToNonAtomic, + Res.get(), 0, VK_RValue)); + } + return Res; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 40fb01ac30..89d4179fce 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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()) + 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()) { - // 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(); + 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) { diff --git a/test/SemaCXX/atomic-type.cxx b/test/SemaCXX/atomic-type.cxx index adaff2a0a2..18707eb8c5 100644 --- a/test/SemaCXX/atomic-type.cxx +++ b/test/SemaCXX/atomic-type.cxx @@ -10,3 +10,26 @@ template struct user { }; user 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); +}