[clang] [clang] Ignore GCC 11 `[[malloc(x)]]` attribute (PR #68059)

Alois Klink via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 1 13:27:52 PDT 2023


https://github.com/aloisklink updated https://github.com/llvm/llvm-project/pull/68059

>From a76561f522f628b0882572f8dabee6f7e4abd5f5 Mon Sep 17 00:00:00 2001
From: Alois Klink <alois at aloisklink.com>
Date: Mon, 2 Oct 2023 19:59:06 +0100
Subject: [PATCH 1/5] [clang] Ignore GCC 11 [[malloc(x)]] attribute

Ignore the `[[malloc(x)]]` or `[[malloc(x, 1)]]` function attribute
syntax added in [GCC 11][1] and print a warning instead of an error.

Unlike `[[malloc]]` with no arguments (which is supported by Clang),
GCC uses the one or two argument form to specify a deallocator for
GCC's static analyzer.

Code currently compiled with `[[malloc(x)]]` or
`__attribute((malloc(x)))` fails with the following error:
`'malloc' attribute takes no arguments`.

[1]: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;f=gcc/doc/extend.texi;h=dce6c58db87ebf7f4477bd3126228e73e4eeee97#patch6

Fixes: https://github.com/llvm/llvm-project/issues/51607
Partial-Bug: https://github.com/llvm/llvm-project/issues/53152
---
 clang/docs/ReleaseNotes.rst                   |  5 +++++
 clang/include/clang/Basic/Attr.td             |  2 ++
 clang/include/clang/Basic/AttrDocs.td         |  3 +++
 .../clang/Basic/DiagnosticCommonKinds.td      |  4 ++++
 clang/lib/Sema/SemaDeclAttr.cpp               | 20 ++++++++++++++++---
 clang/test/Sema/attr-args.c                   |  6 ++++--
 clang/test/SemaCXX/attr-print.cpp             |  8 ++++++++
 7 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6be824771c583be..3cbeed044ada396 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -289,6 +289,11 @@ Bug Fixes to Compiler Builtins
 Bug Fixes to Attribute Support
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+- Clang now emits a warning instead of an error when using the one or two
+  argument form of GCC 11's ``__attribute__((malloc(deallocator)))``
+  or ``__attribute__((malloc(deallocator, ptr-index)))``
+  (`#51607 <https://github.com/llvm/llvm-project/issues/51607>`).
+
 Bug Fixes to C++ Support
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 7a6ec77ae84b15a..db1f332efdb7653 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1629,6 +1629,8 @@ def IFunc : Attr, TargetSpecificAttr<TargetELF> {
 
 def Restrict : InheritableAttr {
   let Spellings = [Declspec<"restrict">, GCC<"malloc">];
+  let Args = [IdentifierArgument<"Deallocator", /*opt*/ 1>,
+              ParamIdxArgument<"DeallocatorPtrArgIndex", /*opt*/ 1>];
   let Subjects = SubjectList<[Function]>;
   let Documentation = [RestrictDocs];
 }
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 8d928dcc146b254..1e498aeea6b7832 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -4122,6 +4122,9 @@ def RestrictDocs : Documentation {
 The ``malloc`` attribute indicates that the function acts like a system memory
 allocation function, returning a pointer to allocated storage disjoint from the
 storage for any other object accessible to the caller.
+
+The form of ``malloc`` with one or two arguments (supported by GCC 11) is
+currently ignored by Clang.
   }];
 }
 
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index f2df283c74829f6..35472b92e460850 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -177,6 +177,10 @@ def warn_unknown_attribute_ignored : Warning<
   "unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
 def warn_attribute_ignored : Warning<"%0 attribute ignored">,
   InGroup<IgnoredAttributes>;
+def warn_multiarg_malloc_attribute_ignored: Warning<
+  "'malloc' attribute ignored because"
+  " Clang does not support the one/two argument form">,
+  InGroup<IgnoredAttributes>;
 def err_keyword_not_supported_on_target : Error<
   "%0 is not supported on this target">;
 def err_use_of_tag_name_without_tag : Error<
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index ed0b4d29b056397..9fe190b74db58fe 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2064,13 +2064,27 @@ static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
 
 static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   QualType ResultType = getFunctionOrMethodResultType(D);
