aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-03-08 22:25:36 +0000
committerJordan Rose <jordan_rose@apple.com>2013-03-08 22:25:36 +0000
commit0918989f0eed08870e50418df97d1486d977d773 (patch)
tree1ee344ae7a85e8ed7078211121495d797b313bef
parentc61361b102fcb9be7b64cc493fb797ea551eb8e7 (diff)
Sema: Preserve attributes on parameters in instantiated function templates.
This was causing correctness issues for ARC and the static analyzer when a function template has "consumed" Objective-C object parameters (i.e. parameters that will be released by the function before returning). The fix is threefold: (1) Actually copy over the attributes from old ParmVarDecls to new ones. (2) Have Sema::BuildFunctionType only work for building FunctionProtoTypes, which it was doing anyway. This allows us to pass an ExtProtoInfo instead of a plain ExtInfo and several flags. (3) Drop param attributes as part of StripImplicitInstantiation, which is used when an implicit instantiation is followed by an explicit one. <rdar://problem/12685622> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176728 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Sema/Sema.h16
-rw-r--r--lib/Sema/SemaTemplate.cpp6
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp6
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp4
-rw-r--r--lib/Sema/SemaType.cpp12
-rw-r--r--lib/Sema/TreeTransform.h28
-rw-r--r--test/CodeGenObjCXX/arc-attrs.mm48
-rw-r--r--test/SemaObjCXX/arc-nsconsumed-errors.mm32
8 files changed, 103 insertions, 49 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index b0d3ad865b..29c1f77aa0 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -959,12 +959,6 @@ public:
/// will be modified to account for adjustments to the types of the
/// function parameters.
///
- /// \param Variadic Whether this is a variadic function type.
- ///
- /// \param HasTrailingReturn Whether this function has a trailing return type.
- ///
- /// \param Quals The cvr-qualifiers to be applied to the function type.
- ///
/// \param Loc The location of the entity whose type involves this
/// function type or, if there is no such entity, the location of the
/// type that will have function type.
@@ -972,14 +966,16 @@ public:
/// \param Entity The name of the entity that involves the function
/// type, if known.
///
- /// \returns A suitable function type, if there are no errors.
+ /// \param EPI Extra information about the function type. Usually this will
+ /// be taken from an existing function with the same prototype.
+ ///
+ /// \returns A suitable function type, if there are no errors. The
+ /// unqualified type will always be a FunctionProtoType.
/// Otherwise, returns a NULL type.
QualType BuildFunctionType(QualType T,
llvm::MutableArrayRef<QualType> ParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals, RefQualifierKind RefQualifier,
SourceLocation Loc, DeclarationName Entity,
- FunctionType::ExtInfo Info);
+ const FunctionProtoType::ExtProtoInfo &EPI);
QualType BuildMemberPointerType(QualType T, QualType Class,
SourceLocation Loc,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 75f255e945..fd0641995b 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -5648,11 +5648,15 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
- // FIXME: "make check" is clean if the call to dropAttrs() is commented out.
D->dropAttrs();
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
FD->setInlineSpecified(false);
+
+ for (FunctionDecl::param_iterator I = FD->param_begin(),
+ E = FD->param_end();
+ I != E; ++I)
+ (*I)->dropAttrs();
}
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index c479895c4b..f3bbe8a0f1 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2418,13 +2418,9 @@ Sema::SubstituteExplicitTemplateArguments(
if (FunctionType) {
*FunctionType = BuildFunctionType(ResultType, ParamTypes,
- Proto->isVariadic(),
- Proto->hasTrailingReturn(),
- Proto->getTypeQuals(),
- Proto->getRefQualifier(),
Function->getLocation(),
Function->getDeclName(),
- Proto->getExtInfo());
+ Proto->getExtProtoInfo());
if (FunctionType->isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 79e16f3942..255df80d66 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1716,7 +1716,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
OldParm->getFunctionScopeIndex() + indexAdjustment);
-
+
+ InstantiateAttrs(TemplateArgs, OldParm, NewParm);
+
return NewParm;
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index fb25a16c01..e9ccbecaba 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1632,11 +1632,8 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
QualType Sema::BuildFunctionType(QualType T,
llvm::MutableArrayRef<QualType> ParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
SourceLocation Loc, DeclarationName Entity,
- FunctionType::ExtInfo Info) {
+ const FunctionProtoType::ExtProtoInfo &EPI) {
if (T->isArrayType() || T->isFunctionType()) {
Diag(Loc, diag::err_func_returning_array_function)
<< T->isFunctionType() << T;
@@ -1670,13 +1667,6 @@ QualType Sema::BuildFunctionType(QualType T,
if (Invalid)
return QualType();
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.Variadic = Variadic;
- EPI.HasTrailingReturn = HasTrailingReturn;
- EPI.TypeQuals = Quals;
- EPI.RefQualifier = RefQualifier;
- EPI.ExtInfo = Info;
-
return Context.getFunctionType(T, ParamTypes, EPI);
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index af82abac93..7112e7d5f3 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -714,10 +714,7 @@ public:
/// Subclasses may override this routine to provide different behavior.
QualType RebuildFunctionProtoType(QualType T,
llvm::MutableArrayRef<QualType> ParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
- const FunctionType::ExtInfo &Info);
+ const FunctionProtoType::ExtProtoInfo &EPI);
/// \brief Build a new unprototyped function type.
QualType RebuildFunctionNoProtoType(QualType ResultType);
@@ -4266,11 +4263,7 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
T->getNumArgs() != ParamTypes.size() ||
!std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) {
Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes,
- T->isVariadic(),
- T->hasTrailingReturn(),
- T->getTypeQuals(),
- T->getRefQualifier(),
- T->getExtInfo());
+ T->getExtProtoInfo());
if (Result.isNull())
return QualType();
}
@@ -8834,7 +8827,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
return ExprError();
}
- const FunctionType *exprFunctionType = E->getFunctionType();
+ const FunctionProtoType *exprFunctionType = E->getFunctionType();
QualType exprResultType =
getDerived().TransformType(exprFunctionType->getResultType());
@@ -8849,9 +8842,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
QualType functionType =
getDerived().RebuildFunctionProtoType(exprResultType, paramTypes,
- oldBlock->isVariadic(),
- false, 0, RQ_None,
- exprFunctionType->getExtInfo());
+ exprFunctionType->getExtProtoInfo());
blockScope->FunctionType = functionType;
// Set the parameters on the block decl.
@@ -9070,16 +9061,11 @@ template<typename Derived>
QualType TreeTransform<Derived>::RebuildFunctionProtoType(
QualType T,
llvm::MutableArrayRef<QualType> ParamTypes,
- bool Variadic,
- bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
- const FunctionType::ExtInfo &Info) {
- return SemaRef.BuildFunctionType(T, ParamTypes, Variadic,
- HasTrailingReturn, Quals, RefQualifier,
+ const FunctionProtoType::ExtProtoInfo &EPI) {
+ return SemaRef.BuildFunctionType(T, ParamTypes,
getDerived().getBaseLocation(),
getDerived().getBaseEntity(),
- Info);
+ EPI);
}
template<typename Derived>
diff --git a/test/CodeGenObjCXX/arc-attrs.mm b/test/CodeGenObjCXX/arc-attrs.mm
new file mode 100644
index 0000000000..57ccb6cdea
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-attrs.mm
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-arc -O0 -o - %s | FileCheck %s
+
+id makeObject1() __attribute__((ns_returns_retained));
+id makeObject2() __attribute__((ns_returns_retained));
+void releaseObject(__attribute__((ns_consumed)) id);
+
+// CHECK: define void @_Z10sanityTestv
+void sanityTest() {
+ // CHECK: [[X:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z11makeObject1v()
+ // CHECK-NEXT: store i8* [[OBJ1]], i8** [[X]], align 8
+ id x = makeObject1();
+
+ // CHECK-NEXT: [[OBJ2:%.*]] = call i8* @_Z11makeObject2v()
+ // CHECK-NEXT: call void @_Z13releaseObjectP11objc_object(i8* [[OBJ2]])
+ releaseObject(makeObject2());
+
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+ // CHECK-NEXT: ret void
+}
+
+
+template <typename T>
+T makeObjectT1() __attribute__((ns_returns_retained));
+template <typename T>
+T makeObjectT2() __attribute__((ns_returns_retained));
+
+template <typename T>
+void releaseObjectT(__attribute__((ns_consumed)) T);
+
+// CHECK: define void @_Z12templateTestv
+void templateTest() {
+ // CHECK: [[X:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z12makeObjectT1IU8__strongP11objc_objectET_v()
+ // CHECK-NEXT: store i8* [[OBJ1]], i8** [[X]], align 8
+ id x = makeObjectT1<id>();
+
+ // CHECK-NEXT: [[OBJ2:%.*]] = call i8* @_Z12makeObjectT2IU8__strongP11objc_objectET_v()
+ // CHECK-NEXT: call void @_Z13releaseObjectP11objc_object(i8* [[OBJ2]])
+ releaseObject(makeObjectT2<id>());
+
+ // CHECK-NEXT: [[OBJ3:%.*]] = call i8* @_Z11makeObject1v()
+ // CHECK-NEXT: call void @_Z14releaseObjectTIU8__strongP11objc_objectEvT_(i8* [[OBJ3]])
+ releaseObjectT(makeObject1());
+
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+ // CHECK-NEXT: ret void
+}
diff --git a/test/SemaObjCXX/arc-nsconsumed-errors.mm b/test/SemaObjCXX/arc-nsconsumed-errors.mm
index 93f5d99967..10ae10d049 100644
--- a/test/SemaObjCXX/arc-nsconsumed-errors.mm
+++ b/test/SemaObjCXX/arc-nsconsumed-errors.mm
@@ -18,3 +18,35 @@ blk1 b2 = ^void (id, __attribute((ns_consumed)) id){}; // expected-error {{canno
blk1 c3 = ^void (__attribute((ns_consumed)) id, __attribute((ns_consumed)) id){};
blk1 d4 = ^void (id, id) {}; // expected-error {{cannot initialize a variable of type '__strong blk1'}}
+
+
+typedef void (*releaser_t)(__attribute__((ns_consumed)) id);
+
+void normalFunction(id);
+releaser_t r1 = normalFunction; // expected-error {{cannot initialize a variable of type 'releaser_t'}}
+
+void releaser(__attribute__((ns_consumed)) id);
+releaser_t r2 = releaser; // no-warning
+
+template <typename T>
+void templateFunction(T) {} // expected-note {{candidate function}}
+releaser_t r3 = templateFunction<id>; // expected-error {{address of overloaded function 'templateFunction' does not match required type 'void (id)'}}
+
+template <typename T>
+void templateReleaser(__attribute__((ns_consumed)) T) {}
+releaser_t r4 = templateReleaser<id>; // no-warning
+
+
+@class AntiRelease, ExplicitAntiRelease, ProRelease;
+
+template<>
+void templateFunction(__attribute__((ns_consumed)) AntiRelease *); // expected-error {{no function template matches function template specialization 'templateFunction'}}
+
+template<>
+void templateReleaser(AntiRelease *); // expected-error {{no function template matches function template specialization 'templateReleaser'}}
+
+template<>
+void templateReleaser(ExplicitAntiRelease *) {} // expected-error {{no function template matches function template specialization 'templateReleaser'}}
+
+template<>
+void templateReleaser(__attribute__((ns_consumed)) ProRelease *); // no-warning