[cfe-commits] r124340 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaCXXCast.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp test/CXX/expr/expr.cast/p4.cpp

Douglas Gregor dgregor at apple.com
Wed Jan 26 16:58:17 PST 2011


Author: dgregor
Date: Wed Jan 26 18:58:17 2011
New Revision: 124340

URL: http://llvm.org/viewvc/llvm-project?rev=124340&view=rev
Log:
Fix a horrible bug in our handling of C-style casting, where a C-style
derived-to-base cast that also casts away constness (one of the cases
for static_cast followed by const_cast) would be treated as a bit-cast
rather than a derived-to-base class, causing miscompiles and
heartburn.

Fixes <rdar://problem/8913298>.

Added:
    cfe/trunk/test/CXX/expr/expr.cast/p4.cpp
Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXCast.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=124340&r1=124339&r2=124340&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jan 26 18:58:17 2011
@@ -999,7 +999,8 @@
                              Expr *From,
                              bool SuppressUserConversions,
                              bool AllowExplicit,
-                             bool InOverloadResolution);
+                             bool InOverloadResolution,
+                             bool CStyle);
 
   bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
   bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
@@ -1023,7 +1024,8 @@
                                     CastKind &Kind,
                                     CXXCastPath &BasePath,
                                     bool IgnoreBaseAccess);
-  bool IsQualificationConversion(QualType FromType, QualType ToType);
+  bool IsQualificationConversion(QualType FromType, QualType ToType,
+                                 bool CStyle);
   bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
 
 
@@ -4559,10 +4561,11 @@
   bool PerformImplicitConversion(Expr *&From, QualType ToType,
                                  const ImplicitConversionSequence& ICS,
                                  AssignmentAction Action,
-                                 bool IgnoreBaseAccess = false);
+                                 bool CStyle = false);
   bool PerformImplicitConversion(Expr *&From, QualType ToType,
                                  const StandardConversionSequence& SCS,
-                                 AssignmentAction Action,bool IgnoreBaseAccess);
+                                 AssignmentAction Action,
+                                 bool CStyle);
 
   /// the following "Check" methods will return a valid/converted QualType
   /// or a null QualType (indicating an error diagnostic was issued).

Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=124340&r1=124339&r2=124340&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Wed Jan 26 18:58:17 2011
@@ -320,7 +320,7 @@
 
   // Test if they're compatible.
   return SrcConstruct != DestConstruct &&
-    !Self.IsQualificationConversion(SrcConstruct, DestConstruct);
+    !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false);
 }
 
 /// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
@@ -1035,8 +1035,7 @@
   
   InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
   InitializationKind InitKind
-    = InitializationKind::CreateCast(/*FIXME:*/OpRange, 
-                                                               CStyle);    
+    = InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle);    
   InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
 
   // At this point of CheckStaticCast, if the destination is a reference,

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124340&r1=124339&r2=124340&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Jan 26 18:58:17 2011
@@ -1737,11 +1737,11 @@
 bool
 Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
                                 const ImplicitConversionSequence &ICS,
-                                AssignmentAction Action, bool IgnoreBaseAccess) {
+                                AssignmentAction Action, bool CStyle) {
   switch (ICS.getKind()) {
   case ImplicitConversionSequence::StandardConversion:
     if (PerformImplicitConversion(From, ToType, ICS.Standard, Action,
-                                  IgnoreBaseAccess))
+                                  CStyle))
       return true;
     break;
 
@@ -1772,7 +1772,7 @@
       if (!ICS.UserDefined.EllipsisConversion) {
         if (PerformImplicitConversion(From, BeforeToType, 
                                       ICS.UserDefined.Before, AA_Converting,
-                                      IgnoreBaseAccess))
+                                      CStyle))
           return true;
       }
     
@@ -1790,7 +1790,7 @@
       From = CastArg.takeAs<Expr>();
 
       return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
-                                       AA_Converting, IgnoreBaseAccess);
+                                       AA_Converting, CStyle);
   }
 
   case ImplicitConversionSequence::AmbiguousConversion:
