summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2017-07-15 11:06:46 +0000
committerJohn McCall <rjmccall@apple.com>2017-07-15 11:06:46 +0000
commitc93eca16e87860f8090db713c88b9c0d7dba7710 (patch)
treed9e40fb59fa3184db6dc30d4f6607d2d48fdcbae
parentdb5402516165f52f4c97200e95022b6e775bba1b (diff)
Use ARC parsing rules for ns_returns_retained in MRC so that code can
be shared without warnings. Build AttributedTypes to leave breadcrumbs for tools like the static analyzer. Warn about attempting to use the attribute with incompatible return types. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@308092 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Type.h1
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--lib/AST/Type.cpp2
-rw-r--r--lib/AST/TypePrinter.cpp73
-rw-r--r--lib/Sema/SemaDeclAttr.cpp15
-rw-r--r--lib/Sema/SemaType.cpp39
-rw-r--r--test/Analysis/retain-release.m2
-rw-r--r--test/SemaCXX/attr-x86-no_caller_saved_registers.cpp2
-rw-r--r--test/SemaObjC/attr-ns_returns_retained.m18
9 files changed, 107 insertions, 47 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 9eb6d81296..64bd3c7019 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -3878,6 +3878,7 @@ public:
attr_sptr,
attr_uptr,
attr_nonnull,
+ attr_ns_returns_retained,
attr_nullable,
attr_null_unspecified,
attr_objc_kindof,
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 95629a2591..49d626755e 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -8380,6 +8380,8 @@ public:
unsigned SpellingListIndex, bool isNSConsumed,
bool isTemplateInstantiation);
+ bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type);
+
//===--------------------------------------------------------------------===//
// C++ Coroutines TS
//
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index a62ca5f9b4..ad06346ba4 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -3023,6 +3023,7 @@ bool AttributedType::isQualifier() const {
case AttributedType::attr_sptr:
case AttributedType::attr_uptr:
case AttributedType::attr_objc_kindof:
+ case AttributedType::attr_ns_returns_retained:
return false;
}
llvm_unreachable("bad attributed type kind");
@@ -3056,6 +3057,7 @@ bool AttributedType::isCallingConv() const {
case attr_objc_inert_unsafe_unretained:
case attr_noreturn:
case attr_nonnull:
+ case attr_ns_returns_retained:
case attr_nullable:
case attr_null_unspecified:
case attr_objc_kindof:
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 0551340c37..55df0f4067 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -104,6 +104,7 @@ namespace {
void printAfter(QualType T, raw_ostream &OS);
void AppendScope(DeclContext *DC, raw_ostream &OS);
void printTag(TagDecl *T, raw_ostream &OS);
+ void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) \
void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \
@@ -685,6 +686,36 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
FunctionType::ExtInfo Info = T->getExtInfo();
+ printFunctionAfter(Info, OS);
+
+ if (unsigned quals = T->getTypeQuals()) {
+ OS << ' ';
+ AppendTypeQualList(OS, quals, Policy.Restrict);
+ }
+
+ switch (T->getRefQualifier()) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ OS << " &";
+ break;
+
+ case RQ_RValue:
+ OS << " &&";
+ break;
+ }
+ T->printExceptionSpecification(OS, Policy);
+
+ if (T->hasTrailingReturn()) {
+ OS << " -> ";
+ print(T->getReturnType(), OS, StringRef());
+ } else
+ printAfter(T->getReturnType(), OS);
+}
+
+void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
+ raw_ostream &OS) {
if (!InsideCCAttribute) {
switch (Info.getCC()) {
case CC_C:
@@ -747,36 +778,13 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
+ if (Info.getProducesResult())
+ OS << " __attribute__((ns_returns_retained))";
if (Info.getRegParm())
OS << " __attribute__((regparm ("
<< Info.getRegParm() << ")))";
if (Info.getNoCallerSavedRegs())
- OS << "__attribute__((no_caller_saved_registers))";
-
- if (unsigned quals = T->getTypeQuals()) {
- OS << ' ';
- AppendTypeQualList(OS, quals, Policy.Restrict);
- }
-
- switch (T->getRefQualifier()) {
- case RQ_None:
- break;
-
- case RQ_LValue:
- OS << " &";
- break;
-
- case RQ_RValue:
- OS << " &&";
- break;
- }
- T->printExceptionSpecification(OS, Policy);
-
- if (T->hasTrailingReturn()) {
- OS << " -> ";
- print(T->getReturnType(), OS, StringRef());
- } else
- printAfter(T->getReturnType(), OS);
+ OS << " __attribute__((no_caller_saved_registers))";
}
void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T,
@@ -795,8 +803,7 @@ void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T,
SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
OS << "()";
- if (T->getNoReturnAttr())
- OS << " __attribute__((noreturn))";
+ printFunctionAfter(T->getExtInfo(), OS);
printAfter(T->getReturnType(), OS);
}
@@ -1270,6 +1277,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
if (T->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained)
return;
+ // Don't print ns_returns_retained unless it had an effect.
+ if (T->getAttrKind() == AttributedType::attr_ns_returns_retained &&
+ !T->getEquivalentType()->castAs<FunctionType>()
+ ->getExtInfo().getProducesResult())
+ return;
+
// Print nullability type specifiers that occur after
if (T->getAttrKind() == AttributedType::attr_nonnull ||
T->getAttrKind() == AttributedType::attr_nullable ||
@@ -1361,6 +1374,10 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << ')';
break;
+ case AttributedType::attr_ns_returns_retained:
+ OS << "ns_returns_retained";
+ break;
+
// FIXME: When Sema learns to form this AttributedType, avoid printing the
// attribute again in printFunctionProtoAfter.
case AttributedType::attr_noreturn: OS << "noreturn"; break;
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 5fb79a6bf6..b90f3e765d 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -4679,6 +4679,16 @@ void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D,
CFConsumedAttr(attrRange, Context, spellingIndex));
}
+bool Sema::checkNSReturnsRetainedReturnType(SourceLocation loc,
+ QualType type) {
+ if (isValidSubjectOfNSReturnsRetainedAttribute(type))
+ return false;
+
+ Diag(loc, diag::warn_ns_attribute_wrong_return_type)
+ << "'ns_returns_retained'" << 0 << 0;
+ return true;
+}
+
static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
QualType returnType;
@@ -4700,6 +4710,8 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
<< Attr.getRange();
return;
}
+ } else if (Attr.isUsedAsTypeAttr()) {
+ return;
} else {
AttributeDeclKind ExpectedDeclKind;
switch (Attr.getKind()) {
@@ -4743,6 +4755,9 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
}
if (!typeOK) {
+ if (Attr.isUsedAsTypeAttr())
+ return;
+
if (isa<ParmVarDecl>(D)) {
S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
<< Attr.getName() << /*pointer-to-CF*/2
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index b19dcb2a50..598a11300b 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -120,6 +120,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
// Function type attributes.
#define FUNCTION_TYPE_ATTRS_CASELIST \
+ case AttributeList::AT_NSReturnsRetained: \
case AttributeList::AT_NoReturn: \
case AttributeList::AT_Regparm: \
case AttributeList::AT_AnyX86NoCallerSavedRegisters: \
@@ -640,12 +641,6 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
- case AttributeList::AT_NSReturnsRetained:
- if (!state.getSema().getLangOpts().ObjCAutoRefCount)
- break;
- // fallthrough
- LLVM_FALLTHROUGH;
-
FUNCTION_TYPE_ATTRS_CASELIST:
distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
@@ -2385,6 +2380,11 @@ QualType Sema::BuildFunctionType(QualType T,
[=](unsigned i) { return Loc; });
}
+ if (EPI.ExtInfo.getProducesResult()) {
+ // This is just a warning, so we can't fail to build if we see it.
+ checkNSReturnsRetainedReturnType(Loc, T);
+ }
+
if (Invalid)
return QualType();
@@ -5017,6 +5017,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_TypeNullUnspecified;
case AttributedType::attr_objc_kindof:
return AttributeList::AT_ObjCKindOf;
+ case AttributedType::attr_ns_returns_retained:
+ return AttributeList::AT_NSReturnsRetained;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -6373,17 +6375,26 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
// ns_returns_retained is not always a type attribute, but if we got
// here, we're treating it as one right now.
if (attr.getKind() == AttributeList::AT_NSReturnsRetained) {
- assert(S.getLangOpts().ObjCAutoRefCount &&
- "ns_returns_retained treated as type attribute in non-ARC");
if (attr.getNumArgs()) return true;
// Delay if this is not a function type.
if (!unwrapped.isFunctionType())
return false;
- FunctionType::ExtInfo EI
- = unwrapped.get()->getExtInfo().withProducesResult(true);
- type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ // Check whether the return type is reasonable.
+ if (S.checkNSReturnsRetainedReturnType(attr.getLoc(),
+ unwrapped.get()->getReturnType()))
+ return true;
+
+ // Only actually change the underlying type in ARC builds.
+ QualType origType = type;
+ if (state.getSema().getLangOpts().ObjCAutoRefCount) {
+ FunctionType::ExtInfo EI
+ = unwrapped.get()->getExtInfo().withProducesResult(true);
+ type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ }
+ type = S.Context.getAttributedType(AttributedType::attr_ns_returns_retained,
+ origType, type);
return true;
}
@@ -6945,12 +6956,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_NSReturnsRetained:
- if (!state.getSema().getLangOpts().ObjCAutoRefCount)
- break;
- // fallthrough into the function attrs
- LLVM_FALLTHROUGH;
-
FUNCTION_TYPE_ATTRS_CASELIST:
attr.setUsedAsTypeAttr();
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 39a3baa896..29af194a3d 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1447,7 +1447,7 @@ typedef NSString* MyStringTy;
+ (void) consume2:(id) CF_CONSUMED x;
@end
-static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}}
+static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' only applies to function types; type here is 'int'}}
void test_attr_1(TestOwnershipAttr *X) {
NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}}
diff --git a/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp b/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp
index 9ed6ae402a..55500519c4 100644
--- a/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp
+++ b/test/SemaCXX/attr-x86-no_caller_saved_registers.cpp
@@ -24,7 +24,7 @@ void foo6(){} // expected-note {{previous declaration is here}}
void __attribute__((no_caller_saved_registers)) foo6(); // expected-error {{function declared with 'no_caller_saved_registers' attribute was previously declared without the 'no_caller_saved_registers' attribute}}
int main(int argc, char **argv) {
- void (*fp)(int *) = foo; // expected-error {{cannot initialize a variable of type 'void (*)(int *)' with an lvalue of type 'void (int *)__attribute__((no_caller_saved_registers))'}}
+ void (*fp)(int *) = foo; // expected-error {{cannot initialize a variable of type 'void (*)(int *)' with an lvalue of type 'void (int *) __attribute__((no_caller_saved_registers))'}}
a::foo(&argc);
foo3 func = foo2;
func(&argc);
diff --git a/test/SemaObjC/attr-ns_returns_retained.m b/test/SemaObjC/attr-ns_returns_retained.m
new file mode 100644
index 0000000000..83397a6556
--- /dev/null
+++ b/test/SemaObjC/attr-ns_returns_retained.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fblocks -verify %s
+
+// rdar://20130079
+
+#if __has_feature(objc_arc)
+__attribute__((ns_returns_retained)) id (^invalidBlockRedecl)(); // expected-note {{previous definition is here}}
+id (^invalidBlockRedecl)(); //expected-error {{redefinition of 'invalidBlockRedecl' with a different type: 'id (^__strong)()' vs 'id ((^__strong))() __attribute__((ns_returns_retained))'}}
+#else
+__attribute__((ns_returns_retained)) id (^invalidBlockRedecl)();
+id (^invalidBlockRedecl)();
+#endif
+
+typedef __attribute__((ns_returns_retained)) id (^blockType)();
+
+typedef __attribute__((ns_returns_retained)) int (^invalidBlockType)(); // expected-warning {{'ns_returns_retained' attribute only applies to functions that return an Objective-C object}}
+
+__attribute__((ns_returns_retained)) int functionDecl(); // expected-warning {{'ns_returns_retained' attribute only applies to functions that return an Objective-C object}}