forked from OSchip/llvm-project
[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
This commit is contained in:
parent
fcc34bdee0
commit
4546181e12
|
@ -83,7 +83,8 @@ namespace clang {
|
||||||
ICK_TransparentUnionConversion, ///< Transparent Union Conversions
|
ICK_TransparentUnionConversion, ///< Transparent Union Conversions
|
||||||
ICK_Writeback_Conversion, ///< Objective-C ARC writeback conversion
|
ICK_Writeback_Conversion, ///< Objective-C ARC writeback conversion
|
||||||
ICK_Zero_Event_Conversion, ///< Zero constant to event (OpenCL1.2 6.12.10)
|
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
|
/// ImplicitConversionRank - The rank of an implicit conversion
|
||||||
|
@ -95,7 +96,9 @@ namespace clang {
|
||||||
ICR_Promotion, ///< Promotion
|
ICR_Promotion, ///< Promotion
|
||||||
ICR_Conversion, ///< Conversion
|
ICR_Conversion, ///< Conversion
|
||||||
ICR_Complex_Real_Conversion, ///< Complex <-> Real 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);
|
ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
|
||||||
|
|
|
@ -8292,19 +8292,23 @@ public:
|
||||||
QualType LHSType,
|
QualType LHSType,
|
||||||
QualType RHSType);
|
QualType RHSType);
|
||||||
|
|
||||||
/// Check assignment constraints and prepare for a conversion of the
|
/// Check assignment constraints and optionally prepare for a conversion of
|
||||||
/// RHS to the LHS type.
|
/// the RHS to the LHS type. The conversion is prepared for if ConvertRHS
|
||||||
|
/// is true.
|
||||||
AssignConvertType CheckAssignmentConstraints(QualType LHSType,
|
AssignConvertType CheckAssignmentConstraints(QualType LHSType,
|
||||||
ExprResult &RHS,
|
ExprResult &RHS,
|
||||||
CastKind &Kind);
|
CastKind &Kind,
|
||||||
|
bool ConvertRHS = true);
|
||||||
|
|
||||||
// CheckSingleAssignmentConstraints - Currently used by
|
// CheckSingleAssignmentConstraints - Currently used by
|
||||||
// CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
|
// 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,
|
AssignConvertType CheckSingleAssignmentConstraints(QualType LHSType,
|
||||||
ExprResult &RHS,
|
ExprResult &RHS,
|
||||||
bool Diagnose = true,
|
bool Diagnose = true,
|
||||||
bool DiagnoseCFAudited = false);
|
bool DiagnoseCFAudited = false,
|
||||||
|
bool ConvertRHS = true);
|
||||||
|
|
||||||
// \brief If the lhs type is a transparent union, check whether we
|
// \brief If the lhs type is a transparent union, check whether we
|
||||||
// can initialize the transparent union with the given expression.
|
// can initialize the transparent union with the given expression.
|
||||||
|
|
|
@ -5376,13 +5376,13 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
|
||||||
return CK_IntegralToFloating;
|
return CK_IntegralToFloating;
|
||||||
case Type::STK_IntegralComplex:
|
case Type::STK_IntegralComplex:
|
||||||
Src = ImpCastExprToType(Src.get(),
|
Src = ImpCastExprToType(Src.get(),
|
||||||
DestTy->castAs<ComplexType>()->getElementType(),
|
DestTy->castAs<ComplexType>()->getElementType(),
|
||||||
CK_IntegralCast);
|
CK_IntegralCast);
|
||||||
return CK_IntegralRealToComplex;
|
return CK_IntegralRealToComplex;
|
||||||
case Type::STK_FloatingComplex:
|
case Type::STK_FloatingComplex:
|
||||||
Src = ImpCastExprToType(Src.get(),
|
Src = ImpCastExprToType(Src.get(),
|
||||||
DestTy->castAs<ComplexType>()->getElementType(),
|
DestTy->castAs<ComplexType>()->getElementType(),
|
||||||
CK_IntegralToFloating);
|
CK_IntegralToFloating);
|
||||||
return CK_FloatingRealToComplex;
|
return CK_FloatingRealToComplex;
|
||||||
case Type::STK_MemberPointer:
|
case Type::STK_MemberPointer:
|
||||||
llvm_unreachable("member pointer type in C");
|
llvm_unreachable("member pointer type in C");
|
||||||
|
@ -6867,7 +6867,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
|
||||||
ExprResult RHSPtr = &RHSExpr;
|
ExprResult RHSPtr = &RHSExpr;
|
||||||
CastKind K = CK_Invalid;
|
CastKind K = CK_Invalid;
|
||||||
|
|
||||||
return CheckAssignmentConstraints(LHSType, RHSPtr, K);
|
return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
|
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
|
||||||
|
@ -6889,7 +6889,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
|
||||||
/// Sets 'Kind' for any result kind except Incompatible.
|
/// Sets 'Kind' for any result kind except Incompatible.
|
||||||
Sema::AssignConvertType
|
Sema::AssignConvertType
|
||||||
Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
||||||
CastKind &Kind) {
|
CastKind &Kind, bool ConvertRHS) {
|
||||||
QualType RHSType = RHS.get()->getType();
|
QualType RHSType = RHS.get()->getType();
|
||||||
QualType OrigLHSType = LHSType;
|
QualType OrigLHSType = LHSType;
|
||||||
|
|
||||||
|
@ -6911,7 +6911,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
||||||
CheckAssignmentConstraints(AtomicTy->getValueType(), RHS, Kind);
|
CheckAssignmentConstraints(AtomicTy->getValueType(), RHS, Kind);
|
||||||
if (result != Compatible)
|
if (result != Compatible)
|
||||||
return result;
|
return result;
|
||||||
if (Kind != CK_NoOp)
|
if (Kind != CK_NoOp && ConvertRHS)
|
||||||
RHS = ImpCastExprToType(RHS.get(), AtomicTy->getValueType(), Kind);
|
RHS = ImpCastExprToType(RHS.get(), AtomicTy->getValueType(), Kind);
|
||||||
Kind = CK_NonAtomicToAtomic;
|
Kind = CK_NonAtomicToAtomic;
|
||||||
return Compatible;
|
return Compatible;
|
||||||
|
@ -6941,7 +6941,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
||||||
// CK_VectorSplat does T -> vector T, so first cast to the
|
// CK_VectorSplat does T -> vector T, so first cast to the
|
||||||
// element type.
|
// element type.
|
||||||
QualType elType = cast<ExtVectorType>(LHSType)->getElementType();
|
QualType elType = cast<ExtVectorType>(LHSType)->getElementType();
|
||||||
if (elType != RHSType) {
|
if (elType != RHSType && ConvertRHS) {
|
||||||
Kind = PrepareScalarCast(RHS, elType);
|
Kind = PrepareScalarCast(RHS, elType);
|
||||||
RHS = ImpCastExprToType(RHS.get(), elType, Kind);
|
RHS = ImpCastExprToType(RHS.get(), elType, Kind);
|
||||||
}
|
}
|
||||||
|
@ -6974,7 +6974,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
||||||
// Arithmetic conversions.
|
// Arithmetic conversions.
|
||||||
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
|
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
|
||||||
!(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
|
!(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
|
||||||
Kind = PrepareScalarCast(RHS, LHSType);
|
if (ConvertRHS)
|
||||||
|
Kind = PrepareScalarCast(RHS, LHSType);
|
||||||
return Compatible;
|
return Compatible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7099,7 +7100,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
||||||
// Only under strict condition T^ is compatible with an Objective-C pointer.
|
// Only under strict condition T^ is compatible with an Objective-C pointer.
|
||||||
if (RHSType->isBlockPointerType() &&
|
if (RHSType->isBlockPointerType() &&
|
||||||
LHSType->isBlockCompatibleObjCPointerType(Context)) {
|
LHSType->isBlockCompatibleObjCPointerType(Context)) {
|
||||||
maybeExtendBlockObject(RHS);
|
if (ConvertRHS)
|
||||||
|
maybeExtendBlockObject(RHS);
|
||||||
Kind = CK_BlockPointerToObjCPointerCast;
|
Kind = CK_BlockPointerToObjCPointerCast;
|
||||||
return Compatible;
|
return Compatible;
|
||||||
}
|
}
|
||||||
|
@ -7225,9 +7227,16 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
|
||||||
}
|
}
|
||||||
|
|
||||||
Sema::AssignConvertType
|
Sema::AssignConvertType
|
||||||
Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
|
||||||
bool Diagnose,
|
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 (getLangOpts().CPlusPlus) {
|
||||||
if (!LHSType->isRecordType() && !LHSType->isAtomicType()) {
|
if (!LHSType->isRecordType() && !LHSType->isAtomicType()) {
|
||||||
// C++ 5.17p3: If the left operand is not of class type, the
|
// 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;
|
CastKind Kind;
|
||||||
CXXCastPath Path;
|
CXXCastPath Path;
|
||||||
CheckPointerConversion(RHS.get(), LHSType, Kind, Path, false);
|
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;
|
return Compatible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7287,6 +7297,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
||||||
//
|
//
|
||||||
// Suppress this for references: C++ 8.5.3p5.
|
// Suppress this for references: C++ 8.5.3p5.
|
||||||
if (!LHSType->isReferenceType()) {
|
if (!LHSType->isReferenceType()) {
|
||||||
|
// FIXME: We potentially allocate here even if ConvertRHS is false.
|
||||||
RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
|
RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
|
||||||
if (RHS.isInvalid())
|
if (RHS.isInvalid())
|
||||||
return Incompatible;
|
return Incompatible;
|
||||||
|
@ -7303,7 +7314,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
||||||
|
|
||||||
CastKind Kind = CK_Invalid;
|
CastKind Kind = CK_Invalid;
|
||||||
Sema::AssignConvertType result =
|
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
|
// C99 6.5.16.1p2: The value of the right operand is converted to the
|
||||||
// type of the assignment expression.
|
// type of the assignment expression.
|
||||||
|
@ -7325,7 +7336,8 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
||||||
return Compatible;
|
return Compatible;
|
||||||
}
|
}
|
||||||
|
|
||||||
RHS = ImpCastExprToType(E, Ty, Kind);
|
if (ConvertRHS)
|
||||||
|
RHS = ImpCastExprToType(E, Ty, Kind);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,11 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
|
||||||
ICR_Complex_Real_Conversion,
|
ICR_Complex_Real_Conversion,
|
||||||
ICR_Conversion,
|
ICR_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];
|
return Rank[(int)Kind];
|
||||||
}
|
}
|
||||||
|
@ -162,7 +166,9 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
|
||||||
"Complex-real conversion",
|
"Complex-real conversion",
|
||||||
"Block Pointer conversion",
|
"Block Pointer conversion",
|
||||||
"Transparent Union Conversion",
|
"Transparent Union Conversion",
|
||||||
"Writeback conversion"
|
"Writeback conversion",
|
||||||
|
"OpenCL Zero Event Conversion",
|
||||||
|
"C specific type conversion"
|
||||||
};
|
};
|
||||||
return Name[Kind];
|
return Name[Kind];
|
||||||
}
|
}
|
||||||
|
@ -1434,13 +1440,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
|
||||||
SCS.CopyConstructor = nullptr;
|
SCS.CopyConstructor = nullptr;
|
||||||
|
|
||||||
// There are no standard conversions for class types in C++, so
|
// There are no standard conversions for class types in C++, so
|
||||||
// abort early. When overloading in C, however, we do permit
|
// abort early. When overloading in C, however, we do permit them.
|
||||||
if (FromType->isRecordType() || ToType->isRecordType()) {
|
if (S.getLangOpts().CPlusPlus &&
|
||||||
if (S.getLangOpts().CPlusPlus)
|
(FromType->isRecordType() || ToType->isRecordType()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// When we're overloading in C, we allow, as standard conversions,
|
|
||||||
}
|
|
||||||
|
|
||||||
// The first conversion can be an lvalue-to-rvalue conversion,
|
// The first conversion can be an lvalue-to-rvalue conversion,
|
||||||
// array-to-pointer conversion, or function-to-pointer conversion
|
// array-to-pointer conversion, or function-to-pointer conversion
|
||||||
|
@ -1651,7 +1654,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
|
||||||
return true;
|
return true;
|
||||||
} else if (ToType->isEventT() &&
|
} else if (ToType->isEventT() &&
|
||||||
From->isIntegerConstantExpr(S.getASTContext()) &&
|
From->isIntegerConstantExpr(S.getASTContext()) &&
|
||||||
(From->EvaluateKnownConstInt(S.getASTContext()) == 0)) {
|
From->EvaluateKnownConstInt(S.getASTContext()) == 0) {
|
||||||
SCS.Second = ICK_Zero_Event_Conversion;
|
SCS.Second = ICK_Zero_Event_Conversion;
|
||||||
FromType = ToType;
|
FromType = ToType;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1690,11 +1693,28 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
|
||||||
}
|
}
|
||||||
SCS.setToType(2, FromType);
|
SCS.setToType(2, FromType);
|
||||||
|
|
||||||
|
if (CanonFrom == CanonTo)
|
||||||
|
return true;
|
||||||
|
|
||||||
// If we have not converted the argument type to the parameter type,
|
// If we have not converted the argument type to the parameter type,
|
||||||
// this is a bad conversion sequence.
|
// this is a bad conversion sequence, unless we're resolving an overload in C.
|
||||||
if (CanonFrom != CanonTo)
|
if (S.getLangOpts().CPlusPlus || !InOverloadResolution)
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4993,6 +5013,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
|
||||||
case ICK_TransparentUnionConversion:
|
case ICK_TransparentUnionConversion:
|
||||||
case ICK_Writeback_Conversion:
|
case ICK_Writeback_Conversion:
|
||||||
case ICK_Zero_Event_Conversion:
|
case ICK_Zero_Event_Conversion:
|
||||||
|
case ICK_C_Only_Conversion:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case ICK_Lvalue_To_Rvalue:
|
case ICK_Lvalue_To_Rvalue:
|
||||||
|
|
|
@ -85,3 +85,17 @@ void local() {
|
||||||
void after_local_1(int) __attribute__((overloadable)); // expected-error {{conflicting types}}
|
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_2(int); // expected-error {{must have the 'overloadable' attribute}}
|
||||||
void after_local_3(int) __attribute__((overloadable));
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue