Allow downcasts of pointers to Objective-C interfaces, with a
warning. This matches GCC's behavior and addresses
<rdar://problem/6458293>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61246 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 0534f3d..1fac775 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -382,7 +382,7 @@
bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
- QualType& ConvertedType);
+ QualType& ConvertedType, bool &IncompatibleObjC);
bool CheckPointerConversion(Expr *From, QualType ToType);
bool IsQualificationConversion(QualType FromType, QualType ToType);
bool IsUserDefinedConversion(Expr *From, QualType ToType,
@@ -1260,9 +1260,11 @@
bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
- bool PerformImplicitConversion(Expr *&From, QualType ToType);
+ bool PerformImplicitConversion(Expr *&From, QualType ToType,
+ const char *Flavor);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
- const StandardConversionSequence& SCS);
+ const StandardConversionSequence& SCS,
+ const char *Flavor);
/// 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/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 925a7bb..6c1af5f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -744,7 +744,10 @@
// Get the type before calling CheckSingleAssignmentConstraints(), since
// it can promote the expression.
QualType InitType = Init->getType();
-
+
+ if (getLangOptions().CPlusPlus)
+ return PerformCopyInitialization(Init, DeclType, "initializing");
+
AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init);
return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
InitType, Init, "initializing");
@@ -843,7 +846,7 @@
// destination type.
// FIXME: We're pretending to do copy elision here; return to
// this when we have ASTs for such things.
- if (!PerformImplicitConversion(Init, DeclType))
+ if (!PerformImplicitConversion(Init, DeclType, "initializing"))
return false;
return Diag(InitLoc, diag::err_typecheck_convert_incompatible)
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 7be76bb..f2f02e2 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1838,7 +1838,7 @@
*ICS = TryImplicitConversion(Init, T1, SuppressUserConversions);
return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
} else {
- return PerformImplicitConversion(Init, T1);
+ return PerformImplicitConversion(Init, T1, "initializing");
}
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d31855e..da03548 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -2138,7 +2138,8 @@
// C++ 5.17p3: If the left operand is not of class type, the
// expression is implicitly converted (C++ 4) to the
// cv-unqualified type of the left operand.
- if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType()))
+ if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType(),
+ "assigning"))
return Incompatible;
else
return Compatible;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index e951016..e18f143 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -708,14 +708,16 @@
/// PerformImplicitConversion - Perform an implicit conversion of the
/// expression From to the type ToType. Returns true if there was an
/// error, false otherwise. The expression From is replaced with the
-/// converted expression.
+/// converted expression. Flavor is the kind of conversion we're
+/// performing, used in the error message.
bool
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType)
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ const char *Flavor)
{
ImplicitConversionSequence ICS = TryImplicitConversion(From, ToType);
switch (ICS.ConversionKind) {
case ImplicitConversionSequence::StandardConversion:
- if (PerformImplicitConversion(From, ToType, ICS.Standard))
+ if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor))
return true;
break;
@@ -742,10 +744,12 @@
/// expression From to the type ToType by following the standard
/// conversion sequence SCS. Returns true if there was an error, false
/// otherwise. The expression From is replaced with the converted
-/// expression.
+/// expression. Flavor is the context in which we're performing this
+/// conversion, for use in error messages.
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
- const StandardConversionSequence& SCS)
+ const StandardConversionSequence& SCS,
+ const char *Flavor)
{
// 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
@@ -808,6 +812,14 @@
break;
case ICK_Pointer_Conversion:
+ if (SCS.IncompatibleObjC) {
+ // Diagnose incompatible Objective-C conversions
+ Diag(From->getSourceRange().getBegin(),
+ diag::ext_typecheck_convert_incompatible_pointer)
+ << From->getType() << ToType << Flavor
+ << From->getSourceRange();
+ }
+
if (CheckPointerConversion(From, ToType))
return true;
ImpCastExprToType(From, ToType);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 3671711..f03c7a4 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -419,6 +419,7 @@
// Standard conversions (C++ [conv])
SCS.setAsIdentityConversion();
SCS.Deprecated = false;
+ SCS.IncompatibleObjC = false;
SCS.FromTypePtr = FromType.getAsOpaquePtr();
SCS.CopyConstructor = 0;
@@ -494,6 +495,7 @@
// point promotion, integral conversion, floating point conversion,
// floating-integral conversion, pointer conversion,
// pointer-to-member conversion, or boolean conversion (C++ 4p1).
+ bool IncompatibleObjC = false;
if (Context.getCanonicalType(FromType).getUnqualifiedType() ==
Context.getCanonicalType(ToType).getUnqualifiedType()) {
// The unqualified versions of the types are the same: there's no
@@ -533,8 +535,10 @@
FromType = ToType.getUnqualifiedType();
}
// Pointer conversions (C++ 4.10).
- else if (IsPointerConversion(From, FromType, ToType, FromType)) {
+ else if (IsPointerConversion(From, FromType, ToType, FromType,
+ IncompatibleObjC)) {
SCS.Second = ICK_Pointer_Conversion;
+ SCS.IncompatibleObjC = IncompatibleObjC;
}
// FIXME: Pointer to member conversions (4.11).
// Boolean conversions (C++ 4.12).
@@ -751,10 +755,15 @@
/// appropriate overloading rules for Objective-C, we may want to
/// split the Objective-C checks into a different routine; however,
/// GCC seems to consider all of these conversions to be pointer
-/// conversions, so for now they live here.
+/// conversions, so for now they live here. IncompatibleObjC will be
+/// set if the conversion is an allowed Objective-C conversion that
+/// should result in a warning.
bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
- QualType& ConvertedType)
+ QualType& ConvertedType,
+ bool &IncompatibleObjC)
{
+ IncompatibleObjC = false;
+
// Blocks: Block pointers can be converted to void*.
if (FromType->isBlockPointerType() && ToType->isPointerType() &&
ToType->getAsPointerType()->getPointeeType()->isVoidType()) {
@@ -836,6 +845,18 @@
return true;
}
+ if (FromIface && ToIface &&
+ Context.canAssignObjCInterfaces(FromIface, ToIface)) {
+ // Okay: this is some kind of implicit downcast of Objective-C
+ // interfaces, which is permitted. However, we're going to
+ // complain about it.
+ IncompatibleObjC = true;
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
// Objective C++: We're able to convert between "id" and a pointer
// to any interface (in both directions).
if ((FromIface && Context.isObjCIdType(ToPointeeType))
@@ -1533,7 +1554,7 @@
if (ToType->isReferenceType())
return CheckReferenceInit(From, ToType);
- if (!PerformImplicitConversion(From, ToType))
+ if (!PerformImplicitConversion(From, ToType, Flavor))
return false;
return Diag(From->getSourceRange().getBegin(),
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 13be00a..c7bf8b2 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -98,6 +98,10 @@
/// (C++ 4.2p2).
bool Deprecated : 1;
+ /// IncompatibleObjC - Whether this is an Objective-C conversion
+ /// that we should warn about (if we actually use it).
+ bool IncompatibleObjC : 1;
+
/// ReferenceBinding - True when this is a reference binding
/// (C++ [over.ics.ref]).
bool ReferenceBinding : 1;