Implement C++20 P1301 [[nodiscard("should have a reason")]].
authorJeanHeyd Meneide <phdofthehouse@gmail.com>
Sat, 19 Oct 2019 04:51:59 +0000 (04:51 +0000)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 19 Oct 2019 04:51:59 +0000 (00:51 -0400)
2019-10-17  JeanHeyd Meneide  <phdofthehouse@gmail.com>

gcc/
        * escaped_string.h (escaped_string): New header.
        * tree.c (escaped_string): Remove escaped_string class.

gcc/c-family
        * c-lex.c (c_common_has_attribute): Update nodiscard value.

gcc/cp/
        * tree.c (handle_nodiscard_attribute) Added C++2a nodiscard
string message.
        (std_attribute_table) Increase nodiscard argument handling
max_length from 0 to 1.
        * parser.c (cp_parser_check_std_attribute): Add requirement
that nodiscard only be seen once in attribute-list.
        (cp_parser_std_attribute): Check that empty parenthesis lists are
        not specified for attributes that have max_length > 0 (e.g.
[[attr()]]).
        * cvt.c (maybe_warn_nodiscard): Add nodiscard message to
output, if applicable.
(convert_to_void): Allow constructors to be nodiscard-able (P1771).

gcc/testsuite/g++.dg/cpp0x
        * gen-attrs-67.C: Test new error message for empty-parenthesis-list.

gcc/testsuite/g++.dg/cpp2a
        * nodiscard-construct.C: New test.
        * nodiscard-once.C: New test.
        * nodiscard-reason-nonstring.C: New test.
        * nodiscard-reason-only-one.C: New test.
        * nodiscard-reason.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
From-SVN: r277200

