Skip to content

Commit 0659620

Browse files
committed
fixup! [clang] Ignore GCC 11 [[malloc(x)]] attribute
Error if `deallocator` and `ptrIdx` to `[[malloc(deallocator, ptrIdx)]]` have invalid types.
1 parent 5f6f893 commit 0659620

File tree

4 files changed

+83
-7
lines changed

4 files changed

+83
-7
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1629,7 +1629,7 @@ def IFunc : Attr, TargetSpecificAttr<TargetELF> {
16291629

16301630
def Restrict : InheritableAttr {
16311631
let Spellings = [Declspec<"restrict">, GCC<"malloc">];
1632-
let Args = [IdentifierArgument<"Deallocator", /*opt=*/ 1>,
1632+
let Args = [ExprArgument<"Deallocator", /*opt=*/ 1>,
16331633
ParamIdxArgument<"DeallocatorPtrArgIndex", /*opt=*/ 1>];
16341634
let Subjects = SubjectList<[Function]>;
16351635
let Documentation = [RestrictDocs];

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4252,6 +4252,12 @@ def err_attribute_cleanup_func_must_take_one_arg : Error<
42524252
def err_attribute_cleanup_func_arg_incompatible_type : Error<
42534253
"'cleanup' function %0 parameter has "
42544254
"%diff{type $ which is incompatible with type $|incompatible type}1,2">;
4255+
def err_attribute_malloc_arg_not_function : Error<
4256+
"'malloc' argument %select{for deallocator |%1 |%1 }0is not a %select{||single }0function">;
4257+
def err_attribute_malloc_arg_not_function_with_pointer_arg : Error<
4258+
"'malloc' argument %0 must take a pointer type as its first argument">;
4259+
def err_attribute_malloc_arg_refers_to_non_pointer_type : Error<
4260+
"'malloc' argument '%0' refers to non-pointer type %1 of %2">; // in GCC, this is a warning, not an error
42554261
def err_attribute_regparm_wrong_platform : Error<
42564262
"'regparm' is not valid on this platform">;
42574263
def err_attribute_regparm_invalid_number : Error<

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,7 +2070,7 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
20702070
return;
20712071
}
20722072

2073-
if (getNumAttributeArgs(AL) == 0) {
2073+
if (AL.getNumArgs() == 0) {
20742074
D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL));
20752075
return;
20762076
}
@@ -2081,9 +2081,69 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
20812081
return;
20822082
}
20832083

2084-
// FIXME: GCC uses [[malloc(my_func)]] to specify a deallocator for the
2085-
// returned pointer, but this isn't currently supported in LLVM
2086-
// see https://github.com/llvm/llvm-project/issues/51607
2084+
// [[gnu::malloc(deallocator)]] with args specifies a deallocator function
2085+
Expr *DeallocE = AL.getArgAsExpr(0);
2086+
SourceLocation DeallocLoc = DeallocE->getExprLoc();
2087+
FunctionDecl *DeallocFD = nullptr;
2088+
DeclarationNameInfo DeallocNI;
2089+
2090+
if (auto *DRE = dyn_cast<DeclRefExpr>(DeallocE)) {
2091+
DeallocFD = dyn_cast<FunctionDecl>(DRE->getDecl());
2092+
DeallocNI = DRE->getNameInfo();
2093+
if (!DeallocFD) {
2094+
S.Diag(DeallocLoc, diag::err_attribute_malloc_arg_not_function)
2095+
<< 1 << DeallocNI.getName();
2096+
return;
2097+
}
2098+
} else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(DeallocE)) {
2099+
DeallocFD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true);
2100+
DeallocNI = ULE->getNameInfo();
2101+
if (!DeallocFD) {
2102+
S.Diag(DeallocLoc, diag::err_attribute_malloc_arg_not_function)
2103+
<< 2 << DeallocNI.getName();
2104+
if (ULE->getType() == S.Context.OverloadTy)
2105+
S.NoteAllOverloadCandidates(ULE);
2106+
return;
2107+
}
2108+
} else {
2109+
S.Diag(DeallocLoc, diag::err_attribute_malloc_arg_not_function) << 0;
2110+
return;
2111+
}
2112+
2113+
// 2nd arg of [[gnu::malloc(deallocator, 2)]] with args specifies the param
2114+
// of deallocator that deallocates the pointer (defaults to 1)
2115+
ParamIdx DeallocPtrIdx;
2116+
if (AL.getNumArgs() == 1) {
2117+
DeallocPtrIdx = ParamIdx(1, DeallocFD);
2118+
2119+
if (!DeallocPtrIdx.isValid() ||
2120+
!getFunctionOrMethodParamType(DeallocFD, DeallocPtrIdx.getASTIndex())
2121+
.getCanonicalType()
2122+
->isPointerType()) {
2123+
S.Diag(DeallocLoc,
2124+
diag::err_attribute_malloc_arg_not_function_with_pointer_arg)
2125+
<< DeallocNI.getName();
2126+
return;
2127+
}
2128+
} else {
2129+
if (!checkFunctionOrMethodParameterIndex(S, DeallocFD, AL, 2,
2130+
AL.getArgAsExpr(1), DeallocPtrIdx,
2131+
/* CanIndexImplicitThis=*/false))
2132+
return;
2133+
2134+
QualType DeallocPtrArgType =
2135+
getFunctionOrMethodParamType(DeallocFD, DeallocPtrIdx.getASTIndex());
2136+
if (!DeallocPtrArgType.getCanonicalType()->isPointerType()) {
2137+
S.Diag(DeallocLoc,
2138+
diag::err_attribute_malloc_arg_refers_to_non_pointer_type)
2139+
<< DeallocPtrIdx.getSourceIndex() << DeallocPtrArgType
2140+
<< DeallocNI.getName();
2141+
return;
2142+
}
2143+
}
2144+
2145+
// FIXME: we should add this attribute to Clang's AST, so that clang-analyzer
2146+
// can use it.
20872147
S.Diag(AL.getLoc(), diag::warn_attribute_form_ignored) << AL;
20882148
}
20892149