-  if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) {
+  if (!ResultType->isAnyPointerType() && !ResultType->isBlockPointerType()) {
+    S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only)
+        << AL << getFunctionOrMethodResultSourceRange(D);
+    return;
+  }
+
+  if (getNumAttributeArgs(AL) == 0) {
     D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL));
     return;
   }
 
-  S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only)
-      << AL << getFunctionOrMethodResultSourceRange(D);
+  if (AL.getAttributeSpellingListIndex() == RestrictAttr::Declspec_restrict) {
+    // __declspec(restrict) accepts no arguments
+    S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 0;
+    return;
+  }
+
+  // FIXME: GCC uses [[malloc(my_func)]] to specify a deallocator for the
+  // returned pointer, but this isn't currently supported in LLVM
+  // see https://github.com/llvm/llvm-project/issues/51607
+  S.Diag(AL.getLoc(), diag::warn_multiarg_malloc_attribute_ignored);
 }
 
 static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
diff --git a/clang/test/Sema/attr-args.c b/clang/test/Sema/attr-args.c
index e275c90be1f9dca..26b642d0363ea71 100644
--- a/clang/test/Sema/attr-args.c
+++ b/clang/test/Sema/attr-args.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -fsyntax-only %s
+// RUN: %clang_cc1 -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -fsyntax-only -fdeclspec %s
 int a;
 
 inline __attribute__((noreturn(a))) void *f1(void);  // expected-error {{'noreturn' attribute takes no arguments}}
@@ -6,7 +6,9 @@ inline __attribute__((always_inline(a))) void *f2(void);  // expected-error {{'a
 inline __attribute__((cdecl(a))) void *f3(void);  // expected-error {{'cdecl' attribute takes no arguments}}
 inline __attribute__((const(a))) void *f4(void);  // expected-error {{'const' attribute takes no arguments}}
 inline __attribute__((fastcall(a))) void *f5(void);  // expected-error {{'fastcall' attribute takes no arguments}}
-inline __attribute__((malloc(a))) void *f5(void);  // expected-error {{'malloc' attribute takes no arguments}}
+inline __declspec(restrict(a)) void *f6_a(void);  // expected-error {{'restrict' attribute takes no arguments}}
+inline __attribute__((malloc(a, 1, a))) void *f6_b(void);  // expected-error {{'malloc' attribute takes no more than 2 arguments}}
+inline __attribute__((malloc(a, 1))) void *f6_c(void);  // expected-warning {{'malloc' attribute ignored because Clang does not support the one/two argument form}}
 inline __attribute__((nothrow(a))) void *f7(void);  // expected-error {{'nothrow' attribute takes no arguments}}
 inline __attribute__((stdcall(a))) void *f8(void);  // expected-error {{'stdcall' attribute takes no arguments}}
 inline __attribute__((used(a))) void *f9(void);  // expected-error {{'used' attribute takes no arguments}}
diff --git a/clang/test/SemaCXX/attr-print.cpp b/clang/test/SemaCXX/attr-print.cpp
index dff290be696be24..17e4d3d823cfd8e 100644
--- a/clang/test/SemaCXX/attr-print.cpp
+++ b/clang/test/SemaCXX/attr-print.cpp
@@ -28,6 +28,14 @@ int v __attribute__((visibility("hidden")));
 // CHECK: char *PR24565() __attribute__((malloc))
 char *PR24565() __attribute__((__malloc__));
 
