aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2016-04-13 16:11:29 -0400
committerJason Merrill <jason@gcc.gnu.org>2016-04-13 16:11:29 -0400
commit2ee35bea2e5f0241fff589ddc038c9d8eb444fb9 (patch)
treef4446c9a372328e1c80530640ab77106661bfe34 /gcc/cp
parent5655267ca161de13e553dbfc0b7e58962fbb2443 (diff)
downloadgcc-2ee35bea2e5f0241fff589ddc038c9d8eb444fb9.zip
gcc-2ee35bea2e5f0241fff589ddc038c9d8eb444fb9.tar.gz
gcc-2ee35bea2e5f0241fff589ddc038c9d8eb444fb9.tar.bz2
Warn about empty parameter ABI with -Wabi=9.
* call.c (empty_class_msg, mark_for_abi_warning) (warn_empty_class_abi): New. (build_call_a): Use them. * decl.c (store_parm_decls): Use mark_for_abi_warning. * error.c (pp_format_to_string): New. From-SVN: r234960
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/call.c58
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/decl.c20
-rw-r--r--gcc/cp/error.c22
5 files changed, 109 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 28541bc..c9929b63 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,12 @@
2016-04-13 Jason Merrill <jason@redhat.com>
+ Warn about empty parameter ABI with -Wabi=9.
+ * call.c (empty_class_msg, mark_for_abi_warning)
+ (warn_empty_class_abi): New.
+ (build_call_a): Use them.
+ * decl.c (store_parm_decls): Use mark_for_abi_warning.
+ * error.c (pp_format_to_string): New.
+
Pass empty class parameters like C.
* call.c (pass_as_empty_struct, empty_class_arg): New.
(type_passed_as, build_x_va_arg): Use pass_as_empty_struct.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 84b6243..687e7bd 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -381,6 +381,11 @@ build_call_a (tree function, int n, tree *argarray)
/* Don't pass empty class objects by value. This is useful
for tags in STL, which are used to control overload resolution.
We don't need to handle other cases of copying empty classes. */
+ bool warned = false;
+ if (decl && !TREE_PUBLIC (decl))
+ /* Don't warn about the ABI of a function local to this TU. */
+ warned = true;
+ tree empty_arg = NULL_TREE;
if (! decl || ! DECL_BUILT_IN (decl))
for (i = 0; i < n; i++)
{
@@ -389,8 +394,19 @@ build_call_a (tree function, int n, tree *argarray)
if (is_really_empty_class (type)
&& ! TREE_ADDRESSABLE (type))
{
+ empty_arg = arg;
CALL_EXPR_ARG (function, i) = empty_class_arg (arg);
}
+ /* Warn about ABI changes for a non-final argument. */
+ else if (!warned && empty_arg)
+ {
+ location_t loc = EXPR_LOC_OR_LOC (empty_arg, input_location);
+ if (decl && !varargs_function_p (decl))
+ mark_for_abi_warning (decl, empty_arg);
+ else
+ warn_empty_class_abi (empty_arg, loc);
+ warned = true;
+ }
}
return function;
@@ -6878,6 +6894,7 @@ build_x_va_arg (source_location loc, tree expr, tree type)
/* Do the reverse of empty_class_arg. */
tree etype = pass_as_empty_struct (type) ? empty_struct_type : type;
expr = build_va_arg (loc, expr, etype);
+ warn_empty_class_abi (type, loc);
tree ec = build0 (EMPTY_CLASS_EXPR, type);
return build2 (COMPOUND_EXPR, type, expr, ec);
}
@@ -7005,6 +7022,47 @@ empty_class_arg (tree val)
return build2 (COMPOUND_EXPR, etype, val, empty);
}
+/* Generate a message warning about the change in empty class parameter passing
+ ABI. */
+
+static tree
+empty_class_msg (tree type)
+{
+ if (!TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ return pp_format_to_string ("empty class %qT parameter passing ABI "
+ "changes in -fabi-version=10 (GCC 6)", type);
+}
+
+/* Warn immediately about the change in empty class parameter ABI. */
+
+void
+warn_empty_class_abi (tree arg, location_t loc)
+{
+ if (!warn_abi || !abi_version_crosses (10))
+ return;
+
+ warning_at (loc, OPT_Wabi, "%E", empty_class_msg (arg));
+}
+
+/* Tack a warning about the change in empty class parameter ABI onto FN, so
+ that we get a warning if a definition or call is emitted. */
+
+void
+mark_for_abi_warning (tree fn, tree type)
+{
+ if (!warn_abi || !abi_version_crosses (10))
+ return;
+ if (lookup_attribute ("abi warning", DECL_ATTRIBUTES (fn)))
+ return;
+
+ tree msg = empty_class_msg (type);
+ msg = build_tree_list (NULL_TREE, msg);
+ DECL_ATTRIBUTES (fn) = tree_cons (get_identifier ("abi warning"), msg,
+ DECL_ATTRIBUTES (fn));
+}
+
/* Returns the type which will really be used for passing an argument of
type TYPE. */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index faea452..8d721c7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5540,6 +5540,8 @@ extern tree build_addr_func (tree, tsubst_flags_t);
extern void set_flags_from_callee (tree);
extern tree build_call_a (tree, int, tree*);
extern tree build_call_n (tree, int, ...);
+extern void mark_for_abi_warning (tree, tree);
+extern void warn_empty_class_abi (tree, location_t);
extern bool null_ptr_cst_p (tree);
extern bool null_member_pointer_value_p (tree);
extern bool sufficient_parms_p (const_tree);
@@ -5894,6 +5896,7 @@ extern bool pedwarn_cxx98 (location_t, int, const char *,
extern location_t location_of (tree);
extern void qualified_name_lookup_error (tree, tree, tree,
location_t);
+extern tree pp_format_to_string (const char *, ...);
/* in except.c */
extern void init_exception_processing (void);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5ca426b..7099199 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -14332,16 +14332,34 @@ store_parm_decls (tree current_function_parms)
they end in the correct forward order. */
specparms = nreverse (specparms);
+ /* Don't warn about the ABI of a function local to this TU. */
+ bool warned = !TREE_PUBLIC (current_function_decl);
+ bool saw_nonempty = false;
for (parm = specparms; parm; parm = next)
{
next = DECL_CHAIN (parm);
if (TREE_CODE (parm) == PARM_DECL)
{
+ tree type = TREE_TYPE (parm);
if (DECL_NAME (parm) == NULL_TREE
- || !VOID_TYPE_P (parm))
+ || !VOID_TYPE_P (type))
pushdecl (parm);
else
error ("parameter %qD declared void", parm);
+ /* If this isn't the last parameter, maybe warn about ABI change
+ in passing empty classes. */
+ if (processing_template_decl)
+ continue;
+ if (TREE_ADDRESSABLE (type)
+ || !is_really_empty_class (type))
+ saw_nonempty = true;
+ else if (!warned
+ && (saw_nonempty
+ || varargs_function_p (current_function_decl)))
+ {
+ mark_for_abi_warning (current_function_decl, type);
+ warned = true;
+ }
}
else
{
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index aa5fd41..5aaa177 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -3718,3 +3718,25 @@ qualified_name_lookup_error (tree scope, tree name,
suggest_alternatives_for (location, name);
}
}
+
+/* Like error et al, but return the formatted message as a STRING_CST. */
+
+tree
+pp_format_to_string (const char *msg, ...)
+{
+ pretty_printer *pp = global_dc->printer;
+ text_info text;
+ va_list ap;
+
+ va_start (ap, msg);
+ text.err_no = errno;
+ text.args_ptr = &ap;
+ text.format_spec = msg;
+ pp_format (pp, &text);
+ pp_output_formatted_text (pp);
+ va_end (ap);
+ const char *fmt = pp_formatted_text (pp);
+ tree str = build_string (strlen (fmt) + 1, fmt);
+ pp_clear_output_area (pp);
+ return str;
+}