From: Jakub Jelinek Date: Tue, 4 Feb 2020 12:39:59 +0000 (+0100) Subject: libcpp: Diagnose __has_include outside of preprocessor directives [PR93545] X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f8d6e448f801bcbdaa83c98991b15ed35d1bb3cc;p=gcc.git libcpp: Diagnose __has_include outside of preprocessor directives [PR93545] The standard says http://eel.is/c++draft/cpp.cond#7.sentence-2 that __has_include can't appear at arbitrary places in the source. As we have not recognized __has_include* outside of preprocessing directives in the past, accepting it there now would be a regression. The patch does still allow it in #define if it is then used in preprocessing directives, I guess that use isn't strictly valid either, but clang seems to accept it. 2020-02-04 Jakub Jelinek * macro.c (builtin_has_include): Diagnose __has_include* use outside of preprocessing directives. * c-c++-common/cpp/has-include-1.c: New test. * c-c++-common/cpp/has-include-next-1.c: New test. * c-c++-common/gomp/has-include-1.c: New test. --- diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e46561a540c..25e9595a6f6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2020-02-04 Jakub Jelinek + * c-c++-common/cpp/has-include-1.c: New test. + * c-c++-common/cpp/has-include-next-1.c: New test. + * c-c++-common/gomp/has-include-1.c: New test. + PR preprocessor/93545 * c-c++-common/cpp/pr88974.c: Expect another diagnostics during error recovery. diff --git a/gcc/testsuite/c-c++-common/cpp/has-include-1.c b/gcc/testsuite/c-c++-common/cpp/has-include-1.c new file mode 100644 index 00000000000..1d9f011cba0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/has-include-1.c @@ -0,0 +1,104 @@ +/* { dg-do preprocess } */ + +#if __has_include ("stdlib.h") +#else +#error error 1 +#endif +#if __has_include () +#else +#error error 2 +#endif +#if !__has_include ("stdlib.h") +#error error 3 +#elif !__has_include () +#error error 4 +#endif +#if __has_include ("stdlib.h") && __has_include () +#else +#error error 5 +#endif +#if !defined(__has_include) +#error error 6 +#endif +#ifndef __has_include +#error error 7 +#endif +#ifdef __has_include +#else +#error error 8 +#endif +#define m1 __has_include("stdlib.h") +#define m2 ("stdlib.h") +#define m3 ("has-include-1-nonexistent.h") +#define m4 has-include-1-nonexistent-2.h>) +#define m5 +#if !m1 +#error error 9 +#endif +#if !__has_include m2 +#error error 10 +#endif +#if __has_include m3 +#error error 11 +#endif +#if __has_include () /* { dg-error "used outside of preprocessing directive" } */ +m1 /* { dg-error "used outside of preprocessing directive" } */ +#if 1 +m1 /* { dg-error "used outside of preprocessing directive" } */ +#endif +#if 0 +#elif 1 +m1 /* { dg-error "used outside of preprocessing directive" } */ +#endif +#if 0 +m1 +#endif +#if 0 +#elif 0 +m1 +#endif +#if __has_include "stdlib.h") /* { dg-error "missing" } */ +#endif +#if __has_include (stdlib.h) /* { dg-error "operator|missing" } */ +#endif +#if __has_include () /* { dg-error "operator|missing" } */ +#endif +#if __has_include ) /* { dg-error "operator|missing" } */ +#endif +#if __has_include ("stdlib.h) +#endif +/* { dg-error "operator|missing\[^\n\r]*after" "" { target *-*-* } .-2 } */ +/* { dg-warning "missing terminating" "" { target *-*-* } .-3 } */ +#if __has_include (stdlib.h>) /* { dg-error "operator|missing" } */ +#endif +#if __has_include ("stdlib.h" /* { dg-error "missing" } */ +#endif +#if __has_include ( /* { dg-error "operator|missing" } */ +#endif +#if __has_include /* { dg-error "operator|missing" } */ +#endif +#if __has_include"stdlib.h" /* { dg-error "missing" } */ +#endif +#if __has_include'h' /* { dg-error "operator|missing" } */ +#endif +#if __has_include('h' /* { dg-error "operator|missing" } */ +#endif +#if __has_include('h') /* { dg-error "operator" } */ +#endif +#define H(h) __has_include(h) +#if H() +#else +#error error 14 +#endif +void +foo () +{ +#pragma omp parallel if (__has_include ("")) + ; +} diff --git a/gcc/testsuite/c-c++-common/cpp/has-include-next-1.c b/gcc/testsuite/c-c++-common/cpp/has-include-next-1.c new file mode 100644 index 00000000000..79e528da667 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/has-include-next-1.c @@ -0,0 +1,104 @@ +/* { dg-do preprocess } */ + +#if __has_include_next ("stdlib.h") +#else +#error error 1 +#endif +#if __has_include_next () +#else +#error error 2 +#endif +#if !__has_include_next ("stdlib.h") +#error error 3 +#elif !__has_include_next () +#error error 4 +#endif +#if __has_include_next ("stdlib.h") && __has_include_next () +#else +#error error 5 +#endif +#if !defined(__has_include_next) +#error error 6 +#endif +#ifndef __has_include_next +#error error 7 +#endif +#ifdef __has_include_next +#else +#error error 8 +#endif +#define m1 __has_include_next("stdlib.h") +#define m2 ("stdlib.h") +#define m3 ("has-include-1-nonexistent.h") +#define m4 has-include-1-nonexistent-2.h>) +#define m5 +#if !m1 +#error error 9 +#endif +#if !__has_include_next m2 +#error error 10 +#endif +#if __has_include_next m3 +#error error 11 +#endif +#if __has_include_next () /* { dg-error "used outside of preprocessing directive" } */ +m1 /* { dg-error "used outside of preprocessing directive" } */ +#if 1 +m1 /* { dg-error "used outside of preprocessing directive" } */ +#endif +#if 0 +#elif 1 +m1 /* { dg-error "used outside of preprocessing directive" } */ +#endif +#if 0 +m1 +#endif +#if 0 +#elif 0 +m1 +#endif +#if __has_include_next "stdlib.h") /* { dg-error "missing" } */ +#endif +#if __has_include_next (stdlib.h) /* { dg-error "operator|missing" } */ +#endif +#if __has_include_next () /* { dg-error "operator|missing" } */ +#endif +#if __has_include_next ) /* { dg-error "operator|missing" } */ +#endif +#if __has_include_next ("stdlib.h) +#endif +/* { dg-error "operator|missing\[^\n\r]*after" "" { target *-*-* } .-2 } */ +/* { dg-warning "missing terminating" "" { target *-*-* } .-3 } */ +#if __has_include_next (stdlib.h>) /* { dg-error "operator|missing" } */ +#endif +#if __has_include_next ("stdlib.h" /* { dg-error "missing" } */ +#endif +#if __has_include_next ( /* { dg-error "operator|missing" } */ +#endif +#if __has_include_next /* { dg-error "operator|missing" } */ +#endif +#if __has_include_next"stdlib.h" /* { dg-error "missing" } */ +#endif +#if __has_include_next'h' /* { dg-error "operator|missing" } */ +#endif +#if __has_include_next('h' /* { dg-error "operator|missing" } */ +#endif +#if __has_include_next('h') /* { dg-error "operator" } */ +#endif +#define H(h) __has_include_next(h) +#if H() +#else +#error error 14 +#endif +void +foo () +{ +#pragma omp parallel if (__has_include_next ("")) + ; +} diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 11c0773adb6..cc5c575ca83 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,5 +1,8 @@ 2020-02-04 Jakub Jelinek + * macro.c (builtin_has_include): Diagnose __has_include* use outside + of preprocessing directives. + PR preprocessor/93545 * macro.c (cpp_get_token_no_padding): New function. (builtin_has_include): Use it instead of cpp_get_token. Don't check diff --git a/libcpp/macro.c b/libcpp/macro.c index 9f9f83134b4..ec0030742c0 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -359,6 +359,11 @@ builtin_has_include (cpp_reader *pfile, cpp_hashnode *op, bool has_next) { int result = 0; + if (!pfile->state.in_directive) + cpp_error (pfile, CPP_DL_ERROR, + "\"%s\" used outside of preprocessing directive", + NODE_NAME (op)); + pfile->state.angled_headers = true; const cpp_token *token = cpp_get_token_no_padding (pfile); bool paren = token->type == CPP_OPEN_PAREN;