+void my_cleanup_func(char *);
+
+// using __attribute__(malloc()) with args is currently ignored by Clang
+// CHECK: char *PR52265_a()
+__attribute__((malloc(my_cleanup_func))) char *PR52265_a();
+// CHECK: char *PR52265_b()
+__attribute__((malloc(my_cleanup_func, 1))) char *PR52265_b();
+
 // CHECK: class __attribute__((consumable("unknown"))) AttrTester1
 class __attribute__((consumable(unknown))) AttrTester1 {
   // CHECK: void callableWhen() __attribute__((callable_when("unconsumed", "consumed")));

>From 02a153d9be1007b9603bcd14bf3f80d4bf900806 Mon Sep 17 00:00:00 2001
From: Alois Klink <alois at aloisklink.com>
Date: Sun, 29 Oct 2023 01:25:07 +0100
Subject: [PATCH 2/5] fixup! [clang] Ignore GCC 11 [[malloc(x)]] attribute

Move diag::warn_multiarg_malloc_attribute_ignored to
`DiagnosticSemaKinds.td` and make it generic so we can use it for other
attributes.

Fixes https://github.com/llvm/llvm-project/pull/68059#discussion_r1355446479
---
 clang/include/clang/Basic/DiagnosticCommonKinds.td | 4 ----
 clang/include/clang/Basic/DiagnosticSemaKinds.td   | 4 ++++
 clang/lib/Sema/SemaDeclAttr.cpp                    | 2 +-
 clang/test/Sema/attr-args.c                        | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 35472b92e460850..f2df283c74829f6 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -177,10 +177,6 @@ def warn_unknown_attribute_ignored : Warning<
   "unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
 def warn_attribute_ignored : Warning<"%0 attribute ignored">,
   InGroup<IgnoredAttributes>;
-def warn_multiarg_malloc_attribute_ignored: Warning<
-  "'malloc' attribute ignored because"
-  " Clang does not support the one/two argument form">,
-  InGroup<IgnoredAttributes>;
 def err_keyword_not_supported_on_target : Error<
   "%0 is not supported on this target">;
 def err_use_of_tag_name_without_tag : Error<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ac854a86a2fce23..b7f11c96dcbf304 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3028,6 +3028,10 @@ def warn_auto_var_is_id : Warning<
   InGroup<DiagGroup<"auto-var-id">>;
 
 // Attributes
+def warn_attribute_form_ignored : Warning<
+  "%0 attribute ignored because Clang does not yet support this attribute signature">,
+  InGroup<IgnoredAttributes>;
+
 def warn_attribute_ignored_no_calls_in_stmt: Warning<
   "%0 attribute is ignored because there exists no call expression inside the "
   "statement">,
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 9fe190b74db58fe..5d2d62a77bda900 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2084,7 +2084,7 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   // FIXME: GCC uses [[malloc(my_func)]] to specify a deallocator for the
   // returned pointer, but this isn't currently supported in LLVM
   // see https://github.com/llvm/llvm-project/issues/51607
-  S.Diag(AL.getLoc(), diag::warn_multiarg_malloc_attribute_ignored);
+  S.Diag(AL.getLoc(), diag::warn_attribute_form_ignored) << AL;
 }
 
 static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
diff --git a/clang/test/Sema/attr-args.c b/clang/test/Sema/attr-args.c
index 26b642d0363ea71..036298e632e1021 100644
--- a/clang/test/Sema/attr-args.c
+++ b/clang/test/Sema/attr-args.c
@@ -8,7 +8,7 @@ inline __attribute__((const(a))) void *f4(void);  // expected-error {{'const' at
 inline __attribute__((fastcall(a))) void *f5(void);  // expected-error {{'fastcall' attribute takes no arguments}}
 inline __declspec(restrict(a)) void *f6_a(void);  // expected-error {{'restrict' attribute takes no arguments}}
 inline __attribute__((malloc(a, 1, a))) void *f6_b(void);  // expected-error {{'malloc' attribute takes no more than 2 arguments}}
-inline __attribute__((malloc(a, 1))) void *f6_c(void);  // expected-warning {{'malloc' attribute ignored because Clang does not support the one/two argument form}}
+inline __attribute__((malloc(a, 1))) void *f6_c(void);  // expected-warning {{'malloc' attribute ignored because Clang does not yet support this attribute signature}}
 inline __attribute__((nothrow(a))) void *f7(void);  // expected-error {{'nothrow' attribute takes no arguments}}
 inline __attribute__((stdcall(a))) void *f8(void);  // expected-error {{'stdcall' attribute takes no arguments}}
 inline __attribute__((used(a))) void *f9(void);  // expected-error {{'used' attribute takes no arguments}}

