Don't allow #include (and its friends #import, #include_next and

#__include_macros) in the arguments of a function-style macro. Directives in the
arguments of such macros have undefined behaviour, and GCC does not correctly
support these cases. In some situations, this can lead to better diagnostics.

llvm-svn: 146765
This commit is contained in:
Richard Smith 2011-12-16 22:50:01 +00:00
parent b6c9d56eb5
commit eb3ce7c3db
4 changed files with 50 additions and 3 deletions

View File

@ -202,8 +202,10 @@ def warn_cxx98_compat_variadic_macro : Warning<
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def ext_named_variadic_macro : Extension<
"named variadic macros are a GNU extension">, InGroup<VariadicMacros>;
def err_embedded_include : Error<
"embedding a #%0 directive within macro arguments is not supported">;
def ext_embedded_directive : Extension<
"embedding a directive within macro arguments is not portable">,
"embedding a directive within macro arguments has undefined behavior">,
InGroup<DiagGroup<"embedded-directive">>;
def ext_missing_varargs_arg : Extension<
"varargs argument missing, but tolerated as an extension">;

View File

@ -577,9 +577,25 @@ void Preprocessor::HandleDirective(Token &Result) {
// A(abc
// #warning blah
// def)
// If so, the user is relying on non-portable behavior, emit a diagnostic.
if (InMacroArgs)
// If so, the user is relying on undefined behavior, emit a diagnostic. Do
// not support this for #include-like directives, since that can result in
// terrible diagnostics, and does not work in GCC.
if (InMacroArgs) {
if (IdentifierInfo *II = Result.getIdentifierInfo()) {
switch (II->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_import:
case tok::pp_include_next:
case tok::pp___include_macros:
Diag(Result, diag::err_embedded_include) << II->getName();
DiscardUntilEndOfDirective();
return;
default:
break;
}
}
Diag(Result, diag::ext_embedded_directive);
}
TryAgain:
switch (Result.getKind()) {

View File

@ -0,0 +1,20 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
// header1.h
void fail(const char *);
#define MUNCH(...) \
({ int result = 0; __VA_ARGS__; if (!result) { fail(#__VA_ARGS__); }; result })
static inline int f(int k) {
return MUNCH( // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{returning 'void'}}
if (k < 3)
result = 24;
else if (k > 4)
result = k - 4;
}
#include "macro_arg_directive.h" // expected-error {{embedding a #include directive within macro arguments is not supported}}
int g(int k) {
return f(k) + f(k-1));
}

View File

@ -0,0 +1,9 @@
// Support header for macro_arg_directive.c
int n;
struct S {
int k;
};
void g(int);