[cfe-commits] r88809 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaCXXCast.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/static-cast.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Sat Nov 14 13:15:49 PST 2009


Author: cornedbee
Date: Sat Nov 14 15:15:49 2009
New Revision: 88809

URL: http://llvm.org/viewvc/llvm-project?rev=88809&view=rev
Log:
- Have TryStaticImplicitCast set the cast kind to NoOp when binding a reference. CheckReferenceInit already inserts implicit casts to the necessary types. This fixes an assertion in CodeGen for some casts and brings a fix for PR5453 close, if I understand that bug correctly.
- Also, perform calculated implicit cast sequences if they're determined to work. This finally diagnoses static_cast to ambiguous or implicit bases and fixes two long-standing fixmes in the test case. For the C-style cast, this requires propagating the access check suppression pretty deep into other functions.
- Pass the expressions for TryStaticCast and TryStaticImplicitCast by reference. This should lead to a better AST being emitted for such casts, and also fixes a memory leak, because CheckReferenceInit and PerformImplicitConversion wrap the node passed to them. These wrappers were previously lost.

Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXCast.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/static-cast.cpp

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=88809&r1=88808&r2=88809&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sat Nov 14 15:15:49 2009
@@ -805,13 +805,15 @@
                            QualType& ConvertedType, bool &IncompatibleObjC);
   bool isObjCPointerConversion(QualType FromType, QualType ToType,
                                QualType& ConvertedType, bool &IncompatibleObjC);
-  bool CheckPointerConversion(Expr *From, QualType ToType, 
-                              CastExpr::CastKind &Kind);
+  bool CheckPointerConversion(Expr *From, QualType ToType,
+                              CastExpr::CastKind &Kind,
+                              bool IgnoreBaseAccess);
   bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
                                  bool InOverloadResolution,
                                  QualType &ConvertedType);
   bool CheckMemberPointerConversion(Expr *From, QualType ToType,
-                                    CastExpr::CastKind &Kind);
+                                    CastExpr::CastKind &Kind,
+                                    bool IgnoreBaseAccess);
   bool IsQualificationConversion(QualType FromType, QualType ToType);
   OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType,
                                UserDefinedConversionSequence& User,
@@ -2361,7 +2363,8 @@
   bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths);
   
   bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
-                                    SourceLocation Loc, SourceRange Range);
+                                    SourceLocation Loc, SourceRange Range,
+                                    bool IgnoreAccess = false);
   bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
                                     unsigned InaccessibleBaseID,
                                     unsigned AmbigiousBaseConvID,
@@ -3670,10 +3673,11 @@
                                  ImplicitConversionSequence& ICS);
   bool PerformImplicitConversion(Expr *&From, QualType ToType,
                                  const ImplicitConversionSequence& ICS,
-                                 const char *Flavor);
+                                 const char *Flavor,
+                                 bool IgnoreBaseAccess = false);
   bool PerformImplicitConversion(Expr *&From, QualType ToType,
                                  const StandardConversionSequence& SCS,
-                                 const char *Flavor);
+                                 const char *Flavor, bool IgnoreBaseAccess);
   
   bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
                                  const ImplicitConversionSequence& ICS,
@@ -3775,7 +3779,8 @@
                           bool SuppressUserConversions,
                           bool AllowExplicit,
                           bool ForceRValue,
-                          ImplicitConversionSequence *ICS = 0);
+                          ImplicitConversionSequence *ICS = 0,
+                          bool IgnoreBaseAccess = false);
 
   /// CheckCastTypes - Check type constraints for casting between types under
   /// C semantics, or forward to CXXCheckCStyleCast in C++.

Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=88809&r1=88808&r2=88809&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Sat Nov 14 15:15:49 2009
@@ -88,13 +88,13 @@
                                                   const SourceRange &OpRange,
                                                   unsigned &msg,
                                                   CastExpr::CastKind &Kind);
-static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr,
+static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr,
                                            QualType DestType, bool CStyle,
                                            const SourceRange &OpRange,
                                            unsigned &msg,
                                            CastExpr::CastKind &Kind,
                                            CXXMethodDecl *&ConversionDecl);
-static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
+static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
                                    QualType DestType, bool CStyle,
                                    const SourceRange &OpRange,
                                    unsigned &msg,
