I think I got the tabs right...? You would not believe how unbelievably
hard it is, just to mail a diff!

-----

07-24-2019    ThePhD    <phdoftheho...@gmail.com>

gcc/

* escaped_string.h: New. Refactored out of tree.c to make more
broadly available (e.g. to parser.c, cvt.c).
* tree.c: remove escaped_string class

gcc/c-family

* c-lex.c - update attribute value

gcc/cp/

* tree.c: Implement p1301 - nodiscard("should have a reason"))
Added C++2a nodiscard string message handling.
Increase nodiscard argument handling max_length from 0
to 1. (error C++2a gated)
* parser.c: add requirement that nodiscard only be seen
once in attribute-list (C++2a gated)
* cvt.c: add nodiscard message to output, if applicable

-----

diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index 851fd704e5d..f5870d095f2 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -345,24 +345,26 @@ c_common_has_attribute (cpp_reader *pfile)
    attr_name = NULL_TREE;
   }
  }
-  else
-  {
-  /* Some standard attributes need special handling. */
-  if (is_attribute_p ("noreturn", attr_name))
-   result = 200809;
-  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;
-  if (result)
-   attr_name = NULL_TREE;
-  }
+   else
+     {
+       /* Some standard attributes need special handling. */
+       if (is_attribute_p ("noreturn", attr_name))
+         result = 200809;
+       else if (is_attribute_p ("deprecated", attr_name))
+         result = 201309;
+       else if (is_attribute_p ("maybe_unused", 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; /* placeholder until C++20 Post-Cologne Working
Draft. */
+
+       if (result)
+         attr_name = NULL_TREE;
+     }
 }
if (attr_name)
 {
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 23d2aabc483..4a5128c76a1 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -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,49 +1027,99 @@ maybe_warn_nodiscard (tree expr, impl_conv_void
implicit)
tree rettype = TREE_TYPE (type);
tree fn = cp_get_fndecl_from_callee (callee);
- if (implicit != ICV_CAST && fn
- && lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn)))
- {
- auto_diagnostic_group d;
- if (warning_at (loc, OPT_Wunused_result,
-    "ignoring return value of %qD, "
-    "declared with attribute nodiscard", fn))
- inform (DECL_SOURCE_LOCATION (fn), "declared here");
- }
- else if (implicit != ICV_CAST
-  && lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype)))
- {
- auto_diagnostic_group d;
- if (warning_at (loc, OPT_Wunused_result,
-    "ignoring returned value of type %qT, "
-    "declared with attribute nodiscard", rettype))
- {
-  if (fn)
-  inform (DECL_SOURCE_LOCATION (fn),
-    "in call to %qD, declared here", fn);
-  inform (DECL_SOURCE_LOCATION (TYPE_NAME (rettype)),
-    "%qT declared here", rettype);
- }
- }
- else if (TREE_CODE (expr) == TARGET_EXPR
-  && lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (type)))
- {
- /* The TARGET_EXPR confuses do_warn_unused_result into thinking that the
-  result is used, so handle that case here. */
- if (fn)
- {
-  auto_diagnostic_group d;
-  if (warning_at (loc, OPT_Wunused_result,
-      "ignoring return value of %qD, "
-      "declared with attribute %<warn_unused_result%>",
-      fn))
-  inform (DECL_SOURCE_LOCATION (fn), "declared here");
- }
- else
- warning_at (loc, OPT_Wunused_result,
-    "ignoring return value of function "
-    "declared with attribute %<warn_unused_result%>");
- }
+ if (implicit != ICV_CAST && fn
+   && lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn)))
+   {
+     tree attr = DECL_ATTRIBUTES (fn);
+     escaped_string msg;
+     if (attr)
+       msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+     bool has_msg = static_cast<bool>(msg);
+     const char* format = (has_msg ?
+       "ignoring return value of %qD, "
+       "declared with attribute %<nodiscard%>: %<%s%>" :
+       "ignoring return value of %qD, "
+       "declared with attribute %<nodiscard%>%s");
+     const char* raw_msg = (has_msg ? (const char*)msg : "");
+     auto_diagnostic_group d;
+     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)))
+   {
+     tree attr = TYPE_ATTRIBUTES (rettype);
+     escaped_string msg;
+     if (attr)
+       msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+     bool has_msg = static_cast<bool>(msg);
+     const char* format = (has_msg ?
+       "ignoring returned value of type %qT, "
+       "declared with attribute %<nodiscard%>: %<%s%>" :
+       "ignoring return value of type %qT, "
+       "declared with attribute %<nodiscard%>%s");
+     const char* raw_msg = (has_msg ? (const char*)msg : "");
+     auto_diagnostic_group d;
+     if (warning_at (loc, OPT_Wunused_result,
+      format, rettype, raw_msg))
+       {
+         if (fn)
+           {
+             inform (DECL_SOURCE_LOCATION (fn),
+              "in call to %qD, declared here", fn);
+           }
+         inform (DECL_SOURCE_LOCATION (TYPE_NAME (rettype)),
+          "%qT declared here", rettype);
+     }
+   }
+ else if (TREE_CODE (expr) == TARGET_EXPR)
+   {
+     if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (type)))
+       {
+         /* The TARGET_EXPR confuses do_warn_unused_result into thinking
that the
+         result is used, so handle that case here. */
+         if (fn)
+           {
+             auto_diagnostic_group d;
+             if (warning_at (loc, OPT_Wunused_result,
+              "ignoring return value of %qD, "
+              "declared with attribute %<warn_unused_result%>",
+              fn))
+               {
+                 inform (DECL_SOURCE_LOCATION (fn),
+                         "declared here");
+               }
+           }
+         else
+           warning_at (loc, OPT_Wunused_result,
+             "ignoring return value of function "
+             "declared with attribute %<warn_unused_result%>");
+       }
+     else if (implicit != ICV_CAST && fn
+       && lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn)))
+       {
+         tree attr = DECL_ATTRIBUTES (fn);
+         escaped_string msg;
+         if (attr)
+           msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE
(attr))));
+         bool has_msg = static_cast<bool>(msg);
+         const char* format = (has_msg ?
+           "ignoring return value of %qD, "
+           "declared with attribute %<nodiscard%>: %<%s%>" :
+           "ignoring return value of %qD, "
+           "declared with attribute %<nodiscard%>%s");
+         const char* raw_msg = (has_msg ? (const char*)msg : "");
+         auto_diagnostic_group d;
+         if (warning_at (loc, OPT_Wunused_result,
+          format, fn, raw_msg))
+           {
+             inform (DECL_SOURCE_LOCATION (fn), "declared here");
+           }
+       }
+   }
}
/* When an expression is used in a void context, its value is discarded and
@@ -1174,17 +1225,17 @@ convert_to_void (tree expr, impl_conv_void
implicit, tsubst_flags_t complain)
case CALL_EXPR: /* We have a special meaning for volatile void fn(). */
/* cdtors may return this or void, depending on
-  targetm.cxx.cdtor_returns_this, but this shouldn't affect our
-  decisions here: neither nodiscard warnings (nodiscard cdtors
-  are nonsensical), nor should any constexpr or template
-  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))
-  return expr;
-
- maybe_warn_nodiscard (expr, implicit);
- break;
+     targetm.cxx.cdtor_returns_this, but this shouldn't affect our
+     decisions here: neither nodiscard warnings (nodiscard cdtors
+     are nonsensical), nor should any constexpr or template
+     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_DESTRUCTOR_P (fn))
+         return expr;
+
+     maybe_warn_nodiscard (expr, implicit);
+     break;
case INDIRECT_REF:
{
@@ -1396,28 +1447,29 @@ convert_to_void (tree expr, impl_conv_void
implicit, tsubst_flags_t complain)
}
case TARGET_EXPR:
- /* Don't bother with the temporary object returned from a function if
-  we don't use it, don't need to destroy it, and won't abort in
-  assign_temp. We'll still
-  allocate space for it in expand_call or declare_return_variable,
-  but we don't need to track it through all the tree phases. */
- if (TARGET_EXPR_IMPLICIT_P (expr)
-  && !TREE_ADDRESSABLE (TREE_TYPE (expr)))
- {
-  tree init = TARGET_EXPR_INITIAL (expr);
-  if (TREE_CODE (init) == AGGR_INIT_EXPR
-  && !AGGR_INIT_VIA_CTOR_P (init))
-  {
-  tree fn = AGGR_INIT_EXPR_FN (init);
-  expr = build_call_array_loc (input_location,
-          TREE_TYPE (TREE_TYPE
-            (TREE_TYPE (fn))),
-          fn,
-          aggr_init_expr_nargs (init),
-          AGGR_INIT_EXPR_ARGP (init));
-  }
- }
- maybe_warn_nodiscard (expr, implicit);
+     /* Don't bother with the temporary object returned from a function if
+     we don't use it, don't need to destroy it, and won't abort in
+     assign_temp. We'll still
+     allocate space for it in expand_call or declare_return_variable,
+     but we don't need to track it through all the tree phases. */
+     if (TARGET_EXPR_IMPLICIT_P (expr)
+      && !TREE_ADDRESSABLE (TREE_TYPE (expr)))
+       {
+         tree init = TARGET_EXPR_INITIAL (expr);
+         if (TREE_CODE (init) == AGGR_INIT_EXPR
+          && !AGGR_INIT_VIA_CTOR_P (init))
+           {
+             tree fn = AGGR_INIT_EXPR_FN (init);
+             expr = build_call_array_loc (input_location,
+             TREE_TYPE (TREE_TYPE
+             (TREE_TYPE (fn))),
+             fn,
+             aggr_init_expr_nargs (init),
+             AGGR_INIT_EXPR_ARGP (init));
+           }
+       }
+
+     maybe_warn_nodiscard (expr, implicit);
break;
default:;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ebeffdb775f..c04afa47d71 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -26399,13 +26399,26 @@ cp_parser_check_std_attribute (tree attributes,
tree attribute)
{
tree name = get_attribute_name (attribute);
if (is_attribute_p ("noreturn", name)
-  && lookup_attribute ("noreturn", attributes))
- error ("attribute %<noreturn%> can appear at most once "
-  "in an attribute-list");
+  && lookup_attribute ("noreturn", attributes))
+ {
+  error ("attribute %<noreturn%> can appear at most once "
+  "in an attribute-list");
+ }
else if (is_attribute_p ("deprecated", name)
  && lookup_attribute ("deprecated", attributes))