17 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-lex.c
gcc/cp/ChangeLog
gcc/cp/cvt.c
gcc/cp/parser.c
gcc/cp/tree.c
gcc/escaped_string.h [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C
gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
gcc/testsuite/g++.dg/cpp2a/nodiscard-constructor.c [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/nodiscard-reason-nonstring.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/nodiscard-reason-only-one.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/nodiscard-reason.C [new file with mode: 0644]
gcc/tree.c

index ccf870c2531f8ea6933747f24531cdd7b73b9e5f..3e038904186f7ecd3a82d1080535b8b57084f491 100644 (file)
@@ -1,3 +1,8 @@
+2019-10-17  JeanHeyd Meneide  <phdofthehouse@gmail.com>
+
+       * escaped_string.h (escaped_string): New header.
+       * tree.c (escaped_string): Remove escaped_string class.
+
 2019-10-18  Martin Sebor  <msebor@redhat.com>
 
        PR tree-optimization/92157
index cb3b9cfa98ef38637a9eb889122002a322ed10e4..aeae1497b92c3c7d6b0c7f180ba92438e3684e3d 100644 (file)
@@ -1,3 +1,7 @@
+2019-10-17  JeanHeyd Meneide  <phdofthehouse@gmail.com>
+
+       * c-lex.c (c_common_has_attribute): Update nodiscard value.
+
 2019-10-14  Richard Sandiford  <richard.sandiford@arm.com>
 
        * c-common.h (user_facing_original_type_p): Declare.
index e3c602fbb8d4b61364b056ddc0afdc2fe787ab82..fb05b5f8af05f9720c760fb1134547daab8071b5 100644 (file)
@@ -353,13 +353,14 @@ c_common_has_attribute (cpp_reader *pfile)
              else if (is_attribute_p ("deprecated", attr_name))
                result = 201309;
              else if (is_attribute_p ("maybe_unused", attr_name)
-                      || is_attribute_p ("nodiscard", attr_name)
                       || is_attribute_p ("fallthrough", attr_name))
                result = 201603;
              else if (is_attribute_p ("no_unique_address", attr_name)
                       || is_attribute_p ("likely", attr_name)
                       || is_attribute_p ("unlikely", attr_name))
                result = 201803;
+             else if (is_attribute_p ("nodiscard", attr_name))
+               result = 201907;
              if (result)
                attr_name = NULL_TREE;
            }
index ba533d5fb95b55fa9ba0690a27933268edd1a07e..30accc5941759cb99062009836e1f5d2376abaef 100644 (file)
@@ -1,3 +1,19 @@
+2019-10-17  JeanHeyd Meneide  <phdofthehouse@gmail.com>
+
+       Implement p1301 [[nodiscard("should have a reason")]] + p1771 DR
+       * tree.c (handle_nodiscard_attribute): Handle C++2a nodiscard
+       string message.
+       (std_attribute_table) Increase nodiscard argument handling
+       max_length from 0 to 1.
+       * parser.c (cp_parser_check_std_attribute): Add requirement
+       that nodiscard only be seen once in attribute-list.
+       (cp_parser_std_attribute): Check that empty parenthesis lists are
+       not specified for attributes that have max_length > 0 (e.g.
+       [[attr()]]).
+       * cvt.c (maybe_warn_nodiscard): Add nodiscard message to
+       output, if applicable.
+       (convert_to_void): Allow constructors to be nodiscard-able (P1771).
+
 2019-10-18  Nathan Sidwell  <nathan@acm.org>
 
        * cp-tree.h (struct lang_type): Remove was_anonymous.
index 364af72e68d46d540858a643c504b884b1b999ce..d41aeb8f1fc9dfd260fc6c14bcef6aef0a9575a7 100644 (file)
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "convert.h"
 #include "stringpool.h"
 #include "attribs.h"
+#include "escaped_string.h"
 
 static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
 static tree build_type_conversion (tree, tree);
@@ -1026,22 +1027,39 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
 
   tree rettype = TREE_TYPE (type);
   tree fn = cp_get_fndecl_from_callee (callee);
+  tree attr;
   if (implicit != ICV_CAST && fn
-      && lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn)))
+      && (attr = lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn))))
     {
+      escaped_string msg;
+      tree args = TREE_VALUE (attr);
+      if (args)
+       msg.escape (TREE_STRING_POINTER (TREE_VALUE (args)));
+      const char* format = (msg ?
+       G_("ignoring return value of %qD, "
+          "declared with attribute %<nodiscard%>: %<%s%>") :
+       G_("ignoring return value of %qD, "
+          "declared with attribute %<nodiscard%>%s"));
+      const char* raw_msg = msg ? msg : "";
       auto_diagnostic_group d;
-      if (warning_at (loc, OPT_Wunused_result,
-                     "ignoring return value of %qD, "
-                     "declared with attribute nodiscard", fn))
+      if (warning_at (loc, OPT_Wunused_result, format, fn, raw_msg))
        inform (DECL_SOURCE_LOCATION (fn), "declared here");
     }
   else if (implicit != ICV_CAST
-          && lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype)))
+          && (attr = lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype))))
     {
+      escaped_string msg;
+      tree args = TREE_VALUE (attr);
+      if (args)
+       msg.escape (TREE_STRING_POINTER (TREE_VALUE (args)));
+      const char* format = msg ?
+       G_("ignoring returned value of type %qT, "
+          "declared with attribute %<nodiscard%>: %<%s%>") :
+       G_("ignoring returned value of type %qT, "
+          "declared with attribute %<nodiscard%>%s");
+      const char* raw_msg = msg ? msg : "";
       auto_diagnostic_group d;
-      if (warning_at (loc, OPT_Wunused_result,
-                     "ignoring returned value of type %qT, "
-                     "declared with attribute nodiscard", rettype))
+      if (warning_at (loc, OPT_Wunused_result, format, rettype, raw_msg))
        {
          if (fn)
            inform (DECL_SOURCE_LOCATION (fn),
@@ -1180,7 +1198,7 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
         instantiations be affected by an ABI property that is, or at
         least ought to be transparent to the language.  */
       if (tree fn = cp_get_callee_fndecl_nofold (expr))
-       if (DECL_CONSTRUCTOR_P (fn) || DECL_DESTRUCTOR_P (fn))
+       if (DECL_DESTRUCTOR_P (fn))
          return expr;
 
       maybe_warn_nodiscard (expr, implicit);
index b29ed0c982de15d8933473fff449be81788bece7..450b1447cc1fadfb366434f22eb83fa5c398f214 100644 (file)
@@ -26551,6 +26551,11 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
       arguments = error_mark_node;
     else
       {
+       if (vec->is_empty())
+         /* e.g. [[attr()]].  */
+         error_at (token->location, "parentheses must be omitted if "
+                   "%qE attribute argument list is empty",
+                   attr_id);
        arguments = build_tree_list_vec (vec);
        release_tree_vector (vec);
       }
@@ -26565,9 +26570,9 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 }
 
 /* Check that the attribute ATTRIBUTE appears at most once in the
-   attribute-list ATTRIBUTES.  This is enforced for noreturn (7.6.3)
-   and deprecated (7.6.5).  Note that carries_dependency (7.6.4)
-   isn't implemented yet in GCC.  */
+   attribute-list ATTRIBUTES.  This is enforced for noreturn (7.6.3),
+   nodiscard, and deprecated (7.6.5).  Note that
+   carries_dependency (7.6.4) isn't implemented yet in GCC.  */
 
 static void
 cp_parser_check_std_attribute (tree attributes, tree attribute)
@@ -26583,6 +26588,10 @@ cp_parser_check_std_attribute (tree attributes, tree attribute)
               && lookup_attribute ("deprecated", attributes))
        error ("attribute %<deprecated%> can appear at most once "
               "in an attribute-list");
+      else if (is_attribute_p ("nodiscard", name)
+              && lookup_attribute ("nodiscard", attributes))
+       error ("attribute %<nodiscard%> can appear at most once "
+              "in an attribute-list");
     }
 }
 
