summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Burgess IV <george.burgess.iv@gmail.com>2015-10-11 20:13:20 +0000
committerGeorge Burgess IV <george.burgess.iv@gmail.com>2015-10-11 20:13:20 +0000
commit4546181e12c89c92e37f6da5cfb800b5b0fea755 (patch)
tree6f901c23b3940dc51b225f77650585c4bd7ecae3
parentfcc34bdee0da68ffe520316fc8e369cce21f8466 (diff)
downloadbcm5719-llvm-4546181e12c89c92e37f6da5cfb800b5b0fea755.tar.gz
bcm5719-llvm-4546181e12c89c92e37f6da5cfb800b5b0fea755.zip
[Sema] Allow C conversions in C overload logic
C allows for some implicit conversions that C++ does not, e.g. void* -> char*. This patch teaches clang that these conversions are okay when dealing with overloads in C. Differential Revision: http://reviews.llvm.org/D13604 llvm-svn: 249995
-rw-r--r--clang/include/clang/Sema/Overload.h7
-rw-r--r--clang/include/clang/Sema/Sema.h14
-rw-r--r--clang/lib/Sema/SemaExpr.cpp42
-rw-r--r--clang/lib/Sema/SemaOverload.cpp51
-rw-r--r--clang/test/Sema/overloadable.c14
5 files changed, 91 insertions, 37 deletions
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 2007dcb59ac..20958b057a4 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -83,7 +83,8 @@ namespace clang {
ICK_TransparentUnionConversion, ///< Transparent Union Conversions
ICK_Writeback_Conversion, ///< Objective-C ARC writeback conversion
ICK_Zero_Event_Conversion, ///< Zero constant to event (OpenCL1.2 6.12.10)
- ICK_Num_Conversion_Kinds ///< The number of conversion kinds
+ ICK_C_Only_Conversion, ///< Conversions allowed in C, but not C++
+ ICK_Num_Conversion_Kinds, ///< The number of conversion kinds
};
/// ImplicitConversionRank - The rank of an implicit conversion
@@ -95,7 +96,9 @@ namespace clang {
ICR_Promotion, ///< Promotion
ICR_Conversion, ///< Conversion
ICR_Complex_Real_Conversion, ///< Complex <-> Real conversion
- ICR_Writeback_Conversion ///< ObjC ARC writeback conversion
+ ICR_Writeback_Conversion, ///< ObjC ARC writeback conversion
+ ICR_C_Conversion ///< Conversion only allowed in the C standard.
+ /// (e.g. void* to char*)
};
ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 3f118e72682..62a8c68eec7 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8292,19 +8292,23 @@ public:
QualType LHSType,
QualType RHSType);
- /// Check assignment constraints and prepare for a conversion of the
- /// RHS to the LHS type.
+ /// Check assignment constraints and optionally prepare for a conversion of
+ /// the RHS to the LHS type. The conversion is prepared for if ConvertRHS
+ /// is true.
AssignConvertType CheckAssignmentConstraints(QualType LHSType,
ExprResult &RHS,
- CastKind &Kind);
+ CastKind &Kind,
+ bool ConvertRHS = true);
// CheckSingleAssignmentConstraints - Currently used by
// CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
- // this routine performs the default function/array converions.
+ // this routine performs the default function/array converions, if ConvertRHS
+ // is true.
AssignConvertType CheckSingleAssignmentConstraints(QualType LHSType,
ExprResult &RHS,
bool Diagnose = true,
- bool DiagnoseCFAudited = false);
+ bool DiagnoseCFAudited = false,
+ bool ConvertRHS = true);
// \brief If the lhs type is a transparent union, check whether we
// can initialize the transparent union with the given expression.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 801709c17db..3c916a30d17 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5376,13 +5376,13 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
return CK_IntegralToFloating;
case Type::STK_IntegralComplex:
Src = ImpCastExprToType(Src.get(),
- DestTy->castAs<ComplexType>()->getElementType(),
- CK_IntegralCast);
+ DestTy->castAs<ComplexType>()->getElementType(),
+ CK_IntegralCast);
return CK_IntegralRealToComplex;
case Type::STK_FloatingComplex:
Src = ImpCastExprToType(Src.get(),
- DestTy->castAs<ComplexType>()->getElementType(),
- CK_IntegralToFloating);
+ DestTy->castAs<ComplexType>()->getElementType(),
+ CK_IntegralToFloating);
return CK_FloatingRealToComplex;
case Type::STK_MemberPointer:
llvm_unreachable("member pointer type in C");
@@ -6867,7 +6867,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
ExprResult RHSPtr = &RHSExpr;
CastKind K = CK_Invalid;
- return CheckAssignmentConstraints(LHSType, RHSPtr, K);
+ return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false);
}
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
@@ -6889,7 +6889,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
/// Sets 'Kind' for any result kind except Incompatible.
Sema::AssignConvertType
Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
- CastKind &Kind) {
+ CastKind &Kind, bool ConvertRHS) {
QualType RHSType = RHS.get()->getType();
QualType OrigLHSType = LHSType;
@@ -6911,7 +6911,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
CheckAssignmentConstraints(AtomicTy->getValueType(), RHS, Kind);
if (result != Compatible)
return result;
- if (Kind != CK_NoOp)
+ if (Kind != CK_NoOp && ConvertRHS)
RHS = ImpCastExprToType(RHS.get(), AtomicTy->getValueType(), Kind);
Kind = CK_NonAtomicToAtomic;
return Compatible;
@@ -6941,7 +6941,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// CK_VectorSplat does T -> vector T, so first cast to the
// element type.
QualType elType = cast<ExtVectorType>(LHSType)->getElementType();
- if (elType != RHSType) {
+ if (elType != RHSType && ConvertRHS) {
Kind = PrepareScalarCast(RHS, elType);
RHS = ImpCastExprToType(RHS.get(), elType, Kind);
}
@@ -6974,7 +6974,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// Arithmetic conversions.
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
!(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
- Kind = PrepareScalarCast(RHS, LHSType);
+ if (ConvertRHS)
+ Kind = PrepareScalarCast(RHS, LHSType);
return Compatible;
}
@@ -7099,7 +7100,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// Only under strict condition T^ is compatible with an Objective-C pointer.
if (RHSType->isBlockPointerType() &&
LHSType->isBlockCompatibleObjCPointerType(Context)) {
- maybeExtendBlockObject(RHS);
+ if (ConvertRHS)
+ maybeExtendBlockObject(RHS);
Kind = CK_BlockPointerToObjCPointerCast;
return Compatible;
}
@@ -7225,9 +7227,16 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
}
Sema::AssignConvertType
-Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
+Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
bool Diagnose,
- bool DiagnoseCFAudited) {
+ bool DiagnoseCFAudited,
+ bool ConvertRHS) {
+ // If ConvertRHS is false, we want to leave the caller's RHS untouched. Sadly,
+ // we can't avoid *all* modifications at the moment, so we need some somewhere
+ // to put the updated value.
+ ExprResult LocalRHS = CallerRHS;
+ ExprResult &RHS = ConvertRHS ? CallerRHS : LocalRHS;
+
if (getLangOpts().CPlusPlus) {
if (!LHSType->isRecordType() && !LHSType->isAtomicType()) {
// C++ 5.17p3: If the left operand is not of class type, the
@@ -7276,7 +7285,8 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
CastKind Kind;
CXXCastPath Path;
CheckPointerConversion(RHS.get(), LHSType, Kind, Path, false);
- RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path);
+ if (ConvertRHS)
+ RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path);
return Compatible;
}
@@ -7287,6 +7297,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
//
// Suppress this for references: C++ 8.5.3p5.
if (!LHSType->isReferenceType()) {
+ // FIXME: We potentially allocate here even if ConvertRHS is false.
RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
if (RHS.isInvalid())
return Incompatible;
@@ -7303,7 +7314,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
CastKind Kind = CK_Invalid;
Sema::AssignConvertType result =
- CheckAssignmentConstraints(LHSType, RHS, Kind);
+ CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS);
// C99 6.5.16.1p2: The value of the right operand is converted to the
// type of the assignment expression.
@@ -7325,7 +7336,8 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
return Compatible;
}
- RHS = ImpCastExprToType(E, Ty, Kind);
+ if (ConvertRHS)
+ RHS = ImpCastExprToType(E, Ty, Kind);
}
return result;
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 03b35ec9855..a9259bb0756 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -130,7 +130,11 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
ICR_Complex_Real_Conversion,
ICR_Conversion,
ICR_Conversion,
- ICR_Writeback_Conversion
+ ICR_Writeback_Conversion,
+ ICR_Exact_Match, // NOTE(gbiv): This may not be completely right --
+ // it was omitted by the patch that added
+ // ICK_Zero_Event_Conversion
+ ICR_C_Conversion
};
return Rank[(int)Kind];
}
@@ -162,7 +166,9 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
"Complex-real conversion",
"Block Pointer conversion",
"Transparent Union Conversion",
- "Writeback conversion"
+ "Writeback conversion",
+ "OpenCL Zero Event Conversion",
+ "C specific type conversion"
};
return Name[Kind];
}
@@ -1411,7 +1417,7 @@ static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle);
-
+
/// IsStandardConversion - Determines whether there is a standard
/// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the
/// expression From to the type ToType. Standard conversion sequences
@@ -1434,13 +1440,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
SCS.CopyConstructor = nullptr;
// There are no standard conversions for class types in C++, so
- // abort early. When overloading in C, however, we do permit
- if (FromType->isRecordType() || ToType->isRecordType()) {
- if (S.getLangOpts().CPlusPlus)
- return false;
-
- // When we're overloading in C, we allow, as standard conversions,
- }
+ // abort early. When overloading in C, however, we do permit them.
+ if (S.getLangOpts().CPlusPlus &&
+ (FromType->isRecordType() || ToType->isRecordType()))
+ return false;
// The first conversion can be an lvalue-to-rvalue conversion,
// array-to-pointer conversion, or function-to-pointer conversion
@@ -1649,9 +1652,9 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// tryAtomicConversion has updated the standard conversion sequence
// appropriately.
return true;
- } else if (ToType->isEventT() &&
+ } else if (ToType->isEventT() &&
From->isIntegerConstantExpr(S.getASTContext()) &&
- (From->EvaluateKnownConstInt(S.getASTContext()) == 0)) {
+ From->EvaluateKnownConstInt(S.getASTContext()) == 0) {
SCS.Second = ICK_Zero_Event_Conversion;
FromType = ToType;
} else {
@@ -1690,11 +1693,28 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
}
SCS.setToType(2, FromType);
+ if (CanonFrom == CanonTo)
+ return true;
+
// If we have not converted the argument type to the parameter type,
- // this is a bad conversion sequence.
- if (CanonFrom != CanonTo)
+ // this is a bad conversion sequence, unless we're resolving an overload in C.
+ if (S.getLangOpts().CPlusPlus || !InOverloadResolution)
+ return false;
+
+ ExprResult ER = ExprResult{From};
+ auto Conv = S.CheckSingleAssignmentConstraints(ToType, ER,
+ /*Diagnose=*/false,
+ /*DiagnoseCFAudited=*/false,
+ /*ConvertRHS=*/false);
+ if (Conv != Sema::Compatible)
return false;
+ SCS.setAllToTypes(ToType);
+ // We need to set all three because we want this conversion to rank terribly,
+ // and we don't know what conversions it may overlap with.
+ SCS.First = ICK_C_Only_Conversion;
+ SCS.Second = ICK_C_Only_Conversion;
+ SCS.Third = ICK_C_Only_Conversion;
return true;
}
@@ -4993,6 +5013,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
case ICK_TransparentUnionConversion:
case ICK_Writeback_Conversion:
case ICK_Zero_Event_Conversion:
+ case ICK_C_Only_Conversion:
return false;
case ICK_Lvalue_To_Rvalue:
@@ -5785,7 +5806,7 @@ ObjCMethodDecl *Sema::SelectBestMethod(Selector Sel, MultiExprArg Args,
Match = false;
break;
}
-
+
ImplicitConversionSequence ConversionState
= TryCopyInitialization(*this, argExpr, param->getType(),
/*SuppressUserConversions*/false,
diff --git a/clang/test/Sema/overloadable.c b/clang/test/Sema/overloadable.c
index bdd471477b4..3120649dbc0 100644
--- a/clang/test/Sema/overloadable.c
+++ b/clang/test/Sema/overloadable.c
@@ -85,3 +85,17 @@ void local() {
void after_local_1(int) __attribute__((overloadable)); // expected-error {{conflicting types}}
void after_local_2(int); // expected-error {{must have the 'overloadable' attribute}}
void after_local_3(int) __attribute__((overloadable));
+
+// Make sure we allow C-specific conversions in C.
+void conversions() {
+ void foo(char *c) __attribute__((overloadable));
+ void foo(char *c) __attribute__((overloadable, enable_if(c, "nope.jpg")));
+
+ void *ptr;
+ foo(ptr);
+
+ void multi_type(unsigned char *c) __attribute__((overloadable));
+ void multi_type(signed char *c) __attribute__((overloadable));
+ unsigned char *c;
+ multi_type(c);
+}
OpenPOWER on IntegriCloud