From 8a0210e535c5dc712f03bb323242e4d9bfa89fd8 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Sat, 16 Nov 2013 19:16:32 +0000 Subject: [PATCH] ObjectiveC ARC. Validate toll free bridge casting of ObjectiveC objects to CF types when CF type has the objc_bridge attribute. llvm-svn: 194930 --- .../clang/Basic/DiagnosticSemaKinds.td | 6 ++- clang/lib/Sema/SemaExprObjC.cpp | 54 +++++++++++++++++-- clang/test/SemaObjC/objcbridge-attribute.m | 6 ++- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 48d62cb1f501..22db61dde426 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2447,10 +2447,14 @@ def err_objc_bridge_not_cftype : Error< "'objc_bridge' attribute must be applied to definition of CF types">; def err_objc_bridge_not_pointert_to_struct : Error< "'objc_bridge' attribute must be applied to a pointer to struct type">; -def err_objc_bridged_not_interface : Error< +def err_objc_cf_bridged_not_interface : Error< "CF object of type %0 is bridged to '%1', which is not an Objective-C class">; +def err_objc_ns_bridged_invalid_cfobject : Error< + "ObjectiveC object of type %0 is bridged to %1, which is not valid CF object">; def warn_objc_invalid_bridge : Warning< "%0 bridges to %1, not %2">, InGroup; +def warn_objc_invalid_bridge_to_cf : Warning< + "%0 cannot bridge to %1">, InGroup; // Function Parameter Semantic Analysis. def err_param_with_void_type : Error<"argument may not have 'void' type">; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index f226af3ae0af..ea1f2a98e3dd 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -3165,7 +3165,7 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, << castRange << castExpr->getSourceRange(); } -static bool CheckObjCBridgeCast(Sema &S, QualType castType, Expr *castExpr) { +static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) { QualType T = castExpr->getType(); while (const TypedefType *TD = dyn_cast(T.getTypePtr())) { TypedefNameDecl *TDNDecl = TD->getDecl(); @@ -3193,7 +3193,7 @@ static bool CheckObjCBridgeCast(Sema &S, QualType castType, Expr *castExpr) { } } } - S.Diag(castExpr->getLocStart(), diag::err_objc_bridged_not_interface) + S.Diag(castExpr->getLocStart(), diag::err_objc_cf_bridged_not_interface) << castExpr->getType() << Parm->getName(); S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); if (Target) @@ -3206,6 +3206,49 @@ static bool CheckObjCBridgeCast(Sema &S, QualType castType, Expr *castExpr) { return false; } +// (CFErrorRef)ns +static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) { + QualType T = castType; + while (const TypedefType *TD = dyn_cast(T.getTypePtr())) { + TypedefNameDecl *TDNDecl = TD->getDecl(); + if (TDNDecl->hasAttr()) { + ObjCBridgeAttr *ObjCBAttr = TDNDecl->getAttr(); + IdentifierInfo *Parm = ObjCBAttr->getBridgedType(); + NamedDecl *Target = 0; + if (Parm && S.getLangOpts().ObjC1) { + // Check for an existing type with this name. + LookupResult R(S, DeclarationName(Parm), SourceLocation(), + Sema::LookupOrdinaryName); + if (S.LookupName(R, S.TUScope)) { + Target = R.getFoundDecl(); + if (Target && isa(Target)) { + ObjCInterfaceDecl *CastClass = cast(Target); + if (const ObjCObjectPointerType *InterfacePointerType = + castExpr->getType()->getAsObjCInterfacePointerType()) { + ObjCInterfaceDecl *ExprClass + = InterfacePointerType->getObjectType()->getInterface(); + if ((CastClass == ExprClass) || (ExprClass && CastClass->isSuperClassOf(ExprClass))) + return true; + S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf) + << ExprClass->getName() << TDNDecl->getName(); + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + return true; + } + } + } + S.Diag(castExpr->getLocStart(), diag::err_objc_ns_bridged_invalid_cfobject) + << castExpr->getType() << castType; + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Target) + S.Diag(Target->getLocStart(), diag::note_declared_at); + } + return true; + } + T = TDNDecl->getUnderlyingType(); + } + return false; +} + Sema::ARCConversionResult Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, Expr *&castExpr, CheckedConversionKind CCK, @@ -3266,7 +3309,12 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation && (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast)) - if (CheckObjCBridgeCast(*this, castType, castExpr)) + if (CheckObjCBridgeNSCast(*this, castType, castExpr)) + return ACR_okay; + + if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable && + (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast)) + if (CheckObjCBridgeCFCast(*this, castType, castExpr)) return ACR_okay; diff --git a/clang/test/SemaObjC/objcbridge-attribute.m b/clang/test/SemaObjC/objcbridge-attribute.m index 4379c6fc8e93..d961528ebdea 100644 --- a/clang/test/SemaObjC/objcbridge-attribute.m +++ b/clang/test/SemaObjC/objcbridge-attribute.m @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s // rdar://15454846 -typedef struct __CFErrorRef * __attribute__ ((objc_bridge(NSError))) CFErrorRef; +typedef struct __CFErrorRef * __attribute__ ((objc_bridge(NSError))) CFErrorRef; // expected-note {{declared here}} typedef struct __CFMyColor * __attribute__((objc_bridge(12))) CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}} @@ -48,8 +48,10 @@ typedef CFErrorRef1 CFErrorRef2; @class NSString; -void Test2(CFErrorRef2 cf) { +void Test2(CFErrorRef2 cf, NSError *ns, NSString *str) { (void)(NSString *)cf; // expected-warning {{CFErrorRef bridges to NSError, not NSString}} (void)(NSError *)cf; // okay (void)(MyError*)cf; // okay, + (void)(CFErrorRef)ns; // okay + (void)(CFErrorRef)str; // expected-warning {{NSString cannot bridge to CFErrorRef}} }