diff mbox

[v2] cpp/c: Add -Wexpansion-to-defined

Message ID 1470823595-1471-1-git-send-email-bonzini@gnu.org
State New
Headers show

Commit Message

Paolo Bonzini Aug. 10, 2016, 10:06 a.m. UTC
clang recently added a new warning -Wexpansion-to-defined, which
warns when `defined' is used outside a #if expression (including the
case of a macro that is then used in a #if expression).

While I disagree with their inclusion of the warning to -Wall, I think
it is a good addition overall.  First, it is a logical extension of the
existing warning for breaking defined across a macro and its caller.
Second, it is good to make these warnings for `defined' available with
a command-line option other than -pedantic.  In fact this warning is
not mandated by the standard and thus is a strange case of a non-pedwarn
enabled by -pedantic.  As a side effect of using the command-line parsing
machinery to attach the new warning to -pedantic, it would become an
error for -pedantic-errors, which would be weird for a diagnostic that
is not mandated by the standard.

This patch adds -Wexpansion-to-defined, and enables it automatically
for -Wextra instead of -pedantic.

Bootstrapped and regression tested x86_64-pc-linux-gnu, ok?

Paolo

libcpp:
2016-08-09  Paolo Bonzini  <bonzini@gnu.org>

        * include/cpplib.h (struct cpp_options): Add new member
        warn_expansion_to_defined.
        (CPP_W_EXPANSION_TO_DEFINED): New enum member.
        * expr.c (parse_defined): Warn for all uses of "defined"
        in macros, and tie warning to CPP_W_EXPANSION_TO_DEFINED.
        * system.h (HAVE_DESIGNATED_INITIALIZERS): Do not use
        "defined" in macros.

gcc:
2016-08-09  Paolo Bonzini  <bonzini@gnu.org>

        * system.h (HAVE_DESIGNATED_INITIALIZERS,
        HAVE_DESIGNATED_UNION_INITIALIZERS): Do not use
        "defined" in macros.

gcc/c-family:
2016-08-09  Paolo Bonzini  <bonzini@gnu.org>

        * c.opt (Wexpansion-to-defined): New.

gcc/doc:
2016-08-09  Paolo Bonzini  <bonzini@gnu.org>

        * cpp.texi (Defined): Mention -Wexpansion-to-defined.
        * cppopts.texi (Invocation): Document -Wexpansion-to-defined.
        * invoke.texi (Warning Options): Document -Wexpansion-to-defined.

gcc/testsuite:
2016-08-09  Paolo Bonzini  <bonzini@gnu.org>

        * gcc.dg/cpp/defined.c: Mark newly introduced warnings.  Adjust
        options to include -Wexpansion-to-defined.
        * gcc.dg/cpp/defined-no-Wexpansion-to-defined.c,
        gcc.dg/cpp/defined-Wextra-Wno-expansion-to-defined.c,
        gcc.dg/cpp/defined-Wextra.c: New testcases.

Comments

