diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-01-27 00:58:17 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-01-27 00:58:17 +0000 |
commit | 14d0aee957f11b9613fa4312919bec3cc5456a1c (patch) | |
tree | b54c89ea196f1db30a542516edcf1f51543ab982 | |
parent | 52a80e19ad688091723a52ad53337767bb0ac684 (diff) |
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>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124340 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Sema/Sema.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 21 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 9 | ||||
-rw-r--r-- | test/CXX/expr/expr.cast/p4.cpp | 23 |
7 files changed, 82 insertions, 45 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 7d51fc34bc..5db08ba830 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -999,7 +999,8 @@ public: 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 @@ public: 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 @@ public: 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). diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index c492c2ac7d..afbfa17e77 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -320,7 +320,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { // 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 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, 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, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 062d4f697a..acdc15fdf2 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1737,11 +1737,11 @@ static ExprResult BuildCXXCastArgument(Sema &S, 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (!ICS.UserDefined.EllipsisConversion) { if (PerformImplicitConversion(From, BeforeToType, ICS.UserDefined.Before, AA_Converting, - IgnoreBaseAccess)) + CStyle)) return true; } @@ -1790,7 +1790,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From = CastArg.takeAs<Expr>(); return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, - AA_Converting, IgnoreBaseAccess); + AA_Converting, CStyle); } case ImplicitConversionSequence::AmbiguousConversion: @@ -1820,7 +1820,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From->getLocStart(), From->getSourceRange(), &BasePath, - IgnoreBaseAccess)) + CStyle)) return true; ImpCastExprToType(From, ToType.getNonReferenceType(), diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 00a13b54cf..b34fe2ff28 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2519,7 +2519,9 @@ static void TryReferenceInitialization(Sema &S, 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 @@ static void TryReferenceInitialization(Sema &S, // "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 @@ static void TryReferenceInitialization(Sema &S, // 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 @@ static void TryReferenceInitialization(Sema &S, 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 @@ InitializationSequence::InitializationSequence(Sema &S, 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 @@ InitializationSequence::Perform(Sema &S, } case SK_ConversionSequence: { - bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); - if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS, getAssignmentAction(Entity), - IgnoreBaseAccess)) + Kind.isCStyleOrFunctionalCast())) return ExprError(); CurInit.release(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 0b01332700..f33f42d856 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -46,7 +46,8 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, 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 @@ static ImplicitConversionSequence 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 @@ bool Sema::TryImplicitConversion(InitializationSequence &Sequence, 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, 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 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType, /// 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 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, 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 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, /// 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 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { // -- 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 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // 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 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, return TryImplicitConversion(S, From, ToType, SuppressUserConversions, /*AllowExplicit=*/false, - InOverloadResolution); + InOverloadResolution, + /*CStyle=*/false); } /// TryObjectArgumentInitialization - Try to initialize the object @@ -3379,7 +3388,8 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) { // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); } /// PerformContextuallyConvertToBool - Perform a contextual conversion @@ -3405,7 +3415,8 @@ TryContextuallyConvertToObjCId(Sema &S, Expr *From) { // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*CStyle=*/false); } /// PerformContextuallyConvertToObjCId - Perform a contextual conversion diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 78f8d5e05a..eed41cc396 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3085,7 +3085,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, 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 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, 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 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, 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 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, // 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); diff --git a/test/CXX/expr/expr.cast/p4.cpp b/test/CXX/expr/expr.cast/p4.cpp new file mode 100644 index 0000000000..d3f978571b --- /dev/null +++ b/test/CXX/expr/expr.cast/p4.cpp @@ -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; +} |