>From b7e125882fe895f0c4fb346a5ae1acddb70f6739 Mon Sep 17 00:00:00 2001
From: Alois Klink <alois at aloisklink.com>
Date: Wed, 1 Nov 2023 15:52:30 +0000
Subject: [PATCH 3/5] fixup! [clang] Ignore GCC 11 [[malloc(x)]] attribute

Support bugprone-argument-comment format.

Co-authored-by: Shafik Yaghmour <shafik at users.noreply.github.com>
---
 clang/include/clang/Basic/Attr.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index db1f332efdb7653..bcd0ecd801bc418 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1629,8 +1629,8 @@ def IFunc : Attr, TargetSpecificAttr<TargetELF> {
 
 def Restrict : InheritableAttr {
   let Spellings = [Declspec<"restrict">, GCC<"malloc">];
-  let Args = [IdentifierArgument<"Deallocator", /*opt*/ 1>,
-              ParamIdxArgument<"DeallocatorPtrArgIndex", /*opt*/ 1>];
+  let Args = [IdentifierArgument<"Deallocator", /*opt=*/ 1>,
+              ParamIdxArgument<"DeallocatorPtrArgIndex", /*opt=*/ 1>];
   let Subjects = SubjectList<[Function]>;
   let Documentation = [RestrictDocs];
 }

>From 5f6f893c867e73a2a8e04e94a2fa6e2104b9b85e Mon Sep 17 00:00:00 2001
From: Alois Klink <alois at aloisklink.com>
Date: Wed, 1 Nov 2023 15:55:47 +0000
Subject: [PATCH 4/5] fixup! [clang] Ignore GCC 11 [[malloc(x)]] attribute

Fix incorrect RST link syntax.

Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3cbeed044ada396..ab5b315934dca27 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -292,7 +292,7 @@ Bug Fixes to Attribute Support
 - Clang now emits a warning instead of an error when using the one or two
   argument form of GCC 11's ``__attribute__((malloc(deallocator)))``
   or ``__attribute__((malloc(deallocator, ptr-index)))``
-  (`#51607 <https://github.com/llvm/llvm-project/issues/51607>`).
+  (`#51607 <https://github.com/llvm/llvm-project/issues/51607>`_).
 
 Bug Fixes to C++ Support
 ^^^^^^^^^^^^^^^^^^^^^^^^

>From 0659620002757ab8bbd892a717fb47478d22aecd Mon Sep 17 00:00:00 2001
From: Alois Klink <alois at aloisklink.com>
Date: Wed, 1 Nov 2023 16:01:22 +0000
Subject: [PATCH 5/5] fixup! [clang] Ignore GCC 11 [[malloc(x)]] attribute

Error if `deallocator` and `ptrIdx` to
`[[malloc(deallocator, ptrIdx)]]` have invalid types.
---
 clang/include/clang/Basic/Attr.td             |  2 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |  6 ++
 clang/lib/Sema/SemaDeclAttr.cpp               | 68 +++++++++++++++++--
 clang/test/Sema/attr-args.c                   | 14 +++-
 4 files changed, 83 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index bcd0ecd801bc418..14302f6311e7744 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1629,7 +1629,7 @@ def IFunc : Attr, TargetSpecificAttr<TargetELF> {
 
 def Restrict : InheritableAttr {
   let Spellings = [Declspec<"restrict">, GCC<"malloc">];
-  let Args = [IdentifierArgument<"Deallocator", /*opt=*/ 1>,
+  let Args = [ExprArgument<"Deallocator", /*opt=*/ 1>,
               ParamIdxArgument<"DeallocatorPtrArgIndex", /*opt=*/ 1>];
   let Subjects = SubjectList<[Function]>;
   let Documentation = [RestrictDocs];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b7f11c96dcbf304..0bf64e0da50dfa2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4252,6 +4252,12 @@ def err_attribute_cleanup_func_must_take_one_arg : Error<
 def err_attribute_cleanup_func_arg_incompatible_type : Error<
   "'cleanup' function %0 parameter has "
   "%diff{type $ which is incompatible with type $|incompatible type}1,2">;
+def err_attribute_malloc_arg_not_function : Error<
+  "'malloc' argument %select{for deallocator |%1 |%1 }0is not a %select{||single }0function">;
+def err_attribute_malloc_arg_not_function_with_pointer_arg : Error<
+  "'malloc' argument %0 must take a pointer type as its first argument">;
+def err_attribute_malloc_arg_refers_to_non_pointer_type : Error<
+  "'malloc' argument '%0' refers to non-pointer type %1 of %2">; // in GCC, this is a warning, not an error
 def err_attribute_regparm_wrong_platform : Error<
   "'regparm' is not valid on this platform">;
 def err_attribute_regparm_invalid_number : Error<
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 5d2d62a77bda900..78b3760a1187901 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2070,7 +2070,7 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
     return;
   }
 
-  if (getNumAttributeArgs(AL) == 0) {
+  if (AL.getNumArgs() == 0) {
     D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL));
     return;
   }
@@ -2081,9 +2081,69 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
     return;
   }
 
-  // FIXME: GCC uses [[malloc(my_func)]] to specify a deallocator for the
-  // returned pointer, but this isn't currently supported in LLVM
-  // see https://github.com/llvm/llvm-project/issues/51607
+  // [[gnu::malloc(deallocator)]] with args specifies a deallocator function
+  Expr *DeallocE = AL.getArgAsExpr(0);
+  SourceLocation DeallocLoc = DeallocE->getExprLoc();
+  FunctionDecl *DeallocFD = nullptr;
+  DeclarationNameInfo DeallocNI;
+
+  if (auto *DRE = dyn_cast<DeclRefExpr>(DeallocE)) {
+    DeallocFD = dyn_cast<FunctionDecl>(DRE->getDecl());
+    DeallocNI = DRE->getNameInfo();
+    if (!DeallocFD) {
+      S.Diag(DeallocLoc, diag::err_attribute_malloc_arg_not_function)
+          << 1 << DeallocNI.getName();
+      return;
+    }
+  } else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(DeallocE)) {
+    DeallocFD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true);
+    DeallocNI = ULE->getNameInfo();
+    if (!DeallocFD) {
+      S.Diag(DeallocLoc, diag::err_attribute_malloc_arg_not_function)
+          << 2 << DeallocNI.getName();
+      if (ULE->getType() == S.Context.OverloadTy)
+        S.NoteAllOverloadCandidates(ULE);
+      return;
+    }
+  } else {
+    S.Diag(DeallocLoc, diag::err_attribute_malloc_arg_not_function) << 0;
+    return;
+  }
+
+  // 2nd arg of [[gnu::malloc(deallocator, 2)]] with args specifies the param
+  // of deallocator that deallocates the pointer (defaults to 1)
+  ParamIdx DeallocPtrIdx;
+  if (AL.getNumArgs() == 1) {
+    DeallocPtrIdx = ParamIdx(1, DeallocFD);
+
+    if (!DeallocPtrIdx.isValid() ||
+        !getFunctionOrMethodParamType(DeallocFD, DeallocPtrIdx.getASTIndex())
+             .getCanonicalType()
+             ->isPointerType()) {
+      S.Diag(DeallocLoc,
+             diag::err_attribute_malloc_arg_not_function_with_pointer_arg)
+          << DeallocNI.getName();
+      return;
+    }
+  } else {
+    if (!checkFunctionOrMethodParameterIndex(S, DeallocFD, AL, 2,
+                                             AL.getArgAsExpr(1), DeallocPtrIdx,
+                                             /* CanIndexImplicitThis=*/false))
+      return;
+
+    QualType DeallocPtrArgType =
+        getFunctionOrMethodParamType(DeallocFD, DeallocPtrIdx.getASTIndex());
+    if (!DeallocPtrArgType.getCanonicalType()->isPointerType()) {
+      S.Diag(DeallocLoc,
+             diag::err_attribute_malloc_arg_refers_to_non_pointer_type)
+          << DeallocPtrIdx.getSourceIndex() << DeallocPtrArgType
+          << DeallocNI.getName();
+      return;
+    }
+  }
+
+  // FIXME: we should add this attribute to Clang's AST, so that clang-analyzer
+  // can use it.
   S.Diag(AL.getLoc(), diag::warn_attribute_form_ignored) << AL;
 }
 
