forked from OSchip/llvm-project
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>. llvm-svn: 124340
This commit is contained in:
parent
92b7077f9e
commit
582813596a
|
@ -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).
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue