From: Douglas Gregor Date: Thu, 17 Jan 2013 23:36:45 +0000 (+0000) Subject: In Objective-C ARC, completely ignore ownership qualifiers on the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=02dd79830979e6d83d4420377e8f4c9e4a77439b;p=clang In Objective-C ARC, completely ignore ownership qualifiers on the return type of a function by canonicalizing them away. They are useless anyway, and conflict with our rules for template argument deduction and __strong. Fixes . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172768 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 328bebe9af..c23d9eee48 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3763,6 +3763,10 @@ def err_arc_collection_forward : Error< def err_arc_multiple_method_decl : Error< "multiple methods named %0 found with mismatched result, " "parameter type or attributes">; +def warn_arc_lifetime_result_type : Warning< + "ARC %select{unused|__unsafe_unretained|__strong|__weak|__autoreleasing}0 " + "lifetime qualifier on return type is ignored">, + InGroup; let CategoryName = "ARC Retain Cycle" in { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index df64237f70..ace9dc0146 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2602,6 +2602,13 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy, return QualType(New, 0); } +/// \brief Determine whether \p T is canonical as the result type of a function. +static bool isCanonicalResultType(QualType T) { + return T.isCanonical() && + (T.getObjCLifetime() == Qualifiers::OCL_None || + T.getObjCLifetime() == Qualifiers::OCL_ExplicitNone); +} + /// getFunctionType - Return a normal function type with a typed argument /// list. isVariadic indicates whether the argument list includes '...'. QualType @@ -2620,7 +2627,7 @@ ASTContext::getFunctionType(QualType ResultTy, // Determine whether the type being created is already canonical or not. bool isCanonical = - EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical() && + EPI.ExceptionSpecType == EST_None && isCanonicalResultType(ResultTy) && !EPI.HasTrailingReturn; for (unsigned i = 0; i != NumArgs && isCanonical; ++i) if (!ArgArray[i].isCanonicalAsParam()) @@ -2646,7 +2653,15 @@ ASTContext::getFunctionType(QualType ResultTy, CanonicalEPI.ExtInfo = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv)); - Canonical = getFunctionType(getCanonicalType(ResultTy), + // Result types do not have ARC lifetime qualifiers. + QualType CanResultTy = getCanonicalType(ResultTy); + if (ResultTy.getQualifiers().hasObjCLifetime()) { + Qualifiers Qs = CanResultTy.getQualifiers(); + Qs.removeObjCLifetime(); + CanResultTy = getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); + } + + Canonical = getFunctionType(CanResultTy, CanonicalArgs.data(), NumArgs, CanonicalEPI); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 15aa39b7e4..35816a42f3 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2471,6 +2471,44 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S); } + // Objective-C ARC ownership qualifiers are ignored on the function + // return type (by type canonicalization). Complain if this attribute + // was written here. + if (T.getQualifiers().hasObjCLifetime()) { + SourceLocation AttrLoc; + if (chunkIndex + 1 < D.getNumTypeObjects()) { + DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1); + for (const AttributeList *Attr = ReturnTypeChunk.getAttrs(); + Attr; Attr = Attr->getNext()) { + if (Attr->getKind() == AttributeList::AT_ObjCOwnership) { + AttrLoc = Attr->getLoc(); + break; + } + } + } + if (AttrLoc.isInvalid()) { + for (const AttributeList *Attr + = D.getDeclSpec().getAttributes().getList(); + Attr; Attr = Attr->getNext()) { + if (Attr->getKind() == AttributeList::AT_ObjCOwnership) { + AttrLoc = Attr->getLoc(); + break; + } + } + } + + if (AttrLoc.isValid()) { + // The ownership attributes are almost always written via + // the predefined + // __strong/__weak/__autoreleasing/__unsafe_unretained. + if (AttrLoc.isMacroID()) + AttrLoc = S.SourceMgr.getImmediateExpansionRange(AttrLoc).first; + + S.Diag(AttrLoc, diag::warn_arc_lifetime_result_type) + << T.getQualifiers().getObjCLifetime(); + } + } + if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) { // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. diff --git a/test/SemaObjC/arc-objc-lifetime.m b/test/SemaObjC/arc-objc-lifetime.m index 08d2dbe16c..f2fb139322 100644 --- a/test/SemaObjC/arc-objc-lifetime.m +++ b/test/SemaObjC/arc-objc-lifetime.m @@ -67,3 +67,22 @@ typedef void (^T) (); - (void)createInferiorTransportAndSetEnvironment:(NSMutableDictionary*)environment error:(__autoreleasing NSError**)error {} @end +// +typedef __strong id strong_id; +typedef NSObject *NSObject_ptr; +typedef __strong NSObject *strong_NSObject_ptr; + +// Warn +__strong id f1(); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}} +NSObject __unsafe_unretained *f2(int); // expected-warning{{ARC __unsafe_unretained lifetime qualifier on return type is ignored}} +__autoreleasing NSObject *f3(void); // expected-warning{{ARC __autoreleasing lifetime qualifier on return type is ignored}} +NSObject * __strong f4(void); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}} +NSObject_ptr __strong f5(); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}} + +typedef __strong id (*fptr)(int); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}} +typedef __strong id (^block_ptr)(int); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}} + +// Don't warn +strong_id f6(); +strong_NSObject_ptr f7(); + diff --git a/test/SemaObjCXX/arc-templates.mm b/test/SemaObjCXX/arc-templates.mm index 80092729d3..ef68b94e72 100644 --- a/test/SemaObjCXX/arc-templates.mm +++ b/test/SemaObjCXX/arc-templates.mm @@ -283,3 +283,12 @@ namespace rdar10862386 { testing(@"hi"); } } + +namespace rdar12367446 { + template class A; + template class A {}; + + void test() { + A value; + } +}