diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 58 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/attr-cleanup.cpp | 11 | ||||
| -rw-r--r-- | clang/test/Sema/attr-cleanup.c | 14 | ||||
| -rw-r--r-- | clang/test/SemaCXX/attr-cleanup-gcc.cpp | 16 | ||||
| -rw-r--r-- | clang/test/SemaCXX/attr-cleanup.cpp | 10 | ||||
| -rw-r--r-- | clang/utils/TableGen/ClangAttrEmitter.cpp | 1 |
7 files changed, 82 insertions, 34 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e06560b55a7..a1101f918d0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2350,10 +2350,14 @@ def err_attribute_sentinel_less_than_zero : Error< "'sentinel' parameter 1 less than zero">; def err_attribute_sentinel_not_zero_or_one : Error< "'sentinel' parameter 2 not 0 or 1">; +def warn_cleanup_ext : Warning< + "GCC does not allow the 'cleanup' attribute argument to be anything other " + "than a simple identifier">, + InGroup<GccCompat>; def err_attribute_cleanup_arg_not_found : Error< "'cleanup' argument %0 not found">; def err_attribute_cleanup_arg_not_function : Error< - "'cleanup' argument %0 is not a function">; + "'cleanup' argument %select{|%1 }0is not a function">; def err_attribute_cleanup_func_must_take_one_arg : Error< "'cleanup' function %0 must take 1 parameter">; def err_attribute_cleanup_func_arg_incompatible_type : Error< diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 78640d62df4..47b130888f9 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2831,40 +2831,44 @@ static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; - return; - } - VarDecl *VD = dyn_cast<VarDecl>(D); - if (!VD || !VD->hasLocalStorage()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup"; + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); return; } - IdentifierLoc *IL = Attr.getArgAsIdent(0); - - // Look up the function - // FIXME: Lookup probably isn't looking in the right place - NamedDecl *CleanupDecl - = S.LookupSingleName(S.TUScope, IL->Ident, IL->Loc, - Sema::LookupOrdinaryName); - if (!CleanupDecl) { - S.Diag(IL->Loc, diag::err_attribute_cleanup_arg_not_found) << IL->Ident; - return; - } + Expr *E = Attr.getArgAsExpr(0); + SourceLocation Loc = E->getExprLoc(); + FunctionDecl *FD = 0; + DeclarationNameInfo NI; + + // gcc only allows for simple identifiers. Since we support more than gcc, we + // will warn the user. + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (DRE->hasQualifier()) + S.Diag(Loc, diag::warn_cleanup_ext); + FD = dyn_cast<FunctionDecl>(DRE->getDecl()); + NI = DRE->getNameInfo(); + if (!FD) { + S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 1 + << NI.getName(); + return; + } + } else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { + if (ULE->hasExplicitTemplateArgs()) + S.Diag(Loc, diag::warn_cleanup_ext); - FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl); - if (!FD) { - S.Diag(IL->Loc, diag::err_attribute_cleanup_arg_not_function) << IL->Ident; + // This will diagnose the case where the function cannot be found. + FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); + NI = ULE->getNameInfo(); + } else { + S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 0; return; } if (FD->getNumParams() != 1) { - S.Diag(IL->Loc, diag::err_attribute_cleanup_func_must_take_one_arg) - << IL->Ident; + S.Diag(Loc, diag::err_attribute_cleanup_func_must_take_one_arg) + << NI.getName(); return; } @@ -2874,16 +2878,14 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { QualType ParamTy = FD->getParamDecl(0)->getType(); if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(), ParamTy, Ty) != Sema::Compatible) { - S.Diag(IL->Loc, diag::err_attribute_cleanup_func_arg_incompatible_type) << - IL->Ident << ParamTy << Ty; + S.Diag(Loc, diag::err_attribute_cleanup_func_arg_incompatible_type) + << NI.getName() << ParamTy << Ty; return; } D->addAttr(::new (S.Context) CleanupAttr(Attr.getRange(), S.Context, FD, Attr.getAttributeSpellingListIndex())); - S.MarkFunctionReferenced(IL->Loc, FD); - S.DiagnoseUseOfDecl(FD, IL->Loc); } /// Handle __attribute__((format_arg((idx)))) attribute based on diff --git a/clang/test/CodeGenCXX/attr-cleanup.cpp b/clang/test/CodeGenCXX/attr-cleanup.cpp new file mode 100644 index 00000000000..03f9481470e --- /dev/null +++ b/clang/test/CodeGenCXX/attr-cleanup.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+namespace N {
+ void free(void *i) {}
+}
+
+int main(void) {
+ // CHECK: call void @_ZN1N4freeEPv(i8* %0)
+ void *fp __attribute__((cleanup(N::free)));
+ return 0;
+}
diff --git a/clang/test/Sema/attr-cleanup.c b/clang/test/Sema/attr-cleanup.c index c063529745a..f5cbc385c68 100644 --- a/clang/test/Sema/attr-cleanup.c +++ b/clang/test/Sema/attr-cleanup.c @@ -2,18 +2,18 @@ void c1(int *a); -extern int g1 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}} -int g2 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}} -static int g3 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}} +extern int g1 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute ignored}} +int g2 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute ignored}} +static int g3 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute ignored}} void t1() { int v1 __attribute((cleanup)); // expected-error {{'cleanup' attribute takes one argument}} int v2 __attribute((cleanup(1, 2))); // expected-error {{'cleanup' attribute takes one argument}} - static int v3 __attribute((cleanup(c1))); // expected-warning {{cleanup attribute ignored}} + static int v3 __attribute((cleanup(c1))); // expected-warning {{'cleanup' attribute ignored}} - int v4 __attribute((cleanup(h))); // expected-error {{'cleanup' argument 'h' not found}} + int v4 __attribute((cleanup(h))); // expected-error {{use of undeclared identifier 'h'}} int v5 __attribute((cleanup(c1))); int v6 __attribute((cleanup(v3))); // expected-error {{'cleanup' argument 'v3' is not a function}} @@ -42,3 +42,7 @@ void c5(void*) __attribute__((deprecated)); // expected-note{{'c5' declared her void t5() { int i __attribute__((cleanup(c5))); // expected-warning {{'c5' is deprecated}} } + +void t6(void) { + int i __attribute__((cleanup((void *)0))); // expected-error {{'cleanup' argument is not a function}} +} diff --git a/clang/test/SemaCXX/attr-cleanup-gcc.cpp b/clang/test/SemaCXX/attr-cleanup-gcc.cpp new file mode 100644 index 00000000000..03001b6f7b1 --- /dev/null +++ b/clang/test/SemaCXX/attr-cleanup-gcc.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -Wgcc-compat
+
+namespace N {
+ void c1(int *a) {}
+}
+
+void c2(int *a) {}
+
+template <typename Ty>
+void c3(Ty *a) {}
+
+void t3() {
+ int v1 __attribute__((cleanup(N::c1))); // expected-warning {{GCC does not allow the 'cleanup' attribute argument to be anything other than a simple identifier}}
+ int v2 __attribute__((cleanup(c2)));
+ int v3 __attribute__((cleanup(c3<int>))); // expected-warning {{GCC does not allow the 'cleanup' attribute argument to be anything other than a simple identifier}}
+}
diff --git a/clang/test/SemaCXX/attr-cleanup.cpp b/clang/test/SemaCXX/attr-cleanup.cpp new file mode 100644 index 00000000000..3ac8e817dc9 --- /dev/null +++ b/clang/test/SemaCXX/attr-cleanup.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -Wno-gcc-compat
+
+namespace N {
+ void c1(int *a) {}
+}
+
+void t1() {
+ int v1 __attribute__((cleanup(N::c1)));
+ int v2 __attribute__((cleanup(N::c2))); // expected-error {{no member named 'c2' in namespace 'N'}}
+}
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index e217d69c132..8922c5c0233 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1069,6 +1069,7 @@ void EmitClangAttrExprArgsList(RecordKeeper &Records, raw_ostream &OS) { .Case("AlignedArgument", true) .Case("BoolArgument", true) .Case("DefaultIntArgument", true) + .Case("FunctionArgument", true) .Case("IntArgument", true) .Case("ExprArgument", true) .Case("StringArgument", true) |

