Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2229,7 +2229,8 @@ bool CheckPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath& BasePath, - bool IgnoreBaseAccess); + bool IgnoreBaseAccess, + bool Diagnose = true); bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType &ConvertedType); @@ -5388,7 +5389,8 @@ unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, - CXXCastPath *BasePath); + CXXCastPath *BasePath, + bool IgnoreAccess = false); std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); @@ -7514,14 +7516,15 @@ ObjCMethodDecl *&ClassMethod, ObjCMethodDecl *&InstanceMethod, TypedefNameDecl *&TDNDecl, - bool CfToNs); - + bool CfToNs, bool Diagnose = true); + bool CheckObjCBridgeRelatedConversions(SourceLocation Loc, QualType DestType, QualType SrcType, - Expr *&SrcExpr); - - bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr); - + Expr *&SrcExpr, bool Diagnose = true); + + bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr, + bool Diagnose = true); + bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); /// \brief Check whether the given new method is a valid override of the @@ -8606,6 +8609,7 @@ ARCConversionResult CheckObjCARCConversion(SourceRange castRange, QualType castType, Expr *&op, CheckedConversionKind CCK, + bool Diagnose = true, bool DiagnoseCFAudited = false, BinaryOperatorKind Opc = BO_PtrMemD ); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -1742,13 +1742,18 @@ /// otherwise. Loc is the location where this routine should point to /// if there is an error, and Range is the source range to highlight /// if there is an error. +/// +/// If either InaccessibleBaseID or AmbigiousBaseConvID are 0, then the +/// diagnostic for the respective type of error will be suppressed, but the +/// check for ill-formed code will still be performed. bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, - CXXCastPath *BasePath) { + CXXCastPath *BasePath, + bool IgnoreAccess) { // First, determine whether the path from Derived to Base is // ambiguous. This is slightly more expensive than checking whether // the Derived to Base conversion exists, because here we need to @@ -1761,7 +1766,7 @@ (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { - if (InaccessibleBaseID) { + if (!IgnoreAccess) { // Check that the base class can be accessed. switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), InaccessibleBaseID)) { @@ -1810,12 +1815,10 @@ SourceLocation Loc, SourceRange Range, CXXCastPath *BasePath, bool IgnoreAccess) { - return CheckDerivedToBaseConversion(Derived, Base, - IgnoreAccess ? 0 - : diag::err_upcast_to_inaccessible_base, - diag::err_ambiguous_derived_to_base_conv, - Loc, Range, DeclarationName(), - BasePath); + return CheckDerivedToBaseConversion( + Derived, Base, diag::err_upcast_to_inaccessible_base, + diag::err_ambiguous_derived_to_base_conv, Loc, Range, DeclarationName(), + BasePath, IgnoreAccess); } Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -7332,11 +7332,14 @@ LHSType->isBlockPointerType()) && RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - CastKind Kind; - CXXCastPath Path; - CheckPointerConversion(RHS.get(), LHSType, Kind, Path, false); - if (ConvertRHS) - RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path); + if (Diagnose || ConvertRHS) { + CastKind Kind; + CXXCastPath Path; + CheckPointerConversion(RHS.get(), LHSType, Kind, Path, + /*IgnoreBaseAccess=*/false, Diagnose); + if (ConvertRHS) + RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path); + } return Compatible; } @@ -7354,8 +7357,8 @@ } Expr *PRE = RHS.get()->IgnoreParenCasts(); - if (ObjCProtocolExpr *OPE = dyn_cast(PRE)) { - ObjCProtocolDecl *PDecl = OPE->getProtocol(); + if (Diagnose && isa(PRE)) { + ObjCProtocolDecl *PDecl = cast(PRE)->getProtocol(); if (PDecl && !PDecl->hasDefinition()) { Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl->getName(); Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl; @@ -7377,11 +7380,11 @@ Expr *E = RHS.get(); if (getLangOpts().ObjCAutoRefCount) CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion, - DiagnoseCFAudited); + Diagnose, DiagnoseCFAudited); if (getLangOpts().ObjC1 && - (CheckObjCBridgeRelatedConversions(E->getLocStart(), - LHSType, E->getType(), E) || - ConversionToObjCStringLiteralCheck(LHSType, E))) { + (CheckObjCBridgeRelatedConversions(E->getLocStart(), LHSType, + E->getType(), E, Diagnose) || + ConversionToObjCStringLiteralCheck(LHSType, E, Diagnose))) { RHS = E; return Compatible; } @@ -8939,8 +8942,9 @@ else { Expr *E = RHS.get(); if (getLangOpts().ObjCAutoRefCount) - CheckObjCARCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion, false, - Opc); + CheckObjCARCConversion(SourceRange(), LHSType, E, + CCK_ImplicitConversion, /*Diagnose=*/true, + /*DiagnoseCFAudited=*/false, Opc); RHS = ImpCastExprToType(E, LHSType, LPT ? CK_BitCast :CK_CPointerToObjCPointerCast); } @@ -11808,8 +11812,8 @@ return new (Context) GNUNullExpr(Ty, TokenLoc); } -bool -Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp) { +bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp, + bool Diagnose) { if (!getLangOpts().ObjC1) return false; @@ -11835,8 +11839,9 @@ StringLiteral *SL = dyn_cast(SrcExpr); if (!SL || !SL->isAscii()) return false; - Diag(SL->getLocStart(), diag::err_missing_atsign_prefix) - << FixItHint::CreateInsertion(SL->getLocStart(), "@"); + if (Diagnose) + Diag(SL->getLocStart(), diag::err_missing_atsign_prefix) + << FixItHint::CreateInsertion(SL->getLocStart(), "@"); Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get(); return true; } Index: lib/Sema/SemaExprObjC.cpp =================================================================== --- lib/Sema/SemaExprObjC.cpp +++ lib/Sema/SemaExprObjC.cpp @@ -3816,7 +3816,7 @@ ObjCMethodDecl *&ClassMethod, ObjCMethodDecl *&InstanceMethod, TypedefNameDecl *&TDNDecl, - bool CfToNs) { + bool CfToNs, bool Diagnose) { QualType T = CfToNs ? SrcType : DestType; ObjCBridgeRelatedAttr *ObjCBAttr = ObjCBridgeRelatedAttrFromType(T, TDNDecl); if (!ObjCBAttr) @@ -3832,20 +3832,24 @@ LookupResult R(*this, DeclarationName(RCId), SourceLocation(), Sema::LookupOrdinaryName); if (!LookupName(R, TUScope)) { - Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId - << SrcType << DestType; - Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Diagnose) { + Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId + << SrcType << DestType; + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + } return false; } Target = R.getFoundDecl(); if (Target && isa(Target)) RelatedClass = cast(Target); else { - Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId - << SrcType << DestType; - Diag(TDNDecl->getLocStart(), diag::note_declared_at); - if (Target) - Diag(Target->getLocStart(), diag::note_declared_at); + if (Diagnose) { + Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId + << SrcType << DestType; + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Target) + Diag(Target->getLocStart(), diag::note_declared_at); + } return false; } @@ -3854,9 +3858,11 @@ Selector Sel = Context.Selectors.getUnarySelector(CMId); ClassMethod = RelatedClass->lookupMethod(Sel, false); if (!ClassMethod) { - Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << Sel << false; - Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Diagnose) { + Diag(Loc, diag::err_objc_bridged_related_known_method) + << SrcType << DestType << Sel << false; + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + } return false; } } @@ -3866,9 +3872,11 @@ Selector Sel = Context.Selectors.getNullarySelector(IMId); InstanceMethod = RelatedClass->lookupMethod(Sel, true); if (!InstanceMethod) { - Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << Sel << true; - Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Diagnose) { + Diag(Loc, diag::err_objc_bridged_related_known_method) + << SrcType << DestType << Sel << true; + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + } return false; } } @@ -3878,7 +3886,7 @@ bool Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc, QualType DestType, QualType SrcType, - Expr *&SrcExpr) { + Expr *&SrcExpr, bool Diagnose) { ARCConversionTypeClass rhsExprACTC = classifyTypeForARCConversion(SrcType); ARCConversionTypeClass lhsExprACTC = classifyTypeForARCConversion(DestType); bool CfToNs = (rhsExprACTC == ACTC_coreFoundation && lhsExprACTC == ACTC_retainable); @@ -3891,27 +3899,29 @@ ObjCMethodDecl *InstanceMethod = nullptr; TypedefNameDecl *TDNDecl = nullptr; if (!checkObjCBridgeRelatedComponents(Loc, DestType, SrcType, RelatedClass, - ClassMethod, InstanceMethod, TDNDecl, CfToNs)) + ClassMethod, InstanceMethod, TDNDecl, + CfToNs, Diagnose)) return false; if (CfToNs) { // Implicit conversion from CF to ObjC object is needed. if (ClassMethod) { - std::string ExpressionString = "["; - ExpressionString += RelatedClass->getNameAsString(); - ExpressionString += " "; - ExpressionString += ClassMethod->getSelector().getAsString(); - SourceLocation SrcExprEndLoc = getLocForEndOfToken(SrcExpr->getLocEnd()); - // Provide a fixit: [RelatedClass ClassMethod SrcExpr] - Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << ClassMethod->getSelector() << false - << FixItHint::CreateInsertion(SrcExpr->getLocStart(), ExpressionString) - << FixItHint::CreateInsertion(SrcExprEndLoc, "]"); - Diag(RelatedClass->getLocStart(), diag::note_declared_at); - Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Diagnose) { + std::string ExpressionString = "["; + ExpressionString += RelatedClass->getNameAsString(); + ExpressionString += " "; + ExpressionString += ClassMethod->getSelector().getAsString(); + SourceLocation SrcExprEndLoc = getLocForEndOfToken(SrcExpr->getLocEnd()); + // Provide a fixit: [RelatedClass ClassMethod SrcExpr] + Diag(Loc, diag::err_objc_bridged_related_known_method) + << SrcType << DestType << ClassMethod->getSelector() << false + << FixItHint::CreateInsertion(SrcExpr->getLocStart(), ExpressionString) + << FixItHint::CreateInsertion(SrcExprEndLoc, "]"); + Diag(RelatedClass->getLocStart(), diag::note_declared_at); + Diag(TDNDecl->getLocStart(), diag::note_declared_at); + } - QualType receiverType = - Context.getObjCInterfaceType(RelatedClass); + QualType receiverType = Context.getObjCInterfaceType(RelatedClass); // Argument. Expr *args[] = { SrcExpr }; ExprResult msg = BuildClassMessageImplicit(receiverType, false, @@ -3925,30 +3935,34 @@ else { // Implicit conversion from ObjC type to CF object is needed. if (InstanceMethod) { - std::string ExpressionString; - SourceLocation SrcExprEndLoc = getLocForEndOfToken(SrcExpr->getLocEnd()); - if (InstanceMethod->isPropertyAccessor()) - if (const ObjCPropertyDecl *PDecl = InstanceMethod->findPropertyDecl()) { - // fixit: ObjectExpr.propertyname when it is aproperty accessor. - ExpressionString = "."; - ExpressionString += PDecl->getNameAsString(); + if (Diagnose) { + std::string ExpressionString; + SourceLocation SrcExprEndLoc = + getLocForEndOfToken(SrcExpr->getLocEnd()); + if (InstanceMethod->isPropertyAccessor()) + if (const ObjCPropertyDecl *PDecl = + InstanceMethod->findPropertyDecl()) { + // fixit: ObjectExpr.propertyname when it is aproperty accessor. + ExpressionString = "."; + ExpressionString += PDecl->getNameAsString(); + Diag(Loc, diag::err_objc_bridged_related_known_method) + << SrcType << DestType << InstanceMethod->getSelector() << true + << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString); + } + if (ExpressionString.empty()) { + // Provide a fixit: [ObjectExpr InstanceMethod] + ExpressionString = " "; + ExpressionString += InstanceMethod->getSelector().getAsString(); + ExpressionString += "]"; + Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << InstanceMethod->getSelector() << true - << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString); + << SrcType << DestType << InstanceMethod->getSelector() << true + << FixItHint::CreateInsertion(SrcExpr->getLocStart(), "[") + << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString); } - if (ExpressionString.empty()) { - // Provide a fixit: [ObjectExpr InstanceMethod] - ExpressionString = " "; - ExpressionString += InstanceMethod->getSelector().getAsString(); - ExpressionString += "]"; - - Diag(Loc, diag::err_objc_bridged_related_known_method) - << SrcType << DestType << InstanceMethod->getSelector() << true - << FixItHint::CreateInsertion(SrcExpr->getLocStart(), "[") - << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString); + Diag(RelatedClass->getLocStart(), diag::note_declared_at); + Diag(TDNDecl->getLocStart(), diag::note_declared_at); } - Diag(RelatedClass->getLocStart(), diag::note_declared_at); - Diag(TDNDecl->getLocStart(), diag::note_declared_at); ExprResult msg = BuildInstanceMessageImplicit(SrcExpr, SrcType, @@ -3965,6 +3979,7 @@ Sema::ARCConversionResult Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, Expr *&castExpr, CheckedConversionKind CCK, + bool Diagnose, bool DiagnoseCFAudited, BinaryOperatorKind Opc) { QualType castExprType = castExpr->getType(); @@ -3980,9 +3995,9 @@ if (exprACTC == castACTC) { // check for viablity and report error if casting an rvalue to a // life-time qualifier. - if ((castACTC == ACTC_retainable) && + if (Diagnose && castACTC == ACTC_retainable && (CCK == CCK_CStyleCast || CCK == CCK_OtherCast) && - (castType != castExprType)) { + castType != castExprType) { const Type *DT = castType.getTypePtr(); QualType QDT = castType; // We desugar some types but not others. We ignore those @@ -4051,19 +4066,20 @@ // to 'NSString *'. Let caller issue a normal mismatched diagnostic with // suitable fix-it. if (castACTC == ACTC_retainable && exprACTC == ACTC_none && - ConversionToObjCStringLiteralCheck(castType, castExpr)) + ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose)) return ACR_okay; // 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 (!DiagnoseCFAudited || exprACTC != ACTC_retainable || - castACTC != ACTC_coreFoundation) + if (Diagnose && + (!DiagnoseCFAudited || exprACTC != ACTC_retainable || + castACTC != ACTC_coreFoundation)) if (!(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable && (Opc == BO_NE || Opc == BO_EQ))) - diagnoseObjCARCConversion(*this, castRange, castType, castACTC, - castExpr, castExpr, exprACTC, CCK); + diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr, + castExpr, exprACTC, CCK); return ACR_okay; } Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -2686,15 +2686,16 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath& BasePath, - bool IgnoreBaseAccess) { + bool IgnoreBaseAccess, + bool Diagnose) { QualType FromType = From->getType(); bool IsCStyleOrFunctionalCast = IgnoreBaseAccess; Kind = CK_BitCast; - if (!IsCStyleOrFunctionalCast && !FromType->isAnyPointerType() && + if (Diagnose && !IsCStyleOrFunctionalCast && !FromType->isAnyPointerType() && From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) == - Expr::NPCK_ZeroExpression) { + Expr::NPCK_ZeroExpression) { if (Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy)) DiagRuntimeBehavior(From->getExprLoc(), From, PDiag(diag::warn_impcast_bool_to_null_pointer) @@ -2712,18 +2713,24 @@ !Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType)) { // We must have a derived-to-base conversion. Check an // ambiguous or inaccessible conversion. - if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType, - From->getExprLoc(), - From->getSourceRange(), &BasePath, - IgnoreBaseAccess)) + unsigned InaccessibleID = 0; + unsigned AmbigiousID = 0; + if (Diagnose) { + InaccessibleID = diag::err_upcast_to_inaccessible_base; + AmbigiousID = diag::err_ambiguous_derived_to_base_conv; + } + if (CheckDerivedToBaseConversion( + FromPointeeType, ToPointeeType, InaccessibleID, AmbigiousID, + From->getExprLoc(), From->getSourceRange(), DeclarationName(), + &BasePath, IgnoreBaseAccess)) return true; // The conversion was successful. Kind = CK_DerivedToBase; } - if (!IsCStyleOrFunctionalCast && FromPointeeType->isFunctionType() && - ToPointeeType->isVoidType()) { + if (Diagnose && !IsCStyleOrFunctionalCast && + FromPointeeType->isFunctionType() && ToPointeeType->isVoidType()) { assert(getLangOpts().MSVCCompat && "this should only be possible with MSVCCompat!"); Diag(From->getExprLoc(), diag::ext_ms_impcast_fn_obj) Index: test/SemaObjC/ovl-check.m =================================================================== --- /dev/null +++ test/SemaObjC/ovl-check.m @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -verify %s -fobjc-arc +// +// These tests exist as a means to help ensure that diagnostics aren't printed +// in overload resolution in ObjC. + +struct Type1 { int a; }; +@interface Iface1 @end + +@interface NeverCalled +- (void) test:(struct Type1 *)arg; +@end + +@interface TakesIface1 +- (void) test:(Iface1 *)arg; +@end + +// PR26085, rdar://problem/24111333 +void testTakesIface1(id x, Iface1 *arg) { + // This should resolve silently to `TakesIface1`. + [x test:arg]; +} + +@class NSString; +@interface NeverCalledv2 +- (void) testStr:(NSString *)arg; +@end + +@interface TakesVanillaConstChar +- (void) testStr:(const void *)a; +@end + +// Not called out explicitly by PR26085, but related. +void testTakesNSString(id x) { + // Overload resolution should not emit a diagnostic about needing to add an + // '@' before "someStringLiteral". + [x testStr:"someStringLiteral"]; +} + +typedef const void *CFTypeRef; +id CreateSomething(); + +@interface NeverCalledv3 +- (void) testCFTypeRef:(struct Type1 *)arg; +@end + +@interface TakesCFTypeRef +- (void) testCFTypeRef:(CFTypeRef)arg; +@end + +// Not called out explicitly by PR26085, but related. +void testTakesCFTypeRef(id x) { + // Overload resolution should occur silently, select the CFTypeRef overload, + // and produce a single complaint. (with notes) + [x testCFTypeRef:CreateSomething()]; // expected-error{{implicit conversion of Objective-C pointer type 'id' to C pointer type 'CFTypeRef'}} expected-note{{use __bridge}} expected-note{{use __bridge_retained}} +}