- error ("attribute %<deprecated%> can appear at most once "
-  "in an attribute-list");
+ {
+  error ("attribute %<deprecated%> can appear at most once "
+  "in an attribute-list");
+ }
+ else if (cxx_dialect >= cxx2a)
+ {
+ if (is_attribute_p ("nodiscard", name)
+  && lookup_attribute ("nodiscard", attributes))
+ {
+  error ("%qE attribute can appear at most once "
+  "in an attribute-list", name);
+ }
+ }
}
}
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 37e24a1669c..f5474be8b03 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -4356,12 +4356,31 @@ 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)
+ *no_add_attrs = true;
+ else if (cxx_dialect >= cxx2a)
+ {
+ if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+ {
+ error ("%qE attribute argument must be a string constant", name);
+ *no_add_attrs = true;
+ }
+ }
+ else
+ {
+ if (!*no_add_attrs)
+ {
+ error ("%qE attribute with an argument only available with "
+ "%<-std=c++2a%> or %<-std=gnu++2a%>", name);
+ }
+ }
+
if (TREE_CODE (*node) == FUNCTION_DECL)
{
- if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*node))))
+ if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*node))) &&
DECL_CONSTRUCTOR_P(*node) == 0)
 warning_at (DECL_SOURCE_LOCATION (*node),
    OPT_Wattributes, "%qE attribute applied to %qD with void "
    "return type", name, *node);