index 7f71891000d8281079152739f4a07fc0f9cf6ae4..a004bb1aa7f1731005e814e205e0510cad172b6f 100644 (file)
@@ -4369,9 +4369,14 @@ zero_init_p (const_tree t)
    warn_unused_result attribute.  */
 
 static tree
-handle_nodiscard_attribute (tree *node, tree name, tree /*args*/,
+handle_nodiscard_attribute (tree *node, tree name, tree args,
                            int /*flags*/, bool *no_add_attrs)
 {
+  if (args && TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+    {
+      error ("%qE attribute argument must be a string constant", name);
+      *no_add_attrs = true;
+    }
   if (TREE_CODE (*node) == FUNCTION_DECL)
     {
       if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))
@@ -4461,7 +4466,7 @@ const struct attribute_spec std_attribute_table[] =
        affects_type_identity, handler, exclude } */
   { "maybe_unused", 0, 0, false, false, false, false,
     handle_unused_attribute, NULL },
-  { "nodiscard", 0, 0, false, false, false, false,
+  { "nodiscard", 0, 1, false, false, false, false,
     handle_nodiscard_attribute, NULL },
   { "no_unique_address", 0, 0, true, false, false, false,
     handle_no_unique_addr_attribute, NULL },
diff --git a/gcc/escaped_string.h b/gcc/escaped_string.h
new file mode 100644 (file)
index 0000000..b83e128
--- /dev/null
@@ -0,0 +1,43 @@
+/* Shared escaped string class.
+   Copyright (C) 1999-2019 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_ESCAPED_STRING_H
+#define GCC_ESCAPED_STRING_H
+
+#include <cstdlib>
+
+/* A class to handle converting a string that might contain
+   control characters, (eg newline, form-feed, etc), into one
+   in which contains escape sequences instead.  */
+
+class escaped_string
+{
+ public:
+  escaped_string () { m_owned = false; m_str = NULL; };
+  ~escaped_string () { if (m_owned) free (m_str); }
+  operator const char *() const { return m_str; }
+  void escape (const char *);
+ private:
+  escaped_string(const escaped_string&) {}
+  escaped_string& operator=(const escaped_string&) { return *this; }
+  char *m_str;
+  bool  m_owned;
+};
+
+#endif /* ! GCC_ESCAPED_STRING_H */
index 3dd3a1fdc7ead0196edbb04f016483c7292742c5..c195dfe7b804ae07cb1f62acc9f056984f47b5c6 100644 (file)
@@ -5,7 +5,7 @@
 [[noreturn(1)]] void f1 (); // { dg-error ".noreturn. attribute does not take any arguments" }
 [[noreturn(1, 2)]] void f2 (); // { dg-error ".noreturn. attribute does not take any arguments" }
 [[maybe_unused()]] int f3(); // { dg-error ".maybe_unused. attribute does not take any arguments" }
-[[nodiscard()]] int f4(); // { dg-error ".nodiscard. attribute does not take any arguments" }
+[[nodiscard()]] int f4(); // { dg-error "parentheses must be omitted if .nodiscard. attribute argument list is empty" }
 [[gnu::noinline()]] int f5(); // { dg-error ".noinline. attribute does not take any arguments" }
 [[gnu::constructor]] int f6();
 [[gnu::constructor(101)]] int f7(); // { dg-error "constructor priorities are not supported" "" { target { ! init_priority } } }
index a5d94462c870702dd3ede53e86b551c084de251d..a18d6aea985159ad8c5f55e2096a8c462abb8594 100644 (file)
 
 #  if ! __has_cpp_attribute(nodiscard)
 #    error "__has_cpp_attribute(nodiscard)"
-#  elif __has_cpp_attribute(nodiscard) != 201603
+#  elif (__has_cpp_attribute(nodiscard) != 201603 && __has_cpp_attribute(nodiscard) != 201907)
 #    error "__has_cpp_attribute(nodiscard) != 201603"
 #  endif
 
index 2b9cfd0effc5963be42ede69c0cd7e635f35e567..95251c2f5c692b0df8d40fca4e2b6ffadd772273 100644 (file)
 
 #  if ! __has_cpp_attribute(nodiscard)
 #    error "__has_cpp_attribute(nodiscard)"
-#  elif __has_cpp_attribute(nodiscard) != 201603
-#    error "__has_cpp_attribute(nodiscard) != 201603"
+#  elif __has_cpp_attribute(nodiscard) != 201907
+#    error "__has_cpp_attribute(nodiscard) != 201907"
 #  endif
 
 #  if ! __has_cpp_attribute(fallthrough)
diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard-constructor.c b/gcc/testsuite/g++.dg/cpp2a/nodiscard-constructor.c
new file mode 100644 (file)
index 0000000..a5c2c65
--- /dev/null
@@ -0,0 +1,13 @@
+/* nodiscard attribute tests  */
+/* { dg-do compile { target c++2a } } */
+/* { dg-options "-O -ftrack-macro-expansion=0" } */
+
+struct A { [[nodiscard("bad constructor")]] A() {} };
+struct B { [[nodiscard]] B() {} };
+
+void
+test (void)
+{
+  A{}; /* { dg-warning "(?n)nodiscard.*bad constructor" } */
+  B{}; /* { dg-warning "(?n)nodiscard" } */
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C b/gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C
new file mode 100644 (file)
index 0000000..4518a11
--- /dev/null
@@ -0,0 +1,12 @@
+/* nodiscard attribute tests  */
+/* { dg-do compile { target c++2a } } */
+/* { dg-options "-O -ftrack-macro-expansion=0" } */
+
+[[nodiscard, nodiscard]] int check1 (void); /* { dg-error "(?n)nodiscard.*can appear at most once" } */
+
+void
+test (void)
+{
+  check1 ();
+  (void) check1 ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard-reason-nonstring.C b/gcc/testsuite/g++.dg/cpp2a/nodiscard-reason-nonstring.C
new file mode 100644 (file)
index 0000000..af715e2
--- /dev/null
@@ -0,0 +1,12 @@
+/* nodiscard attribute tests  */
+/* { dg-do compile { target c++2a } } */
+/* { dg-options "-O -ftrack-macro-expansion=0" } */
+
+[[nodiscard(123)]] int check1 (void); /* { dg-error "(?n)nodiscard.*must be a string constant" } */
+
+void
+test (void)
+{
+  check1 ();
+  (void) check1 ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard-reason-only-one.C b/gcc/testsuite/g++.dg/cpp2a/nodiscard-reason-only-one.C
new file mode 100644 (file)
index 0000000..602a4e2
--- /dev/null
@@ -0,0 +1,12 @@
+/* nodiscard attribute tests  */
+/* { dg-do compile { target c++2a } } */
+/* { dg-options "-O -ftrack-macro-expansion=0" } */
+
+[[nodiscard("not", "allowed")]] int check1 (void); /* { dg-error "(?n)wrong number of arguments..*nodiscard" } */
+
+void
+test (void)
+{
+  check1 ();
+  (void) check1 ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard-reason.C b/gcc/testsuite/g++.dg/cpp2a/nodiscard-reason.C
new file mode 100644 (file)
index 0000000..0113c90
--- /dev/null
@@ -0,0 +1,203 @@
+/* nodiscard attribute tests, adapted from gcc.dg/attr-warn-unused-result.c.  */
+/* { dg-do compile { target c++2a } } */
+/* { dg-options "-O -ftrack-macro-expansion=0" } */
+
+#define NODIS [[nodiscard("exact_message")]]
+#define NODISAI [[nodiscard("exact_inline_message"), gnu::always_inline]] inline
+enum [[nodiscard("exact_E_message")]] E { e };
+typedef E (*fnt) (void);
+
+typedef struct { long i; } A;
+typedef struct { long i; long j; } B;
+typedef struct { char big[1024]; fnt fn; } C;
+struct [[nodiscard("exact_D_message")]] D { int i; D(); ~D(); };
+
+NODIS E check1 (void);
+NODIS void check2 (void); /* { dg-warning "(?n)10:.nodiscard.*exact_message" } */
+NODIS int foo;         /* { dg-warning "(?n)9:.nodiscard.*exact_message" } */
+int bar (void);
+NODISAI E check3 (void) { return (E)bar (); }
+NODIS A check4 (void);
+NODIS B check5 (void);
+NODIS C check6 (void);
+A bar7 (void);
+B bar8 (void);
+C bar9 (void);
+NODISAI A check7 (void) { return bar7 (); }
+NODISAI B check8 (void) { return bar8 (); }
+NODISAI C check9 (void) { return bar9 (); }
+/* This is useful for checking whether return value of statement
+   expressions (returning int in this case) is used.  */
+NODISAI int check_int_result (int res) { return res; }
+#define GU(v) ({ int e = 0; (v) = bar (); if ((v) < 23) e = 14; e; })
+fnt fnptr;
+NODIS E check10 (void);
+int baz (void);
+NODISAI E check11 (void) { return (E)baz (); }
+int k;
+
+D check12();
+
+void
+test (void)
+{
+  int i = 0, j;
+  const fnt pcheck1 = check1;
+  const fnt pcheck3 = check3;
+  A a;
+  B b;
+  C c;
+  D d;
+  if (check1 ())
+    return;
+  i += check1 ();
+  i += ({ check1 (); });
+  check1 ();           /* { dg-warning "(?n)nodiscard.*exact_message" } */
+  (void) check1 ();
+  check1 (), bar ();   /* { dg-warning "(?n)nodiscard.*exact_message" } */
+  check2 ();
+  (void) check2 ();
+  check2 (), bar ();
+  if (check3 ())
+    return;
+  i += check3 ();
+  i += ({ check3 (); });
+  check3 ();           /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  (void) check3 ();
+  check3 (), bar ();   /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  a = check4 ();
+  if (a.i)
+    return;
+  if (check4 ().i)
+    return;
+  if (({ check4 (); }).i)
+    return;
+  check4 ();           /* { dg-warning "(?n)nodiscard.*exact_message" } */
+  (void) check4 ();
+  check4 (), bar ();   /* { dg-warning "(?n)nodiscard.*exact_message" } */
+  b = check5 ();
+  if (b.i + b.j)
+    return;
+  if (check5 ().j)
+    return;
+  if (({ check5 (); }).j)
+    return;
+  check5 ();           /* { dg-warning "(?n)nodiscard.*exact_message" } */
+  (void) check5 ();
+  check5 (), bar ();   /* { dg-warning "(?n)nodiscard.*exact_message" } */
+  c = check6 ();
+  if (c.big[12] + c.big[29])
+    return;
+  if (check6 ().big[27])
+    return;
+  if (({ check6 (); }).big[0])
+    return;
+  check6 ();           /* { dg-warning "(?n)nodiscard.*exact_message" } */
+  (void) check6 ();
+  check6 (), bar ();   /* { dg-warning "(?n)nodiscard.*exact_message" } */
+  a = check7 ();
+  if (a.i)
+    return;
+  if (check7 ().i)
+    return;
+  if (({ check7 (); }).i)
+    return;
+  check7 ();           /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  (void) check7 ();
+  check7 (), bar ();   /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  b = check8 ();
+  if (b.i + b.j)
+    return;
+  if (check8 ().j)
+    return;
+  if (({ check8 (); }).j)
+    return;
+  check8 ();           /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  (void) check8 ();
+  check8 (), bar ();   /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  c = check9 ();
+  if (c.big[12] + c.big[29])
+    return;
+  if (check9 ().big[27])
+    return;
+  if (({ check9 (); }).big[0])
+    return;
+  check9 ();           /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  (void) check9 ();
+  check9 (), bar ();   /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  if (check_int_result (GU (j)))
+    return;
+  i += check_int_result (GU (j));
+  i += ({ check_int_result (GU (j)); });
+  check_int_result (GU (j)); /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  (void) check_int_result (GU (j));
+  check_int_result (GU (j)), bar (); /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  if (fnptr ())
+    return;
+  i += fnptr ();
+  i += ({ fnptr (); });
+  fnptr ();            /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  (void) fnptr ();
+  fnptr (), bar ();    /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  fnptr = check1;
+  if (fnptr ())
+    return;
+  i += fnptr ();
+  i += ({ fnptr (); });
+  fnptr ();            /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  (void) fnptr ();
+  fnptr (), bar ();    /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  fnptr = check3;
+  if (fnptr ())
+    return;
+  i += fnptr ();
+  i += ({ fnptr (); });
+  fnptr ();            /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  (void) fnptr ();
+  fnptr (), bar ();    /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  if (bar9 ().fn ())
+    return;
+  i += bar9 ().fn ();
+  i += ({ bar9 ().fn (); });
+  bar9 ().fn ();       /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  (void) bar9 ().fn ();
+  bar9 ().fn (), bar (); /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  if ((k ? check1 : check10) ())
+    return;
+  i += (k ? check1 : check10) ();
+  i += ({ (k ? check1 : check10) (); });
+  (k ? check1 : check10) (); /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  (void) (k ? check1 : check10) ();
+  (k ? check1 : check10) (), bar (); /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  if ((k ? check3 : check11) ())
+    return;
+  i += (k ? check3 : check11) ();
+  i += ({ (k ? check3 : check11) (); });
+  (k ? check3 : check11) (); /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  (void) (k ? check3 : check11) ();
+  (k ? check3 : check11) (), bar (); /* { dg-warning "(?n)nodiscard.*exact_inline_message" } */
+  if (pcheck1 ())
+    return;
+  i += pcheck1 ();
+  i += ({ pcheck1 (); });
+  pcheck1 ();          /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  (void) pcheck1 ();
+  pcheck1 (), bar ();  /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  if (pcheck3 ())
+    return;
+  i += pcheck3 ();
+  i += ({ pcheck3 (); });
+  pcheck3 ();          /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  (void) pcheck3 ();
+  pcheck3 (), bar ();  /* { dg-warning "(?n)nodiscard.*exact_E_message" } */
+  d = check12 ();
+  if (d.i)
+    return;
+  if (check12 ().i)
+    return;
+  if (({ check12 (); }).i)
+    return;
+  check12 ();          /* { dg-warning "(?n)nodiscard.*exact_D_message" } */
+  (void) check12 ();
+  check12 (), bar ();  /* { dg-warning "(?n)nodiscard.*exact_D_message" } */
+}
index e845fc7a00ee038b03d7a14d2b2d111f1197ac62..2bee1d255ff006d32455f504ef62cc6b9aca193c 100644 (file)
@@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "regs.h"
 #include "tree-vector-builder.h"
 #include "gimple-fold.h"
+#include "escaped_string.h"
 
 /* Tree code classes.  */
 
@@ -13225,22 +13226,6 @@ typedef_variant_p (const_tree type)
   return is_typedef_decl (TYPE_NAME (type));
 }
 
-/* A class to handle converting a string that might contain
-   control characters, (eg newline, form-feed, etc), into one
-   in which contains escape sequences instead.  */
-
-class escaped_string
-{
- public:
-  escaped_string () { m_owned = false; m_str = NULL; };
-  ~escaped_string () { if (m_owned) free (m_str); }
-  operator const char *() const { return (const char *) m_str; }
-  void escape (const char *);
- private:
-  char *m_str;
-  bool  m_owned;
-};
-
 /* PR 84195: Replace control characters in "unescaped" with their
    escaped equivalents.  Allow newlines if -fmessage-length has
    been set to a non-zero value.  This is done here, rather than