+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
+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.
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;
}
+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.
#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);
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),
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);
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);
}
}
/* 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)
&& 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");
}
}
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)))
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 },
--- /dev/null
+/* 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 */
[[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 } } }
# 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
# 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)
--- /dev/null
+/* 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" } */
+}
--- /dev/null
+/* 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 ();
+}
--- /dev/null
+/* 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 ();
+}
--- /dev/null
+/* 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 ();
+}
--- /dev/null
+/* 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" } */
+}
#include "regs.h"
#include "tree-vector-builder.h"
#include "gimple-fold.h"
+#include "escaped_string.h"
/* Tree code classes. */
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