@@ -4447,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
index 00000000000..ab0fbafc5fd
--- /dev/null
+++ b/gcc/escaped_string.h
@@ -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 (const char *) 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 */
diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard-bad-clause.C
b/gcc/testsuite/g++.dg/cpp2a/nodiscard-bad-clause.C
new file mode 100644
index 00000000000..e2a95ef6625
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nodiscard-bad-clause.C
@@ -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 ();   /* { dg-warning "(?n)nodiscard" } */
+ (void) check1 ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard-once-clause.C
b/gcc/testsuite/g++.dg/cpp2a/nodiscard-once-clause.C
new file mode 100644
index 00000000000..5d7cfafc2c8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nodiscard-once-clause.C
@@ -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 ();   /* { dg-warning "nodiscard" } */
+ (void) check1 ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C
b/gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C
new file mode 100644
index 00000000000..d88d5c9d8b1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nodiscard-once.C
@@ -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 ();   /* { dg-warning "nodiscard" } */
+ (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
index 00000000000..3617365b2b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nodiscard-reason.C
@@ -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" } */
+}
diff --git a/gcc/tree.c b/gcc/tree.c
index 8cf75f22220..362e07d1c33 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see
#include "backend.h"
#include "target.h"
#include "tree.h"
+#include "escaped_string.h"
#include "gimple.h"
#include "tree-pass.h"
#include "ssa.h"
@@ -13132,22 +13133,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

Reply via email to