diff options
-rw-r--r-- | lib/Sema/Sema.h | 19 | ||||
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 75 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 10 | ||||
-rw-r--r-- | test/SemaCXX/static-cast.cpp | 6 |
6 files changed, 83 insertions, 60 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 427a21d575..b412882b85 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -805,13 +805,15 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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++. diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 4d46b32c22..d055dd4c58 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -88,13 +88,13 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, 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 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // 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 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /// 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 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, // 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 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, // 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 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, /// 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 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, } 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 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, 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 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, 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, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e631d7ba2a..4c06485703 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -698,6 +698,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, (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 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, 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 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, /// 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 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // actually happens. if (DerivedToBase) return CheckDerivedToBaseConversion(T2, T1, DeclLoc, - Init->getSourceRange()); + Init->getSourceRange(), + IgnoreBaseAccess); else return false; } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 0689c6cce9..3e07f3495e 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1068,10 +1068,11 @@ Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), - From->getSourceRange())) + From->getSourceRange(), + IgnoreBaseAccess)) return true; ImpCastExprToType(From, ToType.getNonReferenceType(), CastExpr::CK_DerivedToBase); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 53e64dfc68..b324068ea8 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1155,7 +1155,8 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, /// 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 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, // 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 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, /// 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) { diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp index 5d4f1bfcdf..68f1dff276 100644 --- a/test/SemaCXX/static-cast.cpp +++ b/test/SemaCXX/static-cast.cpp @@ -5,7 +5,7 @@ struct B : public A {}; // Single public base. 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 @@ void t_529_2() // 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'}} |