@@ -387,15 +387,14 @@
   // This test is outside everything else because it's the only case where
   // a non-lvalue-reference target type does not lead to decay.
   // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
-  if (DestType->isVoidType()) {
+  if (DestType->isVoidType())
     return;
-  }
 
   if (!DestType->isLValueReferenceType() && !DestType->isRecordType())
     Self.DefaultFunctionArrayConversion(SrcExpr);
 
   unsigned msg = diag::err_bad_cxx_cast_generic;
-  if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false,OpRange, msg, 
+  if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
                     Kind, ConversionDecl)
       != TC_Success && msg != 0)
     Self.Diag(OpRange.getBegin(), msg) << CT_Static
@@ -405,7 +404,7 @@
 /// TryStaticCast - Check if a static cast can be performed, and do so if
 /// possible. If @p CStyle, ignore access restrictions on hierarchy casting
 /// and casting away constness.
-static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
+static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
                                    QualType DestType, bool CStyle,
                                    const SourceRange &OpRange, unsigned &msg,
                                    CastExpr::CastKind &Kind,
@@ -430,7 +429,7 @@
   // C++ 5.2.9p5, reference downcast.
   // See the function for details.
   // DR 427 specifies that this is to be applied before paragraph 2.
-  tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange, 
+  tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange,
                                    msg, Kind);
   if (tcr != TC_NotApplicable)
     return tcr;
@@ -438,8 +437,10 @@
   // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
   //   reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
   tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, msg);
-  if (tcr != TC_NotApplicable)
+  if (tcr != TC_NotApplicable) {
+    Kind = CastExpr::CK_NoOp;
     return tcr;
+  }
 
   // C++ 5.2.9p2: An expression e can be explicitly converted to a type T
   //   [...] if the declaration "T t(e);" is well-formed, [...].
@@ -779,7 +780,7 @@
 ///   An expression e can be explicitly converted to a type T using a
 ///   @c static_cast if the declaration "T t(e);" is well-formed [...].
 TryCastResult
-TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
                       bool CStyle, const SourceRange &OpRange, unsigned &msg,
                       CastExpr::CastKind &Kind, 
                       CXXMethodDecl *&ConversionDecl) {
@@ -792,30 +793,39 @@
   }
 
   if (DestType->isReferenceType()) {
+    // All reference bindings insert implicit casts above that do the actual
+    // casting.
+    Kind = CastExpr::CK_NoOp;
+
     // At this point of CheckStaticCast, if the destination is a reference,
     // this has to work. There is no other way that works.
     // On the other hand, if we're checking a C-style cast, we've still got
-    // the reinterpret_cast way. In that case, we pass an ICS so we don't
-    // get error messages.
-    ImplicitConversionSequence ICS;
-    bool failed = Self.CheckReferenceInit(SrcExpr, DestType,
-                                          OpRange.getBegin(),
-                                          /*SuppressUserConversions=*/false,
-                                          /*AllowExplicit=*/false,
-                                          /*ForceRValue=*/false,
-                                          CStyle ? &ICS : 0);
-    if (!failed)
+    // the reinterpret_cast way. So in C-style mode, we first try the call
+    // with an ICS to suppress errors.
+    if (CStyle) {
+      ImplicitConversionSequence ICS;
+      if(Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
+                                 /*SuppressUserConversions=*/false,
+                                 /*AllowExplicit=*/false, /*ForceRValue=*/false,
+                                 &ICS))
+        return TC_NotApplicable;
+    }
+    // Now we're committed either way.
+    if(!Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
+                                /*SuppressUserConversions=*/false,
+                                /*AllowExplicit=*/false,
+                                /*ForceRValue=*/false, 0,
+                                /*IgnoreBaseAccess=*/CStyle))
       return TC_Success;
-    if (CStyle)
-      return TC_NotApplicable;
-    // If we didn't pass the ICS, we already got an error message.
+
+    // We already got an error message.
     msg = 0;
     return TC_Failed;
   }
 
   if (DestType->isRecordType()) {
     if (CXXConstructorDecl *Constructor
-          = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1, 
+          = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1,
                                                 OpRange.getBegin(),
                                                 Sema::IK_Direct)) {
       ConversionDecl = Constructor;
@@ -825,7 +835,7 @@
     
     return TC_NotApplicable;
   }