@@ -1820,7 +1820,7 @@
 bool
 Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
                                 const StandardConversionSequence& SCS,
-                                AssignmentAction Action, bool IgnoreBaseAccess) {
+                                AssignmentAction Action, bool CStyle) {
   // Overall FIXME: we are recomputing too many types here and doing far too
   // much extra work. What this means is that we need to keep track of more
   // information that is computed when we try the implicit conversion initially,
@@ -1982,7 +1982,7 @@
     
     CastKind Kind = CK_Invalid;
     CXXCastPath BasePath;
-    if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess))
+    if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
       return true;
     ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath);
     break;
@@ -1991,8 +1991,7 @@
   case ICK_Pointer_Member: {
     CastKind Kind = CK_Invalid;
     CXXCastPath BasePath;
-    if (CheckMemberPointerConversion(From, ToType, Kind, BasePath,
-                                     IgnoreBaseAccess))
+    if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle))
       return true;
     if (CheckExceptionSpecCompatibility(From, ToType))
       return true;
@@ -2022,7 +2021,7 @@
                                      From->getLocStart(),
                                      From->getSourceRange(), 
                                      &BasePath,
-                                     IgnoreBaseAccess))
+                                     CStyle))
       return true;
 
     ImpCastExprToType(From, ToType.getNonReferenceType(),

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=124340&r1=124339&r2=124340&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Jan 26 18:58:17 2011
@@ -2519,7 +2519,9 @@
   bool T1Function = T1->isFunctionType();
   if (isLValueRef || T1Function) {
     if (InitCategory.isLValue() && 
-        RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+        (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification ||
+         (Kind.isCStyleOrFunctionalCast() && 
+          RefRelationship == Sema::Ref_Related))) {
       //   - is an lvalue (but is not a bit-field), and "cv1 T1" is 
       //     reference-compatible with "cv2 T2," or
       //
@@ -2593,7 +2595,9 @@
   //        "cv1 T1" is reference-compatible with "cv2 T2"
   // Note: functions are handled below.
   if (!T1Function &&
-      RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification &&
+      (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification ||
+       (Kind.isCStyleOrFunctionalCast() && 
+        RefRelationship == Sema::Ref_Related)) &&
       (InitCategory.isXValue() ||
        (InitCategory.isPRValue() && T2->isRecordType()) ||
        (InitCategory.isPRValue() && T2->isArrayType()))) {
@@ -2630,9 +2634,6 @@
   //         reference-related to T2, and can be implicitly converted to an 
   //         xvalue, class prvalue, or function lvalue of type "cv3 T3",
   //         where "cv1 T1" is reference-compatible with "cv3 T3",
-  //
-  // FIXME: Need to handle xvalue, class prvalue, etc. cases in 
-  // TryRefInitWithConversionFunction.
   if (T2->isRecordType()) {
     if (RefRelationship == Sema::Ref_Incompatible) {
       ConvOvlResult = TryRefInitWithConversionFunction(S, Entity,
@@ -2665,7 +2666,8 @@
   if (S.TryImplicitConversion(Sequence, TempEntity, Initializer,
                               /*SuppressUserConversions*/ false,
                               AllowExplicit,
-                              /*FIXME:InOverloadResolution=*/false)) {
+                              /*FIXME:InOverloadResolution=*/false,
+                              /*CStyle=*/Kind.isCStyleOrFunctionalCast())) {
     // FIXME: Use the conversion function set stored in ICS to turn
     // this into an overloading ambiguity diagnostic. However, we need
     // to keep that set as an OverloadCandidateSet rather than as some
@@ -3184,7 +3186,8 @@
   if (S.TryImplicitConversion(*this, Entity, Initializer,
                               /*SuppressUserConversions*/ true,
                               /*AllowExplicitConversions*/ false,
-                              /*InOverloadResolution*/ false))
+                              /*InOverloadResolution*/ false,
+                              /*CStyle=*/Kind.isCStyleOrFunctionalCast()))
   {
     if (Initializer->getType() == Context.OverloadTy)
       SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
@@ -3844,11 +3847,9 @@
     }
 
     case SK_ConversionSequence: {
-      bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast();
-
       if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS,
                                       getAssignmentAction(Entity),
-                                      IgnoreBaseAccess))
+                                      Kind.isCStyleOrFunctionalCast()))
         return ExprError();
         
       CurInit.release();

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=124340&r1=124339&r2=124340&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan 26 18:58:17 2011
@@ -46,7 +46,8 @@
 
 static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
                                  bool InOverloadResolution,
-                                 StandardConversionSequence &SCS);
+                                 StandardConversionSequence &SCS,
+                                 bool CStyle);
 static OverloadingResult
 IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
                         UserDefinedConversionSequence& User,