diff --git a/clang/test/Sema/attr-args.c b/clang/test/Sema/attr-args.c
index 036298e632e1021..db69a99bdee3b7c 100644
--- a/clang/test/Sema/attr-args.c
+++ b/clang/test/Sema/attr-args.c
@@ -1,5 +1,9 @@
 // RUN: %clang_cc1 -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -fsyntax-only -fdeclspec %s
 int a;
+void func_a(void * ptr, int a);
+void func_b(int a);
+void __attribute__((overloadable)) ambigious_func(void *); // expected-note {{candidate function}}
+void __attribute__((overloadable)) ambigious_func(void *, int); // expected-note {{candidate function}}
 
 inline __attribute__((noreturn(a))) void *f1(void);  // expected-error {{'noreturn' attribute takes no arguments}}
 inline __attribute__((always_inline(a))) void *f2(void);  // expected-error {{'always_inline' attribute takes no arguments}}
@@ -7,8 +11,14 @@ inline __attribute__((cdecl(a))) void *f3(void);  // expected-error {{'cdecl' at
 inline __attribute__((const(a))) void *f4(void);  // expected-error {{'const' attribute takes no arguments}}
 inline __attribute__((fastcall(a))) void *f5(void);  // expected-error {{'fastcall' attribute takes no arguments}}
 inline __declspec(restrict(a)) void *f6_a(void);  // expected-error {{'restrict' attribute takes no arguments}}
