Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -8654,7 +8654,7 @@ Expr *CastExpr, SourceLocation RParenLoc); - enum ARCConversionResult { ACR_okay, ACR_unbridged }; + enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error }; /// \brief Checks for invalid conversions and casts between /// retainable pointers and other pointer kinds. Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -7566,15 +7566,23 @@ if (result != Incompatible && RHS.get()->getType() != LHSType) { QualType Ty = LHSType.getNonLValueExprType(Context); Expr *E = RHS.get(); - if (getLangOpts().ObjCAutoRefCount) - CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion, - Diagnose, DiagnoseCFAudited); + if (getLangOpts().ObjCAutoRefCount && + CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion, + Diagnose, DiagnoseCFAudited) != ACR_okay) { + if (!Diagnose) + result = Incompatible; + } if (getLangOpts().ObjC1 && (CheckObjCBridgeRelatedConversions(E->getLocStart(), LHSType, E->getType(), E, Diagnose) || ConversionToObjCStringLiteralCheck(LHSType, E, Diagnose))) { - RHS = E; - return Compatible; + if (Diagnose) { + // If an error was diagnosed here, replace the expression with a + // corrected version and continue so we can find further errors. + RHS = E; + return Compatible; + } + result = Incompatible; } if (ConvertRHS) @@ -12035,10 +12043,11 @@ StringLiteral *SL = dyn_cast(SrcExpr); if (!SL || !SL->isAscii()) return false; - if (Diagnose) + if (Diagnose) { Diag(SL->getLocStart(), diag::err_missing_atsign_prefix) << FixItHint::CreateInsertion(SL->getLocStart(), "@"); - Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get(); + Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get(); + } return true; } Index: lib/Sema/SemaExprObjC.cpp =================================================================== --- lib/Sema/SemaExprObjC.cpp +++ lib/Sema/SemaExprObjC.cpp @@ -3478,6 +3478,8 @@ return; QualType castExprType = castExpr->getType(); + // Defer emitting a diagnostic for bridge-related casts; that will be + // handled by CheckObjCBridgeRelatedConversions. TypedefNameDecl *TDNDecl = nullptr; if ((castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable && ObjCBridgeRelatedAttrFromType(castType, TDNDecl)) || @@ -3922,16 +3924,16 @@ << FixItHint::CreateInsertion(SrcExprEndLoc, "]"); Diag(RelatedClass->getLocStart(), diag::note_declared_at); Diag(TDNDecl->getLocStart(), diag::note_declared_at); - } - QualType receiverType = Context.getObjCInterfaceType(RelatedClass); - // Argument. - Expr *args[] = { SrcExpr }; - ExprResult msg = BuildClassMessageImplicit(receiverType, false, + QualType receiverType = Context.getObjCInterfaceType(RelatedClass); + // Argument. + Expr *args[] = { SrcExpr }; + ExprResult msg = BuildClassMessageImplicit(receiverType, false, ClassMethod->getLocation(), ClassMethod->getSelector(), ClassMethod, MultiExprArg(args, 1)); - SrcExpr = msg.get(); + SrcExpr = msg.get(); + } return true; } } @@ -3965,14 +3967,14 @@ } Diag(RelatedClass->getLocStart(), diag::note_declared_at); Diag(TDNDecl->getLocStart(), diag::note_declared_at); - } - ExprResult msg = - BuildInstanceMessageImplicit(SrcExpr, SrcType, - InstanceMethod->getLocation(), - InstanceMethod->getSelector(), - InstanceMethod, None); - SrcExpr = msg.get(); + ExprResult msg = + BuildInstanceMessageImplicit(SrcExpr, SrcType, + InstanceMethod->getLocation(), + InstanceMethod->getSelector(), + InstanceMethod, None); + SrcExpr = msg.get(); + } return true; } } @@ -3996,9 +3998,9 @@ ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType); ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType); if (exprACTC == castACTC) { - // check for viablity and report error if casting an rvalue to a + // Check for viability and report error if casting an rvalue to a // life-time qualifier. - if (Diagnose && castACTC == ACTC_retainable && + if (castACTC == ACTC_retainable && (CCK == CCK_CStyleCast || CCK == CCK_OtherCast) && castType != castExprType) { const Type *DT = castType.getTypePtr(); @@ -4014,10 +4016,12 @@ QDT = AT->desugar(); if (QDT != castType && QDT.getObjCLifetime() != Qualifiers::OCL_None) { - SourceLocation loc = - (castRange.isValid() ? castRange.getBegin() - : castExpr->getExprLoc()); - Diag(loc, diag::err_arc_nolifetime_behavior); + if (Diagnose) { + SourceLocation loc = (castRange.isValid() ? castRange.getBegin() + : castExpr->getExprLoc()); + Diag(loc, diag::err_arc_nolifetime_behavior); + } + return ACR_error; } } return ACR_okay; @@ -4065,24 +4069,26 @@ CCK != CCK_ImplicitConversion) return ACR_unbridged; - // Do not issue bridge cast" diagnostic when implicit casting a cstring - // to 'NSString *'. Let caller issue a normal mismatched diagnostic with - // suitable fix-it. + // Issue a diagnostic about a missing @-sign when implicit casting a cstring + // to 'NSString *', instead of falling through to report a "bridge cast" + // diagnostic. if (castACTC == ACTC_retainable && exprACTC == ACTC_none && ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose)) - return ACR_okay; + return ACR_error; // Do not issue "bridge cast" diagnostic when implicit casting // a retainable object to a CF type parameter belonging to an audited // CF API function. Let caller issue a normal type mismatched diagnostic // instead. - if (Diagnose && - (!DiagnoseCFAudited || exprACTC != ACTC_retainable || - castACTC != ACTC_coreFoundation)) - if (!(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable && - (Opc == BO_NE || Opc == BO_EQ))) + if ((!DiagnoseCFAudited || exprACTC != ACTC_retainable || + castACTC != ACTC_coreFoundation) && + !(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable && + (Opc == BO_NE || Opc == BO_EQ))) { + if (Diagnose) diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr, castExpr, exprACTC, CCK); + return ACR_error; + } return ACR_okay; } Index: test/SemaObjC/ovl-check.m =================================================================== --- test/SemaObjC/ovl-check.m +++ test/SemaObjC/ovl-check.m @@ -4,20 +4,24 @@ // in overload resolution in ObjC. struct Type1 { int a; }; +typedef const __attribute__((objc_bridge(id))) void * Type2; @interface Iface1 @end @interface NeverCalled - (void) test:(struct Type1 *)arg; +- (void) test2:(Type2 )arg; @end @interface TakesIface1 - (void) test:(Iface1 *)arg; +- (void) test2:(Iface1 *)arg; @end // PR26085, rdar://problem/24111333 void testTakesIface1(id x, Iface1 *arg) { // This should resolve silently to `TakesIface1`. [x test:arg]; + [x test2:arg]; } @class NSString;