[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