-inline __attribute__((malloc(a, 1, a))) void *f6_b(void);  // expected-error {{'malloc' attribute takes no more than 2 arguments}}
-inline __attribute__((malloc(a, 1))) void *f6_c(void);  // expected-warning {{'malloc' attribute ignored because Clang does not yet support this attribute signature}}
+inline __attribute__((malloc(func_a, 1, a))) void *f6_b(void);  // expected-error {{'malloc' attribute takes no more than 2 arguments}}
+inline __attribute__((malloc(func_a, 1))) void *f6_c(void);  // expected-warning {{'malloc' attribute ignored because Clang does not yet support this attribute signature}}
+inline __attribute__((malloc(1234))) void *f6_d(void);  // expected-error {{'malloc' argument for deallocator is not a function}}
+inline __attribute__((malloc(a))) void *f6_e(void);  // expected-error {{'malloc' argument 'a' is not a function}}
+inline __attribute__((malloc(ambigious_func))) void *f6_f(void);  // expected-error {{'malloc' argument 'ambigious_func' is not a single function}}
+inline __attribute__((malloc(func_b))) void *f6_g(void);  // expected-error {{'malloc' argument 'func_b' must take a pointer type as its first argument}}
+inline __attribute__((malloc(func_a, 3))) void *f6_h(void);  // expected-error {{'malloc' attribute parameter 2 is out of bounds}}
+inline __attribute__((malloc(func_a, 2))) void *f6_i(void);  // expected-error {{'malloc' argument '2' refers to non-pointer type 'int' of 'func_a'}}
 inline __attribute__((nothrow(a))) void *f7(void);  // expected-error {{'nothrow' attribute takes no arguments}}
 inline __attribute__((stdcall(a))) void *f8(void);  // expected-error {{'stdcall' attribute takes no arguments}}
 inline __attribute__((used(a))) void *f9(void);  // expected-error {{'used' attribute takes no arguments}}



More information about the cfe-commits mailing list