-  
+
   // FIXME: To get a proper error from invalid conversions here, we need to
   // reimplement more of this.
   // FIXME: This does not actually perform the conversion, and thus does not
@@ -841,18 +851,11 @@
   if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
     return TC_NotApplicable;
 
-  if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) {
-    ConversionDecl = cast<CXXMethodDecl>(ICS.UserDefined.ConversionFunction);
-    if (isa<CXXConstructorDecl>(ConversionDecl))
-      Kind = CastExpr::CK_ConstructorConversion;
-    else if (isa<CXXConversionDecl>(ConversionDecl))
-      Kind = CastExpr::CK_UserDefinedConversion;
-  } else if (ICS.ConversionKind ==
-              ImplicitConversionSequence::StandardConversion) {
-    // FIXME: Set the cast kind depending on which types of conversions we have.
-  }
-
-  return TC_Success;
+  // The conversion is possible, so commit to it.
+  msg = 0;
+  return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, "casting",
+                                        /*IgnoreBaseAccess*/CStyle) ?
+      TC_Failed : TC_Success;
 }
 
 /// TryConstCast - See if a const_cast from source to destination is allowed,

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=88809&r1=88808&r2=88809&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Nov 14 15:15:49 2009
@@ -698,6 +698,8 @@
   (void)DerivationOkay;
   
   if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
+    if (InaccessibleBaseID == 0)
+      return false;
     // Check that the base class can be accessed.
     return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
                                 Name);
@@ -728,9 +730,11 @@
 
 bool
 Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
-                                   SourceLocation Loc, SourceRange Range) {
+                                   SourceLocation Loc, SourceRange Range,
+                                   bool IgnoreAccess) {
   return CheckDerivedToBaseConversion(Derived, Base,
-                                      diag::err_conv_to_inaccessible_base,
+                                      IgnoreAccess ? 0 :
+                                        diag::err_conv_to_inaccessible_base,
                                       diag::err_ambiguous_derived_to_base_conv,
                                       Loc, Range, DeclarationName());
 }
@@ -3693,12 +3697,15 @@
 /// When @p AllowExplicit, we also permit explicit user-defined
 /// conversion functions.
 /// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
+/// When @p IgnoreBaseAccess, we don't do access control on to-base conversion.
+/// This is used when this is called from a C-style cast.
 bool
 Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
                          SourceLocation DeclLoc,
                          bool SuppressUserConversions,
                          bool AllowExplicit, bool ForceRValue,
-                         ImplicitConversionSequence *ICS) {
+                         ImplicitConversionSequence *ICS,
+                         bool IgnoreBaseAccess) {
   assert(DeclType->isReferenceType() && "Reference init needs a reference");
 
   QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
@@ -3913,7 +3920,8 @@
     // actually happens.
     if (DerivedToBase)
       return CheckDerivedToBaseConversion(T2, T1, DeclLoc,
-                                          Init->getSourceRange());
+                                          Init->getSourceRange(),
+                                          IgnoreBaseAccess);
     else
       return false;
   }

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=88809&r1=88808&r2=88809&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sat Nov 14 15:15:49 2009
@@ -1068,10 +1068,11 @@
 bool
 Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
                                 const ImplicitConversionSequence &ICS,
-                                const char* Flavor) {
+                                const char* Flavor, bool IgnoreBaseAccess) {
   switch (ICS.ConversionKind) {
   case ImplicitConversionSequence::StandardConversion:
-    if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor))
+    if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor,
+                                  IgnoreBaseAccess))
       return true;
     break;
 
@@ -1102,7 +1103,8 @@
       // Whatch out for elipsis conversion.
       if (!ICS.UserDefined.EllipsisConversion) {
         if (PerformImplicitConversion(From, BeforeToType, 
-                                      ICS.UserDefined.Before, "converting"))
+                                      ICS.UserDefined.Before, "converting",
+                                      IgnoreBaseAccess))
           return true;
       }
     
@@ -1152,7 +1154,7 @@
 bool
 Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
                                 const StandardConversionSequence& SCS,