@@ -744,10 +745,11 @@
 TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
                       bool SuppressUserConversions,
                       bool AllowExplicit, 
-                      bool InOverloadResolution) {
+                      bool InOverloadResolution,
+                      bool CStyle) {
   ImplicitConversionSequence ICS;
   if (IsStandardConversion(S, From, ToType, InOverloadResolution,
-                           ICS.Standard)) {
+                           ICS.Standard, CStyle)) {
     ICS.setStandard();
     return ICS;
   }
@@ -858,12 +860,14 @@
                                  Expr *Initializer,
                                  bool SuppressUserConversions,
                                  bool AllowExplicitConversions,
-                                 bool InOverloadResolution) {
+                                 bool InOverloadResolution,
+                                 bool CStyle) {
   ImplicitConversionSequence ICS
     = clang::TryImplicitConversion(*this, Initializer, Entity.getType(),
                                    SuppressUserConversions,
                                    AllowExplicitConversions, 
-                                   InOverloadResolution);
+                                   InOverloadResolution,
+                                   CStyle);
   if (ICS.isBad()) return true;
 
   // Perform the actual conversion.
@@ -891,7 +895,8 @@
   ICS = clang::TryImplicitConversion(*this, From, ToType,
                                      /*SuppressUserConversions=*/false,
                                      AllowExplicit,
-                                     /*InOverloadResolution=*/false);
+                                     /*InOverloadResolution=*/false,
+                                     /*CStyle=*/false);
   return PerformImplicitConversion(From, ToType, ICS, Action);
 }
   
@@ -999,7 +1004,8 @@
 /// routine will return false and the value of SCS is unspecified.
 static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
                                  bool InOverloadResolution,
-                                 StandardConversionSequence &SCS) {
+                                 StandardConversionSequence &SCS,
+                                 bool CStyle) {
   QualType FromType = From->getType();
   
   // Standard conversions (C++ [conv])
@@ -1189,7 +1195,7 @@
   QualType CanonFrom;
   QualType CanonTo;
   // The third conversion can be a qualification conversion (C++ 4p1).
-  if (S.IsQualificationConversion(FromType, ToType)) {
+  if (S.IsQualificationConversion(FromType, ToType, CStyle)) {
     SCS.Third = ICK_Qualification;
     FromType = ToType;
     CanonFrom = S.Context.getCanonicalType(FromType);
@@ -1984,7 +1990,8 @@
 /// an rvalue of type FromType to ToType is a qualification conversion
 /// (C++ 4.4).
 bool
-Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
+Sema::IsQualificationConversion(QualType FromType, QualType ToType, 
+                                bool CStyle) {
   FromType = Context.getCanonicalType(FromType);
   ToType = Context.getCanonicalType(ToType);
 
@@ -2009,12 +2016,12 @@
 
     //   -- for every j > 0, if const is in cv 1,j then const is in cv
     //      2,j, and similarly for volatile.
-    if (!ToType.isAtLeastAsQualifiedAs(FromType))
+    if (!CStyle && !ToType.isAtLeastAsQualifiedAs(FromType))
       return false;
 
     //   -- if the cv 1,j and cv 2,j are different, then const is in
     //      every cv for 0 < k < j.
-    if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers()
+    if (!CStyle && FromType.getCVRQualifiers() != ToType.getCVRQualifiers()
         && !PreviousToQualsIncludeConst)
       return false;
 
@@ -3156,7 +3163,8 @@
   //   and does not constitute a conversion.
   ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions,
                               /*AllowExplicit=*/false,
-                              /*InOverloadResolution=*/false);
+                              /*InOverloadResolution=*/false,
+                              /*CStyle=*/false);
 
   // Of course, that's still a reference binding.
   if (ICS.isStandard()) {
@@ -3195,7 +3203,8 @@
   return TryImplicitConversion(S, From, ToType,
                                SuppressUserConversions,
                                /*AllowExplicit=*/false,
-                               InOverloadResolution);
+                               InOverloadResolution,
+                               /*CStyle=*/false);
 }
 
 /// TryObjectArgumentInitialization - Try to initialize the object
@@ -3379,7 +3388,8 @@
                                // FIXME: Are these flags correct?
                                /*SuppressUserConversions=*/false,
                                /*AllowExplicit=*/true,
-                               /*InOverloadResolution=*/false);
+                               /*InOverloadResolution=*/false,
+                               /*CStyle=*/false);
 }
 
 /// PerformContextuallyConvertToBool - Perform a contextual conversion
