From: JeanHeyd Meneide Date: Sat, 19 Oct 2019 04:51:59 +0000 (+0000) Subject: Implement C++20 P1301 [[nodiscard("should have a reason")]]. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8ad0c477e888d34c8fc6dbcc008ef66505071d65;p=gcc.git Implement C++20 P1301 [[nodiscard("should have a reason")]]. 2019-10-17 JeanHeyd Meneide 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 From-SVN: r277200 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ccf870c2531..3e038904186 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-10-17 JeanHeyd Meneide + + * escaped_string.h (escaped_string): New header. + * tree.c (escaped_string): Remove escaped_string class. + 2019-10-18 Martin Sebor PR tree-optimization/92157 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index cb3b9cfa98e..aeae1497b92 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,7 @@ +2019-10-17 JeanHeyd Meneide + + * c-lex.c (c_common_has_attribute): Update nodiscard value. + 2019-10-14 Richard Sandiford * c-common.h (user_facing_original_type_p): Declare. diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c index e3c602fbb8d..fb05b5f8af0 100644 --- a/gcc/c-family/c-lex.c +++ b/gcc/c-family/c-lex.c @@ -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; } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ba533d5fb95..30accc59417 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2019-10-17 JeanHeyd Meneide + + 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 * cp-tree.h (struct lang_type): Remove was_anonymous. diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 364af72e68d..d41aeb8f1fc 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,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 %: %<%s%>") : + G_("ignoring return value of %qD, " + "declared with attribute %%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 %: %<%s%>") : + G_("ignoring returned value of type %qT, " + "declared with attribute %%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); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b29ed0c982d..450b1447cc1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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 % can appear at most once " "in an attribute-list"); + else if (is_attribute_p ("nodiscard", name) + && lookup_attribute ("nodiscard", attributes)) + error ("attribute % can appear at most once " + "in an attribute-list"); } } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7f71891000d..a004bb1aa7f 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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 index 00000000000..b83e1281f27 --- /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 +. */ + +#ifndef GCC_ESCAPED_STRING_H +#define GCC_ESCAPED_STRING_H + +#include + +/* 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 */ diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C index 3dd3a1fdc7e..c195dfe7b80 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-67.C @@ -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 } } } diff --git a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C index a5d94462c87..a18d6aea985 100644 --- a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C +++ b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C @@ -439,7 +439,7 @@ # 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 diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C index 2b9cfd0effc..95251c2f5c6 100644 --- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C +++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C @@ -470,8 +470,8 @@ # 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 index 00000000000..a5c2c6514cf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nodiscard-constructor.c @@ -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 index 00000000000..4518a11c970 --- /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 (); + (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 index 00000000000..af715e2d6b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nodiscard-reason-nonstring.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 (); + (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 index 00000000000..602a4e273f5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nodiscard-reason-only-one.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 (); + (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..0113c904260 --- /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 e845fc7a00e..2bee1d255ff 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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