Files
clang-p2996/clang/test/Sema/attr-error.c
Nick Desaulniers 846e562dcc [Clang] add support for error+warning fn attrs
Add support for the GNU C style __attribute__((error(""))) and
__attribute__((warning(""))). These attributes are meant to be put on
declarations of functions whom should not be called.

They are frequently used to provide compile time diagnostics similar to
_Static_assert, but which may rely on non-ICE conditions (ie. relying on
compiler optimizations). This is also similar to diagnose_if function
attribute, but can diagnose after optimizations have been run.

While users may instead simply call undefined functions in such cases to
get a linkage failure from the linker, these provide a much more
ergonomic and actionable diagnostic to users and do so at compile time
rather than at link time. Users instead may be able use inline asm .err
directives.

These are used throughout the Linux kernel in its implementation of
BUILD_BUG and BUILD_BUG_ON macros. These macros generally cannot be
converted to use _Static_assert because many of the parameters are not
ICEs. The Linux kernel still needs to be modified to make use of these
when building with Clang; I have a patch that does so I will send once
this feature is landed.

To do so, we create a new IR level Function attribute, "dontcall" (both
error and warning boil down to one IR Fn Attr).  Then, similar to calls
to inline asm, we attach a !srcloc Metadata node to call sites of such
attributed callees.

The backend diagnoses these during instruction selection, while we still
know that a call is a call (vs say a JMP that's a tail call) in an arch
agnostic manner.

The frontend then reconstructs the SourceLocation from that Metadata,
and determines whether to emit an error or warning based on the callee's
attribute.

Link: https://bugs.llvm.org/show_bug.cgi?id=16428
Link: https://github.com/ClangBuiltLinux/linux/issues/1173

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D106030
2021-08-25 10:34:18 -07:00

41 lines
1.5 KiB
C

// RUN: %clang_cc1 -fsyntax-only -verify %s
#if !__has_attribute(error)
#error "error attribute missing"
#endif
__attribute__((error("don't call me!"))) int good0(void);
__attribute__((error)) // expected-error {{'error' attribute takes one argument}}
int
bad0(void);
int bad1(__attribute__((error("bad1"))) int param); // expected-error {{'error' attribute only applies to functions}}
int bad2(void) {
__attribute__((error("bad2"))); // expected-error {{'error' attribute cannot be applied to a statement}}
}
__attribute__((error(3))) // expected-error {{'error' attribute requires a string}}
int
bad3(void);
__attribute__((error("foo"), error("foo"))) int good1(void);
__attribute__((error("foo"))) int good1(void);
__attribute__((error("foo"))) int good1(void) {}
__attribute__((error("foo"), warning("foo"))) // expected-error {{'warning' and 'error' attributes are not compatible}}
int
bad4(void);
// expected-note@-3 {{conflicting attribute is here}}
__attribute__((error("foo"))) int bad5(void); // expected-note {{conflicting attribute is here}}
__attribute__((warning("foo"))) int bad5(void); // expected-error {{'error' and 'warning' attributes are not compatible}}
/*
* Note: we differ from GCC here; rather than support redeclarations that add
* or remove this fn attr, we diagnose such differences.
*/
void foo(void); // expected-note {{previous declaration is here}}
__attribute__((error("oh no foo"))) void foo(void); // expected-error {{'error' attribute does not appear on the first declaration}}