@@ -3405,7 +3415,8 @@
                                // FIXME: Are these flags correct?
                                /*SuppressUserConversions=*/false,
                                /*AllowExplicit=*/true,
-                               /*InOverloadResolution=*/false);
+                               /*InOverloadResolution=*/false,
+                               /*CStyle=*/false);
 }
 
 /// PerformContextuallyConvertToObjCId - Perform a contextual conversion

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=124340&r1=124339&r2=124340&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jan 26 18:58:17 2011
@@ -3085,7 +3085,7 @@
 
   if (ParamType->isPointerType() && 
       !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
-      S.IsQualificationConversion(ArgType, ParamType)) {
+      S.IsQualificationConversion(ArgType, ParamType, false)) {
     // For pointer-to-object types, qualification conversions are
     // permitted.
   } else {
@@ -3429,7 +3429,8 @@
                                                             ParamType, 
                                                             Arg, Converted);
 
-    if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType())) {
+    if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(),
+                                  false)) {
       ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg));
     } else if (!Context.hasSameUnqualifiedType(ArgType,
                                            ParamType.getNonReferenceType())) {
@@ -3492,7 +3493,7 @@
 
   if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
     // Types match exactly: nothing more to do here.
-  } else if (IsQualificationConversion(ArgType, ParamType)) {
+  } else if (IsQualificationConversion(ArgType, ParamType, false)) {
     ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg));
   } else {
     // We can't perform this conversion.
@@ -3597,7 +3598,7 @@
       // the element type on the parameter could be more qualified than the
       // element type in the expression we constructed.
       if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
-                                    ParamType.getUnqualifiedType())) {
+                                    ParamType.getUnqualifiedType(), false)) {
         Expr *RefE = RefExpr.takeAs<Expr>();
         ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), CK_NoOp);
         RefExpr = Owned(RefE);

Added: cfe/trunk/test/CXX/expr/expr.cast/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.cast/p4.cpp?rev=124340&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.cast/p4.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.cast/p4.cpp Wed Jan 26 18:58:17 2011
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
+
+struct A { int x; };
+struct B { int y; };
+struct C : A, B { };
+
+// CHECK: casting_away_constness
+void casting_away_constness(const B &b, const C &c, const B *bp, const C *cp) {
+  // CHECK: DerivedToBase (B)
+  // CHECK: DeclRefExpr {{.*}} ParmVar='c'
+  (void)(B&)c;
+  // CHECK: BaseToDerived (B)
+  // CHECK: DeclRefExpr {{.*}} ParmVar='b'
+  (void)(C&)b;
+  // CHECK: DerivedToBase (B)
+  // CHECK: DeclRefExpr {{.*}} ParmVar='cp'
+  (void)(B*)cp;
+  // CHECK: BaseToDerived (B)
+  // CHECK: DeclRefExpr {{.*}} ParmVar='bp'
+  (void)(C*)bp;
+  // CHECK: ReturnStmt
+  return;
+}





More information about the cfe-commits mailing list