clang/test/Sema/attr-args.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
// RUN: %clang_cc1 -verify -Wunused -Wused-but-marked-unused -Wunused-parameter -fsyntax-only -fdeclspec %s
22
int a;
3+
void func_a(void * ptr, int a);
4+
void func_b(int a);
5+
void __attribute__((overloadable)) ambigious_func(void *); // expected-note {{candidate function}}
6+
void __attribute__((overloadable)) ambigious_func(void *, int); // expected-note {{candidate function}}
37

48
inline __attribute__((noreturn(a))) void *f1(void); // expected-error {{'noreturn' attribute takes no arguments}}
59
inline __attribute__((always_inline(a))) void *f2(void); // expected-error {{'always_inline' attribute takes no arguments}}
610
inline __attribute__((cdecl(a))) void *f3(void); // expected-error {{'cdecl' attribute takes no arguments}}
711
inline __attribute__((const(a))) void *f4(void); // expected-error {{'const' attribute takes no arguments}}
812
inline __attribute__((fastcall(a))) void *f5(void); // expected-error {{'fastcall' attribute takes no arguments}}
913
inline __declspec(restrict(a)) void *f6_a(void); // expected-error {{'restrict' attribute takes no arguments}}
10-
inline __attribute__((malloc(a, 1, a))) void *f6_b(void); // expected-error {{'malloc' attribute takes no more than 2 arguments}}
11-
inline __attribute__((malloc(a, 1))) void *f6_c(void); // expected-warning {{'malloc' attribute ignored because Clang does not yet support this attribute signature}}
14+
inline __attribute__((malloc(func_a, 1, a))) void *f6_b(void); // expected-error {{'malloc' attribute takes no more than 2 arguments}}
15+
inline __attribute__((malloc(func_a, 1))) void *f6_c(void); // expected-warning {{'malloc' attribute ignored because Clang does not yet support this attribute signature}}
16+
inline __attribute__((malloc(1234))) void *f6_d(void); // expected-error {{'malloc' argument for deallocator is not a function}}
17+
inline __attribute__((malloc(a))) void *f6_e(void); // expected-error {{'malloc' argument 'a' is not a function}}
18+
inline __attribute__((malloc(ambigious_func))) void *f6_f(void); // expected-error {{'malloc' argument 'ambigious_func' is not a single function}}
19+
inline __attribute__((malloc(func_b))) void *f6_g(void); // expected-error {{'malloc' argument 'func_b' must take a pointer type as its first argument}}
20+
inline __attribute__((malloc(func_a, 3))) void *f6_h(void); // expected-error {{'malloc' attribute parameter 2 is out of bounds}}
21+
inline __attribute__((malloc(func_a, 2))) void *f6_i(void); // expected-error {{'malloc' argument '2' refers to non-pointer type 'int' of 'func_a'}}
1222
inline __attribute__((nothrow(a))) void *f7(void); // expected-error {{'nothrow' attribute takes no arguments}}
1323
inline __attribute__((stdcall(a))) void *f8(void); // expected-error {{'stdcall' attribute takes no arguments}}
1424
inline __attribute__((used(a))) void *f9(void); // expected-error {{'used' attribute takes no arguments}}

0 commit comments

Comments
 (0)