-                                const char *Flavor) {
+                                const char *Flavor, bool IgnoreBaseAccess) {
   // 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,
@@ -1280,7 +1282,7 @@
 
     
     CastExpr::CastKind Kind = CastExpr::CK_Unknown;
-    if (CheckPointerConversion(From, ToType, Kind))
+    if (CheckPointerConversion(From, ToType, Kind, IgnoreBaseAccess))
       return true;
     ImpCastExprToType(From, ToType, Kind);
     break;
@@ -1288,7 +1290,7 @@
   
   case ICK_Pointer_Member: {
     CastExpr::CastKind Kind = CastExpr::CK_Unknown;
-    if (CheckMemberPointerConversion(From, ToType, Kind))
+    if (CheckMemberPointerConversion(From, ToType, Kind, IgnoreBaseAccess))
       return true;
     if (CheckExceptionSpecCompatibility(From, ToType))
       return true;
@@ -1303,7 +1305,8 @@
     if (CheckDerivedToBaseConversion(From->getType(), 
                                      ToType.getNonReferenceType(),
                                      From->getLocStart(),
-                                     From->getSourceRange()))
+                                     From->getSourceRange(),
+                                     IgnoreBaseAccess))
       return true;
     ImpCastExprToType(From, ToType.getNonReferenceType(), 
                       CastExpr::CK_DerivedToBase);

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=88809&r1=88808&r2=88809&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Nov 14 15:15:49 2009
@@ -1155,7 +1155,8 @@
 /// true. It returns true and produces a diagnostic if there was an
 /// error, or returns false otherwise.
 bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
-                                  CastExpr::CastKind &Kind) {
+                                  CastExpr::CastKind &Kind,
+                                  bool IgnoreBaseAccess) {
   QualType FromType = From->getType();
 
   if (const PointerType *FromPtrType = FromType->getAs<PointerType>())
@@ -1169,7 +1170,8 @@
         // ambiguous or inaccessible conversion.
         if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
                                          From->getExprLoc(),
-                                         From->getSourceRange()))
+                                         From->getSourceRange(),
+                                         IgnoreBaseAccess))
           return true;
         
         // The conversion was successful.
@@ -1238,7 +1240,9 @@
 /// true and produces a diagnostic if there was an error, or returns false
 /// otherwise.
 bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
-                                        CastExpr::CastKind &Kind) {
+                                        CastExpr::CastKind &Kind,
+                                        bool IgnoreBaseAccess) {
+  (void)IgnoreBaseAccess;
   QualType FromType = From->getType();
   const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
   if (!FromPtrType) {

Modified: cfe/trunk/test/SemaCXX/static-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-cast.cpp?rev=88809&r1=88808&r2=88809&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/static-cast.cpp (original)
+++ cfe/trunk/test/SemaCXX/static-cast.cpp Sat Nov 14 15:15:49 2009
@@ -5,7 +5,7 @@
 struct C1 : public virtual B {};    // Single virtual base.
 struct C2 : public virtual B {};
 struct D : public C1, public C2 {}; // Diamond
-struct E : private A {};            // Single private base. expected-note 2 {{'private' inheritance specifier here}}
+struct E : private A {};            // Single private base. expected-note 3 {{'private' inheritance specifier here}}
 struct F : public C1 {};            // Single path to B with virtual.
 struct G1 : public B {};
 struct G2 : public B {};
@@ -57,8 +57,8 @@
   // Bad code below
 
   (void)static_cast<void*>((const int*)0); // expected-error {{static_cast from 'int const *' to 'void *' is not allowed}}
-  //(void)static_cast<A*>((E*)0); // {{static_cast from 'struct E *' to 'struct A *' is not allowed}}
-  //(void)static_cast<A*>((H*)0); // {{static_cast from 'struct H *' to 'struct A *' is not allowed}}
+  (void)static_cast<A*>((E*)0); // expected-error {{inaccessible base class 'struct A'}}
+  (void)static_cast<A*>((H*)0); // expected-error {{ambiguous conversion}}
   (void)static_cast<int>((int*)0); // expected-error {{static_cast from 'int *' to 'int' is not allowed}}
   (void)static_cast<A**>((B**)0); // expected-error {{static_cast from 'struct B **' to 'struct A **' is not allowed}}
   (void)static_cast<char&>(i); // expected-error {{non-const lvalue reference to type 'char' cannot be initialized with a value of type 'int'}}





More information about the cfe-commits mailing list