Index: cfe/trunk/include/clang/Sema/Overload.h =================================================================== --- cfe/trunk/include/clang/Sema/Overload.h +++ cfe/trunk/include/clang/Sema/Overload.h @@ -83,7 +83,8 @@ 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 @@ 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); Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -8292,19 +8292,23 @@ 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. Index: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -5376,13 +5376,13 @@ return CK_IntegralToFloating; case Type::STK_IntegralComplex: Src = ImpCastExprToType(Src.get(), - DestTy->castAs()->getElementType(), - CK_IntegralCast); + DestTy->castAs()->getElementType(), + CK_IntegralCast); return CK_IntegralRealToComplex; case Type::STK_FloatingComplex: Src = ImpCastExprToType(Src.get(), - DestTy->castAs()->getElementType(), - CK_IntegralToFloating); + DestTy->castAs()->getElementType(), + CK_IntegralToFloating); return CK_FloatingRealToComplex; case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -6867,7 +6867,7 @@ 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 @@ /// 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 @@ 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 @@ // CK_VectorSplat does T -> vector T, so first cast to the // element type. QualType elType = cast(LHSType)->getElementType(); - if (elType != RHSType) { + if (elType != RHSType && ConvertRHS) { Kind = PrepareScalarCast(RHS, elType); RHS = ImpCastExprToType(RHS.get(), elType, Kind); } @@ -6974,7 +6974,8 @@ // 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 @@ // 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::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 @@ 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 @@ // // 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 @@ 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 @@ return Compatible; } - RHS = ImpCastExprToType(E, Ty, Kind); + if (ConvertRHS) + RHS = ImpCastExprToType(E, Ty, Kind); } return result; } Index: cfe/trunk/lib/Sema/SemaOverload.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp +++ cfe/trunk/lib/Sema/SemaOverload.cpp @@ -130,7 +130,11 @@ 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 @@ "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 @@ 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 @@ 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 @@ // 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 @@ } 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 @@ 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 @@ Match = false; break; } - + ImplicitConversionSequence ConversionState = TryCopyInitialization(*this, argExpr, param->getType(), /*SuppressUserConversions*/false, Index: cfe/trunk/test/Sema/overloadable.c =================================================================== --- cfe/trunk/test/Sema/overloadable.c +++ cfe/trunk/test/Sema/overloadable.c @@ -85,3 +85,17 @@ 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); +}