Manuel López-Ibáñez Aug. 10, 2016, 11:31 a.m. UTC | #1
On 10 August 2016 at 11:06, Paolo Bonzini <bonzini@gnu.org> wrote:
> While I disagree with their inclusion of the warning to -Wall, I think
> it is a good addition overall.  First, it is a logical extension of the
> existing warning for breaking defined across a macro and its caller.
> Second, it is good to make these warnings for `defined' available with
> a command-line option other than -pedantic.  In fact this warning is
> not mandated by the standard and thus is a strange case of a non-pedwarn
> enabled by -pedantic.  As a side effect of using the command-line parsing
> machinery to attach the new warning to -pedantic, it would become an
> error for -pedantic-errors, which would be weird for a diagnostic that
> is not mandated by the standard.

Note that the definition of -pedantic-errors says: "in some cases
where there is undefined behavior at compile-time". Thus, this would
be allowed according to our current definitions. However, the
definition of -Wpedantic does not mention that, thus it could be a
pedwarn not controlled by -Wpedantic.

My only fear is that people not using -Wpedantic nor -pedantic-errors
expect that GNU extensions work. This is a GNU extension that defines
something that is undefined according to ISO. Enabling the warning
with -Wextra is just annoying those people who may not care about
other compilers.

Thus, my opinion is that the current definition of -Wpedantic is too
restrictive and it should contain the "in some cases where there is
undefined behavior at compile-time". And thus, this should be a
pedwarn enabled by -Wpedantic, not by -Wextra and an error with
-pedantic-errors. But you should wait for other opinions, specially
Joseph, before redoing it, even if you agree with me.

Cheers,

Manuel.
Joseph Myers Aug. 10, 2016, 11:53 a.m. UTC | #2
On Wed, 10 Aug 2016, Manuel López-Ibáñez wrote:

> Thus, my opinion is that the current definition of -Wpedantic is too
> restrictive and it should contain the "in some cases where there is
> undefined behavior at compile-time". And thus, this should be a

Yes, it should.
Paolo Bonzini Aug. 10, 2016, 12:06 p.m. UTC | #3
On 10/08/2016 13:31, Manuel López-Ibáñez wrote:
> My only fear is that people not using -Wpedantic nor -pedantic-errors
> expect that GNU extensions work. This is a GNU extension that defines
> something that is undefined according to ISO. Enabling the warning
> with -Wextra is just annoying those people who may not care about
> other compilers.

I think this warning falls in the same category as
-Wshift-negative-value.  (In fact I dislike -Wshift-negative-value a
lot, and would put that one under -Wpedantic only).

It is interesting that GCC has been relying for a long time on such
behavior in the HAVE_DESIGNATED_INITIALIZERS macro, despite GCC not
having any interest in compiling with -Wpedantic.  I think this
reinforces the choice of adding the warning to -Wextra.

People using -Wextra are used to having to remove some warnings
manually, and this one probably doesn't have many hits (1 in QEMU, which
is what motivated me to add it to GCC; and 2 in GCC not counting the
duplicate code between gcc/system.h and libcpp/system.h).

Paolo
Manuel López-Ibáñez Aug. 10, 2016, 2:42 p.m. UTC | #4
On 10 August 2016 at 13:06, Paolo Bonzini <bonzini@gnu.org> wrote:
>
>
> On 10/08/2016 13:31, Manuel López-Ibáñez wrote:
>> My only fear is that people not using -Wpedantic nor -pedantic-errors
>> expect that GNU extensions work. This is a GNU extension that defines
>> something that is undefined according to ISO. Enabling the warning
>> with -Wextra is just annoying those people who may not care about
>> other compilers.
>
> I think this warning falls in the same category as
> -Wshift-negative-value.  (In fact I dislike -Wshift-negative-value a
> lot, and would put that one under -Wpedantic only).

It is not the same category. One is compile-time UB and the other is
runtime UB. See:
https://gcc.gnu.org/ml/gcc-patches/2015-04/msg01551.html
and https://gcc.gnu.org/ml/gcc-patches/2015-04/msg01529.html

Cheers,

Manuel.
Paolo Bonzini Aug. 10, 2016, 2:44 p.m. UTC | #5
On 10/08/2016 16:42, Manuel López-Ibáñez wrote:
> > > My only fear is that people not using -Wpedantic nor -pedantic-errors
> > > expect that GNU extensions work. This is a GNU extension that defines
> > > something that is undefined according to ISO. Enabling the warning
> > > with -Wextra is just annoying those people who may not care about
> > > other compilers.
> >
> > I think this warning falls in the same category as
> > -Wshift-negative-value.  (In fact I dislike -Wshift-negative-value a
> > lot, and would put that one under -Wpedantic only).
>
> It is not the same category. One is compile-time UB and the other is
> runtime UB. See:
> https://gcc.gnu.org/ml/gcc-patches/2015-04/msg01551.html
> and https://gcc.gnu.org/ml/gcc-patches/2015-04/msg01529.html

Right---what I meant is it's the same kind of "annoying for people who
expect that GNU extensions work" warning.

Paolo
Manuel López-Ibáñez Aug. 10, 2016, 3:24 p.m. UTC | #6
On 10 August 2016 at 15:44, Paolo Bonzini <bonzini@gnu.org> wrote:
>
>
> On 10/08/2016 16:42, Manuel López-Ibáñez wrote:
>> > > My only fear is that people not using -Wpedantic nor -pedantic-errors
>> > > expect that GNU extensions work. This is a GNU extension that defines
>> > > something that is undefined according to ISO. Enabling the warning
>> > > with -Wextra is just annoying those people who may not care about
>> > > other compilers.
>> >
>> > I think this warning falls in the same category as
>> > -Wshift-negative-value.  (In fact I dislike -Wshift-negative-value a
>> > lot, and would put that one under -Wpedantic only).
>>
>> It is not the same category. One is compile-time UB and the other is
>> runtime UB. See:
>> https://gcc.gnu.org/ml/gcc-patches/2015-04/msg01551.html
>> and https://gcc.gnu.org/ml/gcc-patches/2015-04/msg01529.html
>
> Right---what I meant is it's the same kind of "annoying for people who
> expect that GNU extensions work" warning.

Oh, I agree. I'm just mentioning what the current definition/behavior
is (and documenting it here:
https://gcc.gnu.org/wiki/DiagnosticsGuidelines FWIW), not what I think
should be.

Perhaps we need something like -Wextra-pedantic, for things that are
undefined by ISO C but defined by GNU. Thus, they would not trigger
pedwarns and no error with -pedantic-errors.

Or we need to split -Wpedantic into -Wpedantic-pedwarns and
-Wpedantic-nopedwarns (with better names). This way -pedantic-errors
would be equivalent to -Werror=pedantic-pedwarns +
-Werror=pedwarns-not-controlled-by-pedantic.

i find -pedantic-errors too out of place with the rest of -W* options.

Manuel.
Paolo Bonzini Aug. 10, 2016, 3:29 p.m. UTC | #7
On 10/08/2016 17:24, Manuel López-Ibáñez wrote:
> Perhaps we need something like -Wextra-pedantic, for things that are
> undefined by ISO C but defined by GNU. Thus, they would not trigger
> pedwarns and no error with -pedantic-errors.

I think this is overengineering it a bit.  If they are annoying, put
them in -Wpedantic; if they aren't too bad, put them in Wextra.

There is also the case (which includes -Wshift-negative-value) of things
that are undefined by ISO C and trapped by ubsan, but defined by GNU C.

Actually are pedwarns even necessary nowadays?  In theory they fall in
two categories:

- stuff that is EnabledBy(Wpedantic) automatically gets bumped from
warning to error by -pedantic-errors or (I think) -Werror=pedantic;

- stuff that is not enabled by anything should use OPT_Wpedantic, and
then warning(OPT_Wpedantic) should have the same effect as
pedwarn(OPT_Wpedantic).

Are there other cases that I'm missing?

Paolo
Joseph Myers Aug. 10, 2016, 3:33 p.m. UTC | #8
On Wed, 10 Aug 2016, Paolo Bonzini wrote:

> - stuff that is not enabled by anything should use OPT_Wpedantic, and

No, lots of pedwarns are for usages that are (a) dubious enough we want to 
diagnose them by default, and (b) required to be diagnosed by ISO C so 
must become errors with -pedantic-errors.  (You could argue about whether 
we should have -fpermissive for C like for C++ and make some of those into 
errors by default.)
Paolo Bonzini Aug. 10, 2016, 3:51 p.m. UTC | #9
On 10/08/2016 17:33, Joseph Myers wrote:
> On Wed, 10 Aug 2016, Paolo Bonzini wrote:
> 
>> - stuff that is not enabled by anything should use OPT_Wpedantic, and
> 
> No, lots of pedwarns are for usages that are (a) dubious enough we want to 
> diagnose them by default, and (b) required to be diagnosed by ISO C so 
> must become errors with -pedantic-errors.  (You could argue about whether 
> we should have -fpermissive for C like for C++ and make some of those into 
> errors by default.)

There are indeed many pedwarn(loc, 0, ...) occurrences in C++ (most, but
not all, are "foo only available with -std=bar" which in the C front-end
would use OPT_Wpedantic, OPT_W*compat be enabled by specific flags such
as -Wvariadic-macros).  In C I only see three:

- overflowing floating-point constants:

          if (!MODE_HAS_INFINITIES (TYPE_MODE (type)))
            pedwarn (input_location, 0,
                     "floating constant exceeds range of %qT", type);
          else
            warning (OPT_Woverflow,
                     "floating constant exceeds range of %qT", type);

- __FUNCTION__ outside function scope

  if (!ix && !current_function_decl)
    pedwarn (loc, 0, "%qD is not defined outside of function scope", decl);

- macro redefinition

For the first two it would not feel wrong at all to use permerror.  The
last one indeed is a very good example of a pedwarn.

Paolo
Joseph Myers Aug. 10, 2016, 3:58 p.m. UTC | #10
On Wed, 10 Aug 2016, Paolo Bonzini wrote:

> There are indeed many pedwarn(loc, 0, ...) occurrences in C++ (most, but
> not all, are "foo only available with -std=bar" which in the C front-end
> would use OPT_Wpedantic, OPT_W*compat be enabled by specific flags such
> as -Wvariadic-macros).  In C I only see three:

I don't know why you think there are only three; there are loads.  The 
first few in c-decl.c are:

            pedwarn (csi->location, 0,
                     "%qD is static but used in inline function %qD "
                     "which is not static", csi->static_decl, csi->function);

            pedwarn (csi->location, 0,
                     "%q+D is static but declared in inline function %qD "
                     "which is not static", csi->static_decl, csi->function);

                pedwarn (input_location, 0,
                         "inline function %q+D declared but never defined", p);

          pedwarned = pedwarn (input_location, 0,
                               "conflicting types for %q+D", newdecl);

          pedwarned = pedwarn (input_location, 0,
                               "conflicting types for %q+D", newdecl);

                  pedwarn (input_location, 0,
                           "unnamed struct/union that defines no instances");
Paolo Bonzini Aug. 10, 2016, 4:01 p.m. UTC | #11
On 10/08/2016 17:58, Joseph Myers wrote:
> On Wed, 10 Aug 2016, Paolo Bonzini wrote:
> 
>> There are indeed many pedwarn(loc, 0, ...) occurrences in C++ (most, but
>> not all, are "foo only available with -std=bar" which in the C front-end
>> would use OPT_Wpedantic, OPT_W*compat be enabled by specific flags such
>> as -Wvariadic-macros).  In C I only see three:
> 
> I don't know why you think there are only three; there are loads.  The 
> first few in c-decl.c are:
> 
>             pedwarn (csi->location, 0,
>                      "%qD is static but used in inline function %qD "
>                      "which is not static", csi->static_decl, csi->function);
> 
>             pedwarn (csi->location, 0,
>                      "%q+D is static but declared in inline function %qD "
>                      "which is not static", csi->static_decl, csi->function);
> 
>                 pedwarn (input_location, 0,
>                          "inline function %q+D declared but never defined", p);
> 
>           pedwarned = pedwarn (input_location, 0,
>                                "conflicting types for %q+D", newdecl);
> 
>           pedwarned = pedwarn (input_location, 0,
>                                "conflicting types for %q+D", newdecl);
> 
>                   pedwarn (input_location, 0,
>                            "unnamed struct/union that defines no instances");
> 

Hmm I was searching toplevel and c-family/.  I forgot that c/ now
exists, my knowledge is getting very dated...

Paolo
Sandra Loosemore Aug. 11, 2016, 3 a.m. UTC | #12
On 08/10/2016 04:06 AM, Paolo Bonzini wrote:

> ===================================================================
> --- gcc/doc/invoke.texi	(revision 239276)
> +++ gcc/doc/invoke.texi	(working copy)
> @@ -4914,6 +4914,12 @@
>   construct, known from C++, was introduced with ISO C99 and is by default
>   allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Declarations}.
>
> +@item -Wexpansion-to-defined
> +@opindex Wexpansion-to-defined
> +Warn whenever @samp{defined} is encountered in the expansion of a macro.
> +(including the case where the macro is expanded by an @samp{#if} directive).

You've got too many periods in that sentence, and I'd get rid of the 
parentheses, too:

Warn whenever @samp{defined} is encountered in the expansion of a macro,
including the case where the macro is expanded by an @samp{#if} directive.

-Sandra the nit-picky
diff mbox

Patch

Index: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt	(revision 239276)
+++ gcc/c-family/c.opt	(working copy)
@@ -506,6 +506,10 @@ 
 C ObjC C++ ObjC++ Var(warn_double_promotion) Warning
 Warn about implicit conversions from \"float\" to \"double\".
 
+Wexpansion-to-defined
+C ObjC C++ ObjC++ CPP(warn_expansion_to_defined) CppReason(CPP_W_EXPANSION_TO_DEFINED) Var(cpp_warn_expansion_to_defined) Init(0) Warning EnabledBy(Wextra)
+Warn if \"defined\" is used outside #if.
+
 Wimplicit-function-declaration
 C ObjC Var(warn_implicit_function_declaration) Init(-1) Warning LangEnabledBy(C ObjC,Wimplicit)
 Warn about implicit function declarations.
Index: gcc/doc/cpp.texi
===================================================================
--- gcc/doc/cpp.texi	(revision 239276)
+++ gcc/doc/cpp.texi	(working copy)
@@ -3342,7 +3342,8 @@ 
 the C standard says the behavior is undefined.  GNU cpp treats it as a
 genuine @code{defined} operator and evaluates it normally.  It will warn
 wherever your code uses this feature if you use the command-line option
-@option{-pedantic}, since other compilers may handle it differently.
+@option{-Wextra}, since other compilers may handle it differently.  The
+warning can also be enabled individually with @option{-Wexpansion-to-defined}.
 
 @node Else
 @subsection Else
Index: gcc/doc/cppopts.texi
===================================================================
--- gcc/doc/cppopts.texi	(revision 239276)
+++ gcc/doc/cppopts.texi	(working copy)
@@ -120,6 +120,12 @@ 
 @samp{#if} directive, outside of @samp{defined}.  Such identifiers are
 replaced with zero.
 
+@item -Wexpansion-to-defined
+@opindex Wexpansion-to-defined
+Warn whenever @samp{defined} is encountered in the expansion of a macro
+(including the case where the macro is expanded by an @samp{#if} directive).
+Such usage is not portable.
+
 @item -Wunused-macros
 @opindex Wunused-macros
 Warn about macros defined in the main file that are unused.  A macro
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 239276)
+++ gcc/doc/invoke.texi	(working copy)
@@ -4914,6 +4914,12 @@ 
 construct, known from C++, was introduced with ISO C99 and is by default
 allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Declarations}.
 
+@item -Wexpansion-to-defined
+@opindex Wexpansion-to-defined
+Warn whenever @samp{defined} is encountered in the expansion of a macro.
+(including the case where the macro is expanded by an @samp{#if} directive).
+This warning is also enabled by @option{-Wextra}.
+
 @item -Wundef
 @opindex Wundef
 @opindex Wno-undef
Index: gcc/system.h
===================================================================
--- gcc/system.h	(revision 239276)
+++ gcc/system.h	(working copy)
@@ -577,16 +577,22 @@ 
 
 /* 1 if we have C99 designated initializers.  */
 #if !defined(HAVE_DESIGNATED_INITIALIZERS)
+#ifdef __cplusplus
+#define HAVE_DESIGNATED_INITIALIZERS 0
+#else
 #define HAVE_DESIGNATED_INITIALIZERS \
-  (((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L)) \
-   && !defined(__cplusplus))
+  (((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L))
 #endif
+#endif
 
 #if !defined(HAVE_DESIGNATED_UNION_INITIALIZERS)
+#ifdef __cplusplus
+#define HAVE_DESIGNATED_UNION_INITIALIZERS (GCC_VERSION >= 4007)
+#else
 #define HAVE_DESIGNATED_UNION_INITIALIZERS \
-  (((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L)) \
-   && (!defined(__cplusplus) || (GCC_VERSION >= 4007)))
+  (((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L))
 #endif
+#endif
 
 #if HAVE_SYS_STAT_H
 # include <sys/stat.h>
Index: gcc/testsuite/gcc.dg/cpp/defined-Wextra-Wno-expansion-to-defined.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/defined-Wextra-Wno-expansion-to-defined.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cpp/defined-Wextra-Wno-expansion-to-defined.c	(working copy)
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 2000 Free Software Foundation, Inc.  */
+
+/* { dg-do preprocess } */
+/* { dg-options "-Wextra -Wno-expansion-to-defined" } */
+
+/* Use of defined in different contexts.  */
+
+/*  Source: Neil Booth, 29 Oct 2000, Zack Weinberg 11 Dec 2000.  */
+
+#define Z
+
+#define bad0 defined Z
+#if !bad0                       /* { dg-bogus "may not be portable" } */
+#error Z is defined
+#endif
+
+#define bad1 defined
+#if !bad1 Z			/* { dg-bogus "may not be portable" } */
+#error Z is defined
+#endif 
+
+#if !bad1 (Z)			/* { dg-bogus "may not be portable" } */
+#error Z is defined
+#endif 
+
+#define bad2 defined (Z
+#if !bad2)			/* { dg-bogus "may not be portable" } */
+#error Z is defined
+#endif 
+
Index: gcc/testsuite/gcc.dg/cpp/defined-Wextra.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/defined-Wextra.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cpp/defined-Wextra.c	(working copy)
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 2000 Free Software Foundation, Inc.  */
+
+/* { dg-do preprocess } */
+/* { dg-options "-Wextra" } */
+
+/* Use of defined in different contexts.  */
+
+/*  Source: Neil Booth, 29 Oct 2000, Zack Weinberg 11 Dec 2000.  */
+
+#define Z
+
+#define bad0 defined Z
+#if !bad0                       /* { dg-warning "may not be portable" } */
+#error Z is defined
+#endif
+
+#define bad1 defined
+#if !bad1 Z			/* { dg-warning "may not be portable" } */
+#error Z is defined
+#endif 
+
+#if !bad1 (Z)			/* { dg-warning "may not be portable" } */
+#error Z is defined
+#endif 
+
+#define bad2 defined (Z
+#if !bad2)			/* { dg-warning "may not be portable" } */
+#error Z is defined
+#endif 
+
Index: gcc/testsuite/gcc.dg/cpp/defined-no-Wexpansion-to-defined.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/defined-no-Wexpansion-to-defined.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cpp/defined-no-Wexpansion-to-defined.c	(working copy)
@@ -0,0 +1,30 @@ 
+/* Copyright (C) 2000 Free Software Foundation, Inc.  */
+
+/* { dg-do preprocess } */
+/* { dg-options "-ansi -pedantic-errors" } */
+
+/* Use of defined in different contexts.  */
+
+/*  Source: Neil Booth, 29 Oct 2000, Zack Weinberg 11 Dec 2000.  */
+
+#define Z
+
+#define bad0 defined Z
+#if !bad0                       /* { dg-bogus "may not be portable" } */
+#error Z is defined
+#endif
+
+#define bad1 defined
+#if !bad1 Z			/* { dg-bogus "may not be portable" } */
+#error Z is defined
+#endif 
+
+#if !bad1 (Z)			/* { dg-bogus "may not be portable" } */
+#error Z is defined
+#endif 
+
+#define bad2 defined (Z
+#if !bad2)			/* { dg-bogus "may not be portable" } */
+#error Z is defined
+#endif 
+
Index: gcc/testsuite/gcc.dg/cpp/defined.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/defined.c	(revision 239276)
+++ gcc/testsuite/gcc.dg/cpp/defined.c	(working copy)
@@ -1,6 +1,7 @@ 
 /* Copyright (C) 2000 Free Software Foundation, Inc.  */
 
 /* { dg-do preprocess } */
+/* { dg-options "-ansi -pedantic-errors -Wexpansion-to-defined" } */
 
 /* Tests behavior of the defined operator.  */
 
@@ -21,7 +22,7 @@ 
 
 /* The behavior of "defined" when it comes from a macro expansion is
    now documented.  */
-#if is_Z_defined
+#if is_Z_defined                /* { dg-warning "may not be portable" } */
 #error Macro expanding into defined operator test 1
 #endif
 
@@ -31,7 +32,7 @@ 
 #error Z is defined
 #endif
 
-#if !is_Z_defined
+#if !is_Z_defined               /* { dg-warning "may not be portable" } */
 #error Macro expanding into defined operator test 2
 #endif
 
@@ -53,7 +54,7 @@ 
 
 /* The behavior of "defined" when it comes from a macro expansion is
    now documented.  */
-#if is_Z_defined
+#if is_Z_defined                /* { dg-warning "may not be portable" } */
 #error Macro expanding into defined operator test 1
 #endif
 
@@ -63,7 +64,7 @@ 
 #error Z is defined
 #endif
 
-#if !is_Z_defined
+#if !is_Z_defined               /* { dg-warning "may not be portable" } */
 #error Macro expanding into defined operator test 2
 #endif
 
Index: libcpp/expr.c
===================================================================
--- libcpp/expr.c	(revision 239276)
+++ libcpp/expr.c	(working copy)
@@ -947,9 +947,11 @@ 
 
   if (node)
     {
-      if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
-	cpp_error (pfile, CPP_DL_WARNING,
-		   "this use of \"defined\" may not be portable");
+      if ((pfile->context != initial_context
+	   || initial_context != &pfile->base_context)
+	  && CPP_OPTION (pfile, warn_expansion_to_defined))
+        cpp_warning (pfile, CPP_W_EXPANSION_TO_DEFINED,
+		     "this use of \"defined\" may not be portable");
 
       _cpp_mark_macro_used (node);
       if (!(node->flags & NODE_USED))
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 239276)
+++ libcpp/include/cpplib.h	(working copy)
@@ -410,6 +410,10 @@ 
   /* Nonzero means warn if undefined identifiers are evaluated in an #if.  */
   unsigned char warn_undef;
 
+  /* Nonzero means warn if "defined" is encountered in a place other than
+     an #if.  */
+  unsigned char warn_expansion_to_defined;
+
   /* Nonzero means warn of unused macros from the main file.  */
   unsigned char warn_unused_macros;
 
@@ -1025,7 +1029,8 @@ 
   CPP_W_DATE_TIME,
   CPP_W_PEDANTIC,
   CPP_W_C90_C99_COMPAT,
-  CPP_W_CXX11_COMPAT
+  CPP_W_CXX11_COMPAT,
+  CPP_W_EXPANSION_TO_DEFINED
 };
 
 /* Output a diagnostic of some kind.  */
Index: libcpp/system.h
===================================================================
--- libcpp/system.h	(revision 239276)
+++ libcpp/system.h	(working copy)
@@ -375,10 +375,13 @@ 
    ??? C99 designated initializers are not supported by most C++
    compilers, including G++.  -- gdr, 2005-05-18  */
 #if !defined(HAVE_DESIGNATED_INITIALIZERS)
+#ifdef __cplusplus
+#define HAVE_DESIGNATED_INITIALIZERS 0
+#else
 #define HAVE_DESIGNATED_INITIALIZERS \
-  (!defined(__cplusplus) \
-   && ((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L)))
+   ((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L))
 #endif
+#endif
 
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER)	((size_t) &((TYPE *) 0)->MEMBER)