Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2868,6 +2868,83 @@ AA_Casting, AA_Passing_CFAudited }; + /// AssignConvertType - All of the 'assignment' semantic checks return this + /// enum to indicate whether the assignment was allowed. These checks are + /// done for simple assignments, as well as initialization, return from + /// function, argument passing, etc. The query is phrased in terms of a + /// source and destination type. + enum AssignConvertType { + /// Compatible - the types are compatible according to the standard. + Compatible, + + /// PointerToInt - The assignment converts a pointer to an int, which we + /// accept as an extension. + PointerToInt, + + /// IntToPointer - The assignment converts an int to a pointer, which we + /// accept as an extension. + IntToPointer, + + /// FunctionVoidPointer - The assignment is between a function pointer and + /// void*, which the standard doesn't allow, but we accept as an extension. + FunctionVoidPointer, + + /// IncompatiblePointer - The assignment is between two pointers types that + /// are not compatible, but we accept them as an extension. + IncompatiblePointer, + + /// IncompatiblePointerSign - The assignment is between two pointers types + /// which point to integers which have a different sign, but are otherwise + /// identical. This is a subset of the above, but broken out because it's by + /// far the most common case of incompatible pointers. + IncompatiblePointerSign, + + /// CompatiblePointerDiscardsQualifiers - The assignment discards + /// c/v/r qualifiers, which we accept as an extension. + CompatiblePointerDiscardsQualifiers, + + /// IncompatiblePointerDiscardsQualifiers - The assignment + /// discards qualifiers that we don't permit to be discarded, + /// like address spaces. + IncompatiblePointerDiscardsQualifiers, + + /// IncompatibleNestedPointerAddressSpaceMismatch - The assignment + /// changes address spaces in nested pointer types which is not allowed. + /// For instance, converting __private int ** to __generic int ** is + /// illegal even though __private could be converted to __generic. + IncompatibleNestedPointerAddressSpaceMismatch, + + /// IncompatibleNestedPointerQualifiers - The assignment is between two + /// nested pointer types, and the qualifiers other than the first two + /// levels differ e.g. char ** -> const char **, but we accept them as an + /// extension. + IncompatibleNestedPointerQualifiers, + + /// IncompatibleVectors - The assignment is between two vector types that + /// have the same size, which we accept as an extension. + IncompatibleVectors, + + /// IntToBlockPointer - The assignment converts an int to a block + /// pointer. We disallow this. + IntToBlockPointer, + + /// IncompatibleBlockPointer - The assignment is between two block + /// pointers types that are not compatible. + IncompatibleBlockPointer, + + /// IncompatibleObjCQualifiedId - The assignment is between a qualified + /// id type and something else (that is incompatible with it). For example, + /// "id " = "Foo *", where "Foo *" doesn't implement the XXX protocol. + IncompatibleObjCQualifiedId, + + /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an + /// object with __weak qualifier. + IncompatibleObjCWeakRef, + + /// Incompatible - We reject this conversion outright, it is invalid to + /// represent it in the AST. + Incompatible + }; /// C++ Overloading. enum OverloadKind { @@ -2933,7 +3010,8 @@ CXXCastPath &BasePath, bool IgnoreBaseAccess); bool IsQualificationConversion(QualType FromType, QualType ToType, - bool CStyle, bool &ObjCLifetimeConversion); + bool CStyle, bool &ObjCLifetimeConversion, + AssignConvertType &ConvType); bool IsFunctionConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); @@ -10466,83 +10544,7 @@ QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, ArithConvKind ACK); - /// AssignConvertType - All of the 'assignment' semantic checks return this - /// enum to indicate whether the assignment was allowed. These checks are - /// done for simple assignments, as well as initialization, return from - /// function, argument passing, etc. The query is phrased in terms of a - /// source and destination type. - enum AssignConvertType { - /// Compatible - the types are compatible according to the standard. - Compatible, - - /// PointerToInt - The assignment converts a pointer to an int, which we - /// accept as an extension. - PointerToInt, - - /// IntToPointer - The assignment converts an int to a pointer, which we - /// accept as an extension. - IntToPointer, - /// FunctionVoidPointer - The assignment is between a function pointer and - /// void*, which the standard doesn't allow, but we accept as an extension. - FunctionVoidPointer, - - /// IncompatiblePointer - The assignment is between two pointers types that - /// are not compatible, but we accept them as an extension. - IncompatiblePointer, - - /// IncompatiblePointerSign - The assignment is between two pointers types - /// which point to integers which have a different sign, but are otherwise - /// identical. This is a subset of the above, but broken out because it's by - /// far the most common case of incompatible pointers. - IncompatiblePointerSign, - - /// CompatiblePointerDiscardsQualifiers - The assignment discards - /// c/v/r qualifiers, which we accept as an extension. - CompatiblePointerDiscardsQualifiers, - - /// IncompatiblePointerDiscardsQualifiers - The assignment - /// discards qualifiers that we don't permit to be discarded, - /// like address spaces. - IncompatiblePointerDiscardsQualifiers, - - /// IncompatibleNestedPointerAddressSpaceMismatch - The assignment - /// changes address spaces in nested pointer types which is not allowed. - /// For instance, converting __private int ** to __generic int ** is - /// illegal even though __private could be converted to __generic. - IncompatibleNestedPointerAddressSpaceMismatch, - - /// IncompatibleNestedPointerQualifiers - The assignment is between two - /// nested pointer types, and the qualifiers other than the first two - /// levels differ e.g. char ** -> const char **, but we accept them as an - /// extension. - IncompatibleNestedPointerQualifiers, - - /// IncompatibleVectors - The assignment is between two vector types that - /// have the same size, which we accept as an extension. - IncompatibleVectors, - - /// IntToBlockPointer - The assignment converts an int to a block - /// pointer. We disallow this. - IntToBlockPointer, - - /// IncompatibleBlockPointer - The assignment is between two block - /// pointers types that are not compatible. - IncompatibleBlockPointer, - - /// IncompatibleObjCQualifiedId - The assignment is between a qualified - /// id type and something else (that is incompatible with it). For example, - /// "id " = "Foo *", where "Foo *" doesn't implement the XXX protocol. - IncompatibleObjCQualifiedId, - - /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an - /// object with __weak qualifier. - IncompatibleObjCWeakRef, - - /// Incompatible - We reject this conversion outright, it is invalid to - /// represent it in the AST. - Incompatible - }; /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the @@ -10555,7 +10557,7 @@ /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag /// enum. If AllowMask is true, then we also allow the complement of a valid - /// value, to be used as a mask. + /// value, to be used as a mask.// bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, bool AllowMask) const; @@ -10608,14 +10610,17 @@ ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, + /*clang::Sema::AssignConvertType& ConvType,*/ bool AllowExplicit = false); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, - ImplicitConversionSequence& ICS); + ImplicitConversionSequence& ICS, + Sema::AssignConvertType& ConvType); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence& ICS, - AssignmentAction Action, + AssignmentAction Action, + Sema::AssignConvertType& ConvType, CheckedConversionKind CCK = CCK_ImplicitConversion); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, Index: clang/lib/Sema/SemaExceptionSpec.cpp =================================================================== --- clang/lib/Sema/SemaExceptionSpec.cpp +++ clang/lib/Sema/SemaExceptionSpec.cpp @@ -696,8 +696,9 @@ QualType Result; // FIXME: Should we treat the exception as catchable if a lifetime // conversion is required? + Sema::AssignConvertType ConvType = Sema::Compatible; if (IsQualificationConversion(ExceptionType, HandlerType, false, - LifetimeConv) || + LifetimeConv, ConvType) || IsFunctionConversion(ExceptionType, HandlerType, Result)) return true; Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -8684,9 +8684,10 @@ // expression is implicitly converted (C++ 4) to the // cv-unqualified type of the left operand. QualType RHSType = RHS.get()->getType(); + Sema::AssignConvertType ConvType = Compatible; if (Diagnose) { RHS = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), - AA_Assigning); + AA_Assigning, ConvType); } else { ImplicitConversionSequence ICS = TryImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), @@ -8698,15 +8699,19 @@ if (ICS.isFailure()) return Incompatible; RHS = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), - ICS, AA_Assigning); + ICS, AA_Assigning, ConvType); } - if (RHS.isInvalid()) - return Incompatible; - Sema::AssignConvertType result = Compatible; - if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && - !CheckObjCARCUnavailableWeakConversion(LHSType, RHSType)) - result = IncompatibleObjCWeakRef; - return result; + // FIXME: We won't need this check if PerformImplicitConversion sets + // AssignConvertType correctly. + if (ConvType == Compatible && RHS.isInvalid()) + ConvType = Incompatible; + + if (ConvType == Compatible) + if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && + !CheckObjCARCUnavailableWeakConversion(LHSType, RHSType)) + ConvType = IncompatibleObjCWeakRef; + + return ConvType; } // FIXME: Currently, we fall through and treat C++ classes like C Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -3790,7 +3790,7 @@ ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence &ICS, - AssignmentAction Action, + AssignmentAction Action, Sema::AssignConvertType& ConvType, CheckedConversionKind CCK) { // C++ [over.match.oper]p7: [...] operands of class type are converted [...] if (CCK == CCK_ForBuiltinOverloadedOp && !From->getType()->isRecordType()) @@ -3872,9 +3872,9 @@ case ImplicitConversionSequence::BadConversion: bool Diagnosed = - DiagnoseAssignmentResult(Incompatible, From->getExprLoc(), ToType, + DiagnoseAssignmentResult(ConvType==Compatible ? Incompatible : ConvType, + From->getExprLoc(), ToType, From->getType(), From, Action); - assert(Diagnosed && "failed to diagnose bad conversion"); (void)Diagnosed; return ExprError(); } @@ -5686,16 +5686,17 @@ switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) { case OR_Success: { // We found a match. Perform the conversions on the arguments and move on. + Sema::AssignConvertType ConvType = Sema::Compatible; ExprResult LHSRes = Self.PerformImplicitConversion( LHS.get(), Best->BuiltinParamTypes[0], Best->Conversions[0], - Sema::AA_Converting); + Sema::AA_Converting, ConvType); if (LHSRes.isInvalid()) break; LHS = LHSRes; ExprResult RHSRes = Self.PerformImplicitConversion( RHS.get(), Best->BuiltinParamTypes[1], Best->Conversions[1], - Sema::AA_Converting); + Sema::AA_Converting, ConvType); if (RHSRes.isInvalid()) break; RHS = RHSRes; Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -8171,9 +8171,10 @@ : Kind.isFunctionalCast()? Sema::CCK_FunctionalCast : Kind.isExplicitCast()? Sema::CCK_OtherCast : Sema::CCK_ImplicitConversion; + Sema::AssignConvertType ConvType = Sema::Compatible; ExprResult CurInitExprRes = S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS, - getAssignmentAction(Entity), CCK); + getAssignmentAction(Entity), ConvType, CCK); if (CurInitExprRes.isInvalid()) return ExprError(); Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -80,7 +80,8 @@ bool InOverloadResolution, StandardConversionSequence &SCS, bool CStyle, - bool AllowObjCWritebackConversion); + bool AllowObjCWritebackConversion, + Sema::AssignConvertType& ConvType); static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From, QualType &ToType, @@ -1424,10 +1425,11 @@ bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion, - bool AllowObjCConversionOnExplicit) { + bool AllowObjCConversionOnExplicit, + Sema::AssignConvertType& ConvType) { ImplicitConversionSequence ICS; if (IsStandardConversion(S, From, ToType, InOverloadResolution, - ICS.Standard, CStyle, AllowObjCWritebackConversion)){ + ICS.Standard, CStyle, AllowObjCWritebackConversion, ConvType)){ ICS.setStandard(); return ICS; } @@ -1479,11 +1481,12 @@ bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion) { + Sema::AssignConvertType ConvTy; return ::TryImplicitConversion(*this, From, ToType, SuppressUserConversions, AllowExplicit, InOverloadResolution, CStyle, AllowObjCWritebackConversion, - /*AllowObjCConversionOnExplicit=*/false); + /*AllowObjCConversionOnExplicit=*/false, ConvTy); } /// PerformImplicitConversion - Perform an implicit conversion of the @@ -1493,15 +1496,18 @@ /// explicit user-defined conversions are permitted. ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, - AssignmentAction Action, bool AllowExplicit) { + AssignmentAction Action, + /*Sema::AssignConvertType& ConvTy,*/ bool AllowExplicit) { ImplicitConversionSequence ICS; - return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS); + Sema::AssignConvertType ConvTy = Compatible; + return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS, ConvTy); } ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, - ImplicitConversionSequence& ICS) { + ImplicitConversionSequence& ICS, + Sema::AssignConvertType& ConvTy) { if (checkPlaceholderForOverload(*this, From)) return ExprError(); @@ -1518,8 +1524,9 @@ /*InOverloadResolution=*/false, /*CStyle=*/false, AllowObjCWritebackConversion, - /*AllowObjCConversionOnExplicit=*/false); - return PerformImplicitConversion(From, ToType, ICS, Action); + /*AllowObjCConversionOnExplicit=*/false, + ConvTy); + return PerformImplicitConversion(From, ToType, ICS, Action, ConvTy); } /// Determine whether the conversion from FromType to ToType is a valid @@ -1681,7 +1688,8 @@ bool InOverloadResolution, StandardConversionSequence &SCS, bool CStyle, - bool AllowObjCWritebackConversion) { + bool AllowObjCWritebackConversion, + Sema::AssignConvertType& ConvType) { QualType FromType = From->getType(); // Standard conversions (C++ [conv]) @@ -1949,7 +1957,7 @@ // 'noreturn' (Clang extension). SCS.Third = ICK_Function_Conversion; } else if (S.IsQualificationConversion(FromType, ToType, CStyle, - ObjCLifetimeConversion)) { + ObjCLifetimeConversion, ConvType)) { SCS.Third = ICK_Qualification; SCS.QualificationIncludesObjCLifetime = ObjCLifetimeConversion; FromType = ToType; @@ -2033,8 +2041,9 @@ RecordDecl *UD = UT->getDecl(); // It's compatible if the expression matches any of the fields. for (const auto *it : UD->fields()) { + Sema::AssignConvertType ConvType = Sema::Compatible; if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS, - CStyle, /*AllowObjCWritebackConversion=*/false)) { + CStyle, /*AllowObjCWritebackConversion=*/false, ConvType)) { ToType = it->getType(); return true; } @@ -3178,7 +3187,8 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType, bool CStyle, bool IsTopLevel, bool &PreviousToQualsIncludeConst, - bool &ObjCLifetimeConversion) { + bool &ObjCLifetimeConversion, + Sema::AssignConvertType& ConvType) { Qualifiers FromQuals = FromType.getQualifiers(); Qualifiers ToQuals = ToType.getQualifiers(); @@ -3218,11 +3228,14 @@ // superset in all cases apart from C-style casts where we allow // conversions between overlapping address spaces. // - in non-top levels it is not a valid conversion. - if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() && - (!IsTopLevel || - !(ToQuals.isAddressSpaceSupersetOf(FromQuals) || - (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals))))) + if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace()) { + if (!IsTopLevel) + ConvType = Sema::IncompatibleNestedPointerAddressSpaceMismatch; + else if ((ToQuals.isAddressSpaceSupersetOf(FromQuals) || + (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals)))) + return true; return false; + } // -- if the cv 1,j and cv 2,j are different, then const is in // every cv for 0 < k < j. @@ -3246,7 +3259,8 @@ /// object lifetime. bool Sema::IsQualificationConversion(QualType FromType, QualType ToType, - bool CStyle, bool &ObjCLifetimeConversion) { + bool CStyle, bool &ObjCLifetimeConversion, + Sema::AssignConvertType& ConvType) { FromType = Context.getCanonicalType(FromType); ToType = Context.getCanonicalType(ToType); ObjCLifetimeConversion = false; @@ -3264,7 +3278,7 @@ while (Context.UnwrapSimilarTypes(FromType, ToType)) { if (!isQualificationConversionStep( FromType, ToType, CStyle, !UnwrappedAnyPointer, - PreviousToQualsIncludeConst, ObjCLifetimeConversion)) + PreviousToQualsIncludeConst, ObjCLifetimeConversion, ConvType)) return false; UnwrappedAnyPointer = true; } @@ -3291,9 +3305,10 @@ return false; StandardConversionSequence InnerSCS; + Sema::AssignConvertType ConvType = Sema::Compatible; if (!IsStandardConversion(S, From, ToAtomic->getValueType(), InOverloadResolution, InnerSCS, - CStyle, /*AllowObjCWritebackConversion=*/false)) + CStyle, /*AllowObjCWritebackConversion=*/false, ConvType)) return false; SCS.Second = InnerSCS.Second; @@ -4508,9 +4523,10 @@ // If we find a qualifier mismatch, the types are not reference-compatible, // but are still be reference-related if they're similar. bool ObjCLifetimeConversion = false; + AssignConvertType ConvType = Compatible; if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel, PreviousToQualsIncludeConst, - ObjCLifetimeConversion)) + ObjCLifetimeConversion, ConvType)) return (ConvertedReferent || Context.hasSimilarType(T1, T2)) ? Ref_Related : Ref_Incompatible; @@ -4867,12 +4883,13 @@ // the argument expression. Any difference in top-level // cv-qualification is subsumed by the initialization itself // and does not constitute a conversion. + Sema::AssignConvertType ConvType = Sema::Compatible; ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions, /*AllowExplicit=*/false, /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false, - /*AllowObjCConversionOnExplicit=*/false); + /*AllowObjCConversionOnExplicit=*/false, ConvType); // Of course, that's still a reference binding. if (ICS.isStandard()) { @@ -5187,13 +5204,15 @@ /*FIXME:*/ From->getBeginLoc(), SuppressUserConversions, AllowExplicit); + Sema::AssignConvertType ConvType = Sema::Compatible; + return TryImplicitConversion(S, From, ToType, SuppressUserConversions, /*AllowExplicit=*/false, InOverloadResolution, /*CStyle=*/false, AllowObjCWritebackConversion, - /*AllowObjCConversionOnExplicit=*/false); + /*AllowObjCConversionOnExplicit=*/false, ConvType); } static bool TryCopyInitialization(const CanQualType FromQTy, @@ -5435,13 +5454,14 @@ /// expression From to bool (C++0x [conv]p3). static ImplicitConversionSequence TryContextuallyConvertToBool(Sema &S, Expr *From) { + Sema::AssignConvertType ConvType = Sema::Compatible; return TryImplicitConversion(S, From, S.Context.BoolTy, /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false, - /*AllowObjCConversionOnExplicit=*/false); + /*AllowObjCConversionOnExplicit=*/false, ConvType); } /// PerformContextuallyConvertToBool - Perform a contextual conversion @@ -5451,8 +5471,10 @@ return ExprError(); ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From); - if (!ICS.isBad()) - return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting); + if (!ICS.isBad()) { + Sema::AssignConvertType ConvType = Sema::Compatible; + return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting, ConvType); + } if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy)) return Diag(From->getBeginLoc(), diag::err_typecheck_bool_condition) @@ -5590,9 +5612,9 @@ diag::err_typecheck_converted_constant_expression_indirect) << From->getType() << From->getSourceRange() << T; } - + Sema::AssignConvertType ConvType = Sema::Compatible; ExprResult Result = - S.PerformImplicitConversion(From, T, ICS, Sema::AA_Converting); + S.PerformImplicitConversion(From, T, ICS, Sema::AA_Converting, ConvType); if (Result.isInvalid()) return Result; @@ -5705,6 +5727,7 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) { // Do an implicit conversion to 'id'. QualType Ty = S.Context.getObjCIdType(); + Sema::AssignConvertType ConvType = Sema::Compatible; ImplicitConversionSequence ICS = TryImplicitConversion(S, From, Ty, // FIXME: Are these flags correct? @@ -5713,7 +5736,7 @@ /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false, - /*AllowObjCConversionOnExplicit=*/true); + /*AllowObjCConversionOnExplicit=*/true, ConvType); // Strip off any final conversions to 'id'. switch (ICS.getKind()) { @@ -5744,8 +5767,10 @@ QualType Ty = Context.getObjCIdType(); ImplicitConversionSequence ICS = TryContextuallyConvertToObjCPointer(*this, From); - if (!ICS.isBad()) - return PerformImplicitConversion(From, Ty, ICS, AA_Converting); + if (!ICS.isBad()) { + Sema::AssignConvertType ConvType = Sema::Compatible; + return PerformImplicitConversion(From, Ty, ICS, AA_Converting, ConvType); + } return ExprResult(); } @@ -7108,8 +7133,9 @@ // Allow qualification conversions. bool ObjCLifetimeConversion; + Sema::AssignConvertType Conv = Sema::Compatible; if (S.IsQualificationConversion(ConvType, ToNonRefType, /*CStyle*/false, - ObjCLifetimeConversion)) + ObjCLifetimeConversion, Conv)) return true; // If we're not allowed to consider Objective-C pointer conversions, @@ -13000,9 +13026,10 @@ // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in // operator node. + Sema::AssignConvertType ConvType = Sema::Compatible; ExprResult InputRes = PerformImplicitConversion( Input, Best->BuiltinParamTypes[0], Best->Conversions[0], AA_Passing, - CCK_ForBuiltinOverloadedOp); + ConvType, CCK_ForBuiltinOverloadedOp); if (InputRes.isInvalid()) return ExprError(); Input = InputRes.get(); @@ -13391,16 +13418,17 @@ // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in // operator node. + Sema::AssignConvertType ConvType = Sema::Compatible; ExprResult ArgsRes0 = PerformImplicitConversion( Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0], - AA_Passing, CCK_ForBuiltinOverloadedOp); + AA_Passing, ConvType, CCK_ForBuiltinOverloadedOp); if (ArgsRes0.isInvalid()) return ExprError(); Args[0] = ArgsRes0.get(); ExprResult ArgsRes1 = PerformImplicitConversion( Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1], - AA_Passing, CCK_ForBuiltinOverloadedOp); + AA_Passing, ConvType, CCK_ForBuiltinOverloadedOp); if (ArgsRes1.isInvalid()) return ExprError(); Args[1] = ArgsRes1.get(); @@ -13713,16 +13741,17 @@ // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in // operator node. + Sema::AssignConvertType ConvType = Sema::Compatible; ExprResult ArgsRes0 = PerformImplicitConversion( Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0], - AA_Passing, CCK_ForBuiltinOverloadedOp); + AA_Passing, ConvType, CCK_ForBuiltinOverloadedOp); if (ArgsRes0.isInvalid()) return ExprError(); Args[0] = ArgsRes0.get(); ExprResult ArgsRes1 = PerformImplicitConversion( Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1], - AA_Passing, CCK_ForBuiltinOverloadedOp); + AA_Passing, ConvType, CCK_ForBuiltinOverloadedOp); if (ArgsRes1.isInvalid()) return ExprError(); Args[1] = ArgsRes1.get(); Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -5847,9 +5847,10 @@ !EvalResult.Val.getMemberPointerDecl())) { // If our expression has an appropriate type, we've succeeded. bool ObjCLifetimeConversion; + Sema::AssignConvertType ConvType = Sema::Compatible; if (S.Context.hasSameUnqualifiedType(Arg->getType(), ParamType) || S.IsQualificationConversion(Arg->getType(), ParamType, false, - ObjCLifetimeConversion)) + ObjCLifetimeConversion, ConvType)) return NPV_NullPointer; // The types didn't match, but we know we got a null pointer; complain, @@ -5884,10 +5885,11 @@ Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn, Expr *Arg, QualType ArgType) { bool ObjCLifetimeConversion; + Sema::AssignConvertType ConvType = Sema::Compatible; if (ParamType->isPointerType() && !ParamType->castAs()->getPointeeType()->isFunctionType() && S.IsQualificationConversion(ArgType, ParamType, false, - ObjCLifetimeConversion)) { + ObjCLifetimeConversion, ConvType)) { // For pointer-to-object types, qualification conversions are // permitted. } else { @@ -6303,10 +6305,10 @@ case NPV_NotNullPointer: break; } - + Sema::AssignConvertType ConvType = Sema::Compatible; if (S.IsQualificationConversion(ResultArg->getType(), ParamType.getNonReferenceType(), false, - ObjCLifetimeConversion)) { + ObjCLifetimeConversion, ConvType)) { ResultArg = S.ImpCastExprToType(ResultArg, ParamType, CK_NoOp, ResultArg->getValueKind()) .get(); Index: clang/lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- clang/lib/Sema/SemaTemplateDeduction.cpp +++ clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3286,9 +3286,10 @@ // function types (recursively). bool ObjCLifetimeConversion = false; QualType ResultTy; + Sema::AssignConvertType ConvType = Sema::Compatible; if ((A->isAnyPointerType() || A->isMemberPointerType()) && (S.IsQualificationConversion(A, DeducedA, false, - ObjCLifetimeConversion) || + ObjCLifetimeConversion, ConvType) || S.IsFunctionConversion(A, DeducedA, ResultTy))) return Sema::TDK_Success; Index: clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl =================================================================== --- clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl +++ clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl @@ -515,11 +515,7 @@ // Case 3: Corresponded inner pointees has overlapping but not equivalent address spaces. var_as_as_int = var_asc_asc_int; #ifdef GENERIC -#if !__OPENCL_CPP_VERSION__ -// expected-error@-3 {{assigning '__local int *__local *__private' to '__generic int *__generic *__private' changes address space of nested pointer}} -#else -// expected-error@-5 {{assigning to '__generic int *__generic *' from incompatible type '__local int *__local *__private'}} -#endif +// expected-error-re@-2{{assigning '__local int *__local *__private' to '__generic int *__generic {{\*|\*__private}}' changes address space of nested pointer}} #endif var_as_as_int = (AS int *AS *)var_asc_asc_int;