Actually produce base paths for CastExprs of kind CK_DerivedToBase.
llvm-svn: 102259
This commit is contained in:
parent
5d270e8fa6
commit
a70cff624e
|
@ -1658,9 +1658,12 @@ private:
|
|||
void CheckBasePath() const {
|
||||
#ifndef NDEBUG
|
||||
switch (getCastKind()) {
|
||||
case CK_DerivedToBase:
|
||||
assert(!BasePath.empty() && "Cast kind should have a base path!");
|
||||
break;
|
||||
|
||||
// FIXME: We should add inheritance paths for these.
|
||||
case CK_BaseToDerived:
|
||||
case CK_DerivedToBase:
|
||||
case CK_UncheckedDerivedToBase:
|
||||
case CK_BaseToDerivedMemberPointer:
|
||||
case CK_DerivedToBaseMemberPointer:
|
||||
|
@ -1687,7 +1690,7 @@ private:
|
|||
case CK_MemberPointerToBoolean:
|
||||
case CK_AnyPointerToObjCPointerCast:
|
||||
case CK_AnyPointerToBlockPointerCast:
|
||||
assert(BasePath.empty() && "Cast kind shoudl not have a base path!");
|
||||
assert(BasePath.empty() && "Cast kind should not have a base path!");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -300,9 +300,35 @@ void StmtDumper::VisitExpr(Expr *Node) {
|
|||
DumpExpr(Node);
|
||||
}
|
||||
|
||||
static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) {
|
||||
if (Node->getBasePath().empty())
|
||||
return;
|
||||
|
||||
OS << " (";
|
||||
bool First = true;
|
||||
for (CXXBaseSpecifierArray::iterator I = Node->getBasePath().begin(),
|
||||
E = Node->getBasePath().end(); I != E; ++I) {
|
||||
const CXXBaseSpecifier *Base = *I;
|
||||
if (!First)
|
||||
OS << " -> ";
|
||||
|
||||
const CXXRecordDecl *RD =
|
||||
cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
|
||||
|
||||
if (Base->isVirtual())
|
||||
OS << "virtual ";
|
||||
OS << RD->getName();
|
||||
First = false;
|
||||
}
|
||||
|
||||
OS << ')';
|
||||
}
|
||||
|
||||
void StmtDumper::VisitCastExpr(CastExpr *Node) {
|
||||
DumpExpr(Node);
|
||||
OS << " <" << Node->getCastKindName() << ">";
|
||||
OS << " <" << Node->getCastKindName();
|
||||
DumpBasePath(OS, Node);
|
||||
OS << ">";
|
||||
}
|
||||
|
||||
void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
|
||||
|
@ -452,7 +478,9 @@ void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
|
|||
DumpExpr(Node);
|
||||
OS << " " << Node->getCastName()
|
||||
<< "<" << Node->getTypeAsWritten().getAsString() << ">"
|
||||
<< " <" << Node->getCastKindName() << ">";
|
||||
<< " <" << Node->getCastKindName();
|
||||
DumpBasePath(OS, Node);
|
||||
OS << ">";
|
||||
}
|
||||
|
||||
void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
|
||||
|
|
|
@ -1087,6 +1087,7 @@ public:
|
|||
QualType& ConvertedType, bool &IncompatibleObjC);
|
||||
bool CheckPointerConversion(Expr *From, QualType ToType,
|
||||
CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray& BasePath,
|
||||
bool IgnoreBaseAccess);
|
||||
bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
|
||||
bool InOverloadResolution,
|
||||
|
@ -2594,6 +2595,10 @@ public:
|
|||
bool IsDerivedFrom(QualType Derived, QualType Base);
|
||||
bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths);
|
||||
|
||||
// FIXME: I don't like this name.
|
||||
void BuildBasePathArray(const CXXBasePaths &Paths,
|
||||
CXXBaseSpecifierArray &BasePath);
|
||||
|
||||
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
|
||||
SourceLocation Loc, SourceRange Range,
|
||||
CXXBaseSpecifierArray *BasePath = 0,
|
||||
|
@ -4227,7 +4232,7 @@ public:
|
|||
/// CheckCastTypes - Check type constraints for casting between types under
|
||||
/// C semantics, or forward to CXXCheckCStyleCast in C++.
|
||||
bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr,
|
||||
CastExpr::CastKind &Kind,
|
||||
CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath,
|
||||
bool FunctionalStyle = false);
|
||||
|
||||
// CheckVectorCast - check type constraints for vectors.
|
||||
|
@ -4248,7 +4253,9 @@ public:
|
|||
/// CXXCheckCStyleCast - Check constraints of a C-style or function-style
|
||||
/// cast under C++ semantics.
|
||||
bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
|
||||
CastExpr::CastKind &Kind, bool FunctionalStyle);
|
||||
CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray &BasePath,
|
||||
bool FunctionalStyle);
|
||||
|
||||
/// CheckMessageArgumentTypes - Check types in an Obj-C message send.
|
||||
/// \param Method - May be null.
|
||||
|
|
|
@ -46,11 +46,13 @@ static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
CastExpr::CastKind &Kind);
|
||||
static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
||||
const SourceRange &OpRange,
|
||||
CastExpr::CastKind &Kind);
|
||||
CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray &BasePath);
|
||||
static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
||||
const SourceRange &OpRange,
|
||||
const SourceRange &DestRange,
|
||||
CastExpr::CastKind &Kind);
|
||||
CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray &BasePath);
|
||||
|
||||
static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
|
||||
|
||||
|
@ -98,7 +100,8 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
|
|||
QualType DestType, bool CStyle,
|
||||
const SourceRange &OpRange,
|
||||
unsigned &msg,
|
||||
CastExpr::CastKind &Kind);
|
||||
CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray &BasePath);
|
||||
static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
|
||||
bool CStyle, unsigned &msg);
|
||||
static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
||||
|
@ -150,30 +153,27 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
|||
|
||||
case tok::kw_dynamic_cast: {
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
// FIXME: Initialize base path!
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
if (!TypeDependent)
|
||||
CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind);
|
||||
CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind, BasePath);
|
||||
return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
|
||||
Kind, Ex, BasePath, DestTInfo,
|
||||
OpLoc));
|
||||
}
|
||||
case tok::kw_reinterpret_cast: {
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
// FIXME: Initialize base path!
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
if (!TypeDependent)
|
||||
CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
|
||||
return Owned(new (Context) CXXReinterpretCastExpr(
|
||||
DestType.getNonReferenceType(),
|
||||
Kind, Ex, BasePath, DestTInfo, OpLoc));
|
||||
Kind, Ex, CXXBaseSpecifierArray(),
|
||||
DestTInfo, OpLoc));
|
||||
}
|
||||
case tok::kw_static_cast: {
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
// FIXME: Initialize base path!
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
if (!TypeDependent)
|
||||
CheckStaticCast(*this, Ex, DestType, OpRange, Kind);
|
||||
CheckStaticCast(*this, Ex, DestType, OpRange, Kind, BasePath);
|
||||
|
||||
return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
|
||||
Kind, Ex, BasePath,
|
||||
|
@ -282,7 +282,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
|
|||
static void
|
||||
CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
||||
const SourceRange &OpRange,
|
||||
const SourceRange &DestRange, CastExpr::CastKind &Kind) {
|
||||
const SourceRange &DestRange, CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray &BasePath) {
|
||||
QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
|
||||
DestType = Self.Context.getCanonicalType(DestType);
|
||||
|
||||
|
@ -376,10 +377,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
// C++ 5.2.7p5
|
||||
// Upcasts are resolved statically.
|
||||
if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
|
||||
Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
|
||||
OpRange.getBegin(), OpRange);
|
||||
if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
|
||||
OpRange.getBegin(), OpRange,
|
||||
&BasePath))
|
||||
return;
|
||||
|
||||
Kind = CastExpr::CK_DerivedToBase;
|
||||
// Diagnostic already emitted on error.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -439,7 +442,8 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
/// implicit conversions explicit and getting rid of data loss warnings.
|
||||
void
|
||||
CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
||||
const SourceRange &OpRange, CastExpr::CastKind &Kind) {
|
||||
const SourceRange &OpRange, CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray &BasePath) {
|
||||
// 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".
|
||||
|
@ -453,8 +457,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
|
||||
unsigned msg = diag::err_bad_cxx_cast_generic;
|
||||
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
|
||||
Kind)
|
||||
!= TC_Success && msg != 0)
|
||||
Kind, BasePath) != TC_Success && msg != 0)
|
||||
Self.Diag(OpRange.getBegin(), msg) << CT_Static
|
||||
<< SrcExpr->getType() << DestType << OpRange;
|
||||
}
|
||||
|
@ -465,7 +468,8 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
|
||||
QualType DestType, bool CStyle,
|
||||
const SourceRange &OpRange, unsigned &msg,
|
||||
CastExpr::CastKind &Kind) {
|
||||
CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray &BasePath) {
|
||||
// The order the tests is not entirely arbitrary. There is one conversion
|
||||
// that can be handled in two different ways. Given:
|
||||
// struct A {};
|
||||
|
@ -1189,8 +1193,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
|||
return TC_Success;
|
||||
}
|
||||
|
||||
bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
|
||||
CastExpr::CastKind &Kind, bool FunctionalStyle) {
|
||||
bool
|
||||
Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
|
||||
CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray &BasePath,
|
||||
bool FunctionalStyle) {
|
||||
// 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".
|
||||
|
@ -1225,7 +1232,8 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
|
|||
|
||||
if (tcr == TC_NotApplicable) {
|
||||
// ... or if that is not possible, a static_cast, ignoring const, ...
|
||||
tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, Kind);
|
||||
tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, Kind,
|
||||
BasePath);
|
||||
if (tcr == TC_NotApplicable) {
|
||||
// ... and finally a reinterpret_cast, ignoring const.
|
||||
tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
|
||||
|
|
|
@ -423,7 +423,8 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
|
|||
// GCC does an implicit conversion to the pointer or integer ValType. This
|
||||
// can fail in some cases (1i -> int**), check for this error case now.
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind))
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, BasePath))
|
||||
return true;
|
||||
|
||||
// Okay, we have something that *can* be converted to the right type. Check
|
||||
|
|
|
@ -710,6 +710,29 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
|
|||
return DerivedRD->isDerivedFrom(BaseRD, Paths);
|
||||
}
|
||||
|
||||
void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
|
||||
CXXBaseSpecifierArray &BasePathArray) {
|
||||
assert(BasePathArray.empty() && "Base path array must be empty!");
|
||||
assert(Paths.isRecordingPaths() && "Must record paths!");
|
||||
|
||||
const CXXBasePath &Path = Paths.front();
|
||||
|
||||
// We first go backward and check if we have a virtual base.
|
||||
// FIXME: It would be better if CXXBasePath had the base specifier for
|
||||
// the nearest virtual base.
|
||||
unsigned Start = 0;
|
||||
for (unsigned I = Path.size(); I != 0; --I) {
|
||||
if (Path[I - 1].Base->isVirtual()) {
|
||||
Start = I - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now add all bases.
|
||||
for (unsigned I = Start, E = Path.size(); I != E; ++I)
|
||||
BasePathArray.push_back(Path[I].Base);
|
||||
}
|
||||
|
||||
/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
|
||||
/// conversion (where Derived and Base are class types) is
|
||||
/// well-formed, meaning that the conversion is unambiguous (and
|
||||
|
@ -737,23 +760,23 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
|
|||
(void)DerivationOkay;
|
||||
|
||||
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
|
||||
if (!InaccessibleBaseID)
|
||||
return false;
|
||||
|
||||
// Check that the base class can be accessed.
|
||||
switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
|
||||
InaccessibleBaseID)) {
|
||||
case AR_inaccessible:
|
||||
return true;
|
||||
case AR_accessible:
|
||||
case AR_dependent:
|
||||
case AR_delayed:
|
||||
// Build a base path if necessary.
|
||||
if (BasePath) {
|
||||
// FIXME: Do this!
|
||||
if (InaccessibleBaseID) {
|
||||
// Check that the base class can be accessed.
|
||||
switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
|
||||
InaccessibleBaseID)) {
|
||||
case AR_inaccessible:
|
||||
return true;
|
||||
case AR_accessible:
|
||||
case AR_dependent:
|
||||
case AR_delayed:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build a base path if necessary.
|
||||
if (BasePath)
|
||||
BuildBasePathArray(Paths, *BasePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We know that the derived-to-base conversion is ambiguous, and
|
||||
|
|
|
@ -3794,9 +3794,11 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context,
|
|||
/// CheckCastTypes - Check type constraints for casting between types.
|
||||
bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
|
||||
CastExpr::CastKind& Kind,
|
||||
CXXBaseSpecifierArray &BasePath,
|
||||
bool FunctionalStyle) {
|
||||
if (getLangOptions().CPlusPlus)
|
||||
return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle);
|
||||
return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, BasePath,
|
||||
FunctionalStyle);
|
||||
|
||||
DefaultFunctionArrayLvalueConversion(castExpr);
|
||||
|
||||
|
@ -3957,10 +3959,9 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
|
|||
Expr *castExpr = static_cast<Expr*>(Op.get());
|
||||
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
// FIXME: Initialize base path!
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
|
||||
Kind))
|
||||
Kind, BasePath))
|
||||
return ExprError();
|
||||
|
||||
Op.release();
|
||||
|
|
|
@ -501,9 +501,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
|
|||
//
|
||||
if (NumExprs == 1) {
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
// FIXME: Initialize base path!
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, /*FunctionalStyle=*/true))
|
||||
if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, BasePath,
|
||||
/*FunctionalStyle=*/true))
|
||||
return ExprError();
|
||||
|
||||
exprs.release();
|
||||
|
@ -1745,9 +1745,10 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
|
|||
|
||||
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
if (CheckPointerConversion(From, ToType, Kind, IgnoreBaseAccess))
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess))
|
||||
return true;
|
||||
ImpCastExprToType(From, ToType, Kind);
|
||||
ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1875,7 +1876,7 @@ QualType Sema::CheckPointerToMemberOperands(
|
|||
<< OpSpelling << (int)isIndirect)) {
|
||||
return QualType();
|
||||
}
|
||||
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
|
||||
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
|
||||
/*DetectVirtual=*/false);
|
||||
// FIXME: Would it be useful to print full ambiguity paths, or is that
|
||||
// overkill?
|
||||
|
@ -1888,7 +1889,11 @@ QualType Sema::CheckPointerToMemberOperands(
|
|||
// Cast LHS to type of use.
|
||||
QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
|
||||
bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid;
|
||||
ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue);
|
||||
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
BuildBasePathArray(Paths, BasePath);
|
||||
ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue,
|
||||
BasePath);
|
||||
}
|
||||
|
||||
if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) {
|
||||
|
|
|
@ -3457,18 +3457,20 @@ InitializationSequence::Perform(Sema &S,
|
|||
// We have a derived-to-base cast that produces either an rvalue or an
|
||||
// lvalue. Perform that cast.
|
||||
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
|
||||
// Casts to inaccessible base classes are allowed with C-style casts.
|
||||
bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast();
|
||||
if (S.CheckDerivedToBaseConversion(SourceType, Step->Type,
|
||||
CurInitExpr->getLocStart(),
|
||||
CurInitExpr->getSourceRange(), 0,
|
||||
IgnoreBaseAccess))
|
||||
CurInitExpr->getSourceRange(),
|
||||
&BasePath, IgnoreBaseAccess))
|
||||
return S.ExprError();
|
||||
|
||||
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type,
|
||||
CastExpr::CK_DerivedToBase,
|
||||
(Expr*)CurInit.release(),
|
||||
CXXBaseSpecifierArray(),
|
||||
BasePath,
|
||||
Step->Kind == SK_CastDerivedToBaseLValue));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1343,6 +1343,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
|||
/// error, or returns false otherwise.
|
||||
bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
|
||||
CastExpr::CastKind &Kind,
|
||||
CXXBaseSpecifierArray& BasePath,
|
||||
bool IgnoreBaseAccess) {
|
||||
QualType FromType = From->getType();
|
||||
|
||||
|
@ -1357,7 +1358,7 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
|
|||
// ambiguous or inaccessible conversion.
|
||||
if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
|
||||
From->getExprLoc(),
|
||||
From->getSourceRange(), 0,
|
||||
From->getSourceRange(), &BasePath,
|
||||
IgnoreBaseAccess))
|
||||
return true;
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@ struct B : A { } b;
|
|||
// CHECK: example1
|
||||
void example1() {
|
||||
// CHECK: A &ra =
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase> lvalue
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)> lvalue
|
||||
A &ra = b;
|
||||
// CHECK: A const &rca =
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp>
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase>
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
|
||||
const A& rca = b;
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,12 @@ struct X {
|
|||
void example2() {
|
||||
// CHECK: A const &rca =
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp>
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase>
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
|
||||
// CHECK: CallExpr{{.*}}B
|
||||
const A &rca = f();
|
||||
// CHECK: A const &r =
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp>
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase>
|
||||
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
|
||||
// CHECK: CXXMemberCallExpr{{.*}}'struct B'
|
||||
const A& r = x;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue