Commit 62984918 by Jason Merrill Committed by Jason Merrill

Support -Wabi warning about backward compatibility.

gcc/c-family/
	* c.opt (Wabi=, fabi-compat-version): New.
	* c-opts.c (c_common_handle_option): Handle -Wabi=.
	(c_common_post_options): Handle flag_abi_compat_version default.
	Disallow -fabi-compat-version=1.
	* c-common.h (abi_version_crosses): New.
gcc/cp/
	* call.c (convert_arg_to_ellipsis): Use abi_version_crosses.
	* cvt.c (type_promotes_to): Likewise.
	* mangle.c (write_type, write_expression): Likewise.
	(write_name, write_template_arg): Likewise.
	(mangle_decl): Make alias based on flag_abi_compat_version.
	Emit -Wabi warning here.
	(finish_mangling_internal): Not here.  Drop warn parm.
	(finish_mangling_get_identifier, finish_mangling): Adjust.
	(mangle_type_string, mangle_special_for_type): Adjust.
	(mangle_ctor_vtbl_for_type, mangle_thunk): Adjust.
	(mangle_guard_variable, mangle_tls_init_fn): Adjust.
	(mangle_tls_wrapper_fn, mangle_ref_init_variable): Adjust.

From-SVN: r211594
parent ca0e51a0
2014-06-12 Jason Merrill <jason@redhat.com>
* c.opt (Wabi=, fabi-compat-version): New.
* c-opts.c (c_common_handle_option): Handle -Wabi=.
(c_common_post_options): Handle flag_abi_compat_version default.
Disallow -fabi-compat-version=1.
* c-common.h (abi_version_crosses): New.
2014-06-11 Jan Hubicka <hubicka@ucw.cz>
* c-family/c-common.c (handle_section_attribute): Update handling for
......
......@@ -619,6 +619,13 @@ extern const char *constant_string_class_name;
/* C++ language option variables. */
/* Return TRUE if one of {flag_abi_version,flag_abi_compat_version} is
less than N and the other is at least N, for use by -Wabi. */
#define abi_version_crosses(N) \
(abi_version_at_least(N) \
!= (flag_abi_compat_version == 0 \
|| flag_abi_compat_version >= (N)))
/* Nonzero means generate separate instantiation control files and
juggle them at link time. */
......
......@@ -456,6 +456,16 @@ c_common_handle_option (size_t scode, const char *arg, int value,
handle_OPT_d (arg);
break;
case OPT_Wabi_:
warn_abi = true;
if (value == 1)
{
warning (0, "%<-Wabi=1%> is not supported, using =2");
value = 2;
}
flag_abi_compat_version = value;
break;
case OPT_fcanonical_system_headers:
cpp_opts->canonical_system_headers = value;
break;
......@@ -910,6 +920,22 @@ c_common_post_options (const char **pfilename)
if (flag_declone_ctor_dtor == -1)
flag_declone_ctor_dtor = optimize_size;
if (flag_abi_compat_version == 1)
{
warning (0, "%<-fabi-compat-version=1%> is not supported, using =2");
flag_abi_compat_version = 2;
}
else if (flag_abi_compat_version == -1)
{
/* Generate compatibility aliases for ABI v2 (3.4-4.9) by default. */
flag_abi_compat_version = (flag_abi_version == 0 ? 2 : 0);
/* But don't warn about backward compatibility unless explicitly
requested with -Wabi=n. */
if (flag_abi_version == 0)
warn_abi = false;
}
if (cxx_dialect >= cxx11)
{
/* If we're allowing C++0x constructs, don't warn about C++98
......
......@@ -256,6 +256,10 @@ Wabi
C ObjC C++ ObjC++ LTO Var(warn_abi) Warning
Warn about things that will change when compiling with an ABI-compliant compiler
Wabi=
C ObjC C++ ObjC++ LTO Joined RejectNegative UInteger Warning
Warn about things that change between the current -fabi-version and the specified version
Wabi-tag
C++ ObjC++ Var(warn_abi_tag) Warning
Warn if a subobject has an abi_tag attribute that the complete object type does not have
......@@ -845,6 +849,10 @@ d
C ObjC C++ ObjC++ Joined
; Documented in common.opt. FIXME - what about -dI, -dD, -dN and -dD?
fabi-compat-version=
C++ ObjC++ Joined RejectNegative UInteger Var(flag_abi_compat_version) Init(-1)
The version of the C++ ABI used for -Wabi warnings and link compatibility aliases
faccess-control
C++ ObjC++ Var(flag_access_control) Init(1)
Enforce class member access control semantics
......
2014-06-12 Jason Merrill <jason@redhat.com>
* call.c (convert_arg_to_ellipsis): Use abi_version_crosses.
* cvt.c (type_promotes_to): Likewise.
* mangle.c (write_type, write_expression): Likewise.
(write_name, write_template_arg): Likewise.
(mangle_decl): Make alias based on flag_abi_compat_version.
Emit -Wabi warning here.
(finish_mangling_internal): Not here. Drop warn parm.
(finish_mangling_get_identifier, finish_mangling): Adjust.
(mangle_type_string, mangle_special_for_type): Adjust.
(mangle_ctor_vtbl_for_type, mangle_thunk): Adjust.
(mangle_guard_variable, mangle_tls_init_fn): Adjust.
(mangle_tls_wrapper_fn, mangle_ref_init_variable): Adjust.
* call.c (build_operator_new_call): Remove -fabi-version=1 support.
* class.c (walk_subobject_offsets, include_empty_classes): Likewise.
(layout_nonempty_base_or_field, end_of_class): Likewise.
......
......@@ -6508,14 +6508,22 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
arg = null_pointer_node;
else if (INTEGRAL_OR_ENUMERATION_TYPE_P (arg_type))
{
if (SCOPED_ENUM_P (arg_type) && !abi_version_at_least (6))
if (SCOPED_ENUM_P (arg_type))
{
if (complain & tf_warning)
warning_at (loc, OPT_Wabi, "scoped enum %qT will not promote to an "
"integral type in a future version of GCC", arg_type);
arg = cp_convert (ENUM_UNDERLYING_TYPE (arg_type), arg, complain);
tree prom = cp_convert (ENUM_UNDERLYING_TYPE (arg_type), arg,
complain);
prom = cp_perform_integral_promotions (prom, complain);
if (abi_version_crosses (6)
&& TYPE_MODE (TREE_TYPE (prom)) != TYPE_MODE (arg_type)
&& (complain & tf_warning))
warning_at (loc, OPT_Wabi, "scoped enum %qT passed through ... as "
"%qT before -fabi-version=6, %qT after", arg_type,
TREE_TYPE (prom), ENUM_UNDERLYING_TYPE (arg_type));
if (!abi_version_at_least (6))
arg = prom;
}
arg = cp_perform_integral_promotions (arg, complain);
else
arg = cp_perform_integral_promotions (arg, complain);
}
arg = require_complete_type_sfinae (arg, complain);
......
......@@ -1701,13 +1701,9 @@ type_promotes_to (tree type)
if (TREE_CODE (type) == BOOLEAN_TYPE)
type = integer_type_node;
/* Scoped enums don't promote, but pretend they do for backward ABI bug
compatibility wrt varargs. */
else if (SCOPED_ENUM_P (type) && abi_version_at_least (6))
;
/* Normally convert enums to int, but convert wide enums to something
wider. */
wider. Scoped enums don't promote, but pretend they do for backward
ABI bug compatibility wrt varargs. */
else if (TREE_CODE (type) == ENUMERAL_TYPE
|| type == char16_type_node
|| type == char32_type_node
......@@ -1716,16 +1712,26 @@ type_promotes_to (tree type)
int precision = MAX (TYPE_PRECISION (type),
TYPE_PRECISION (integer_type_node));
tree totype = c_common_type_for_size (precision, 0);
tree prom = type;
if (TREE_CODE (prom) == ENUMERAL_TYPE)
prom = ENUM_UNDERLYING_TYPE (prom);
if (TYPE_UNSIGNED (prom)
&& ! int_fits_type_p (TYPE_MAX_VALUE (prom), totype))
prom = c_common_type_for_size (precision, 1);
else
prom = totype;
if (SCOPED_ENUM_P (type))
warning (OPT_Wabi, "scoped enum %qT will not promote to an integral "
"type in a future version of GCC", type);
if (TREE_CODE (type) == ENUMERAL_TYPE)
type = ENUM_UNDERLYING_TYPE (type);
if (TYPE_UNSIGNED (type)
&& ! int_fits_type_p (TYPE_MAX_VALUE (type), totype))
type = c_common_type_for_size (precision, 1);
{
if (abi_version_crosses (6)
&& TYPE_MODE (prom) != TYPE_MODE (type))
warning (OPT_Wabi, "scoped enum %qT passed through ... as "
"%qT before -fabi-version=6, %qT after",
type, prom, ENUM_UNDERLYING_TYPE (type));
if (!abi_version_at_least (6))
type = prom;
}
else
type = totype;
type = prom;
}
else if (c_promoting_integer_type_p (type))
{
......
......@@ -225,7 +225,6 @@ static int local_class_index (tree);
/* Control functions. */
static inline void start_mangling (const tree);
static inline const char *finish_mangling (const bool);
static tree mangle_special_for_type (const tree, const char *);
/* Foreign language functions. */
......@@ -786,6 +785,11 @@ write_name (tree decl, const int ignore_local_scope)
gcc_assert (context != NULL_TREE);
if (abi_version_crosses (7)
&& ignore_local_scope
&& TREE_CODE (context) == PARM_DECL)
G.need_abi_warning = 1;
/* A decl in :: or ::std scope is treated specially. The former is
mangled using <unscoped-name> or <unscoped-template-name>, the
latter with a special substitution. Also, a name that is
......@@ -1865,6 +1869,8 @@ write_type (tree type)
write_function_type (t);
else
write_type (t);
if (abi_version_crosses (8))
G.need_abi_warning = 1;
}
else
write_type (t);
......@@ -1970,9 +1976,14 @@ write_type (tree type)
a typedef or template argument can have function type
with function-cv-quals (that use the same representation),
but you can't have a pointer/reference to such a type. */
if (abi_version_at_least (5)
&& TREE_CODE (target) == FUNCTION_TYPE)
target = build_qualified_type (target, TYPE_UNQUALIFIED);
if (TREE_CODE (target) == FUNCTION_TYPE)
{
if (abi_version_crosses (5)
&& TYPE_QUALS (target) != TYPE_UNQUALIFIED)
G.need_abi_warning = 1;
if (abi_version_at_least (5))
target = build_qualified_type (target, TYPE_UNQUALIFIED);
}
write_type (target);
}
break;
......@@ -2012,10 +2023,9 @@ write_type (tree type)
write_char ('_');
}
else
{
G.need_abi_warning = 1;
write_string ("U8__vector");
}
write_string ("U8__vector");
if (abi_version_crosses (4))
G.need_abi_warning = 1;
write_type (TREE_TYPE (type));
break;
......@@ -2030,8 +2040,7 @@ write_type (tree type)
&& !DECLTYPE_FOR_LAMBDA_PROXY (type));
/* In ABI <5, we stripped decltype of a plain decl. */
if (!abi_version_at_least (5)
&& DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type))
{
tree expr = DECLTYPE_TYPE_EXPR (type);
tree etype = NULL_TREE;
......@@ -2052,9 +2061,13 @@ write_type (tree type)
if (etype && !type_uses_auto (etype))
{
G.need_abi_warning = 1;
write_type (etype);
return;
if (abi_version_crosses (5))
G.need_abi_warning = 1;
if (!abi_version_at_least (5))
{
write_type (etype);
return;
}
}
}
......@@ -2073,6 +2086,8 @@ write_type (tree type)
write_string ("Dn");
if (abi_version_at_least (7))
++is_builtin_type;
if (abi_version_crosses (7))
G.need_abi_warning = 1;
break;
case TYPEOF_TYPE:
......@@ -2621,7 +2636,7 @@ write_expression (tree expr)
write_char ('L');
write_unsigned_number (delta - 1);
}
else
if (abi_version_crosses (5))
G.need_abi_warning = true;
}
write_char ('p');
......@@ -2853,12 +2868,13 @@ write_expression (tree expr)
name = operator_name_info[(int) code].mangled_name;
/* We used to mangle const_cast and static_cast like a C cast. */
if (!abi_version_at_least (6)
&& (code == CONST_CAST_EXPR
|| code == STATIC_CAST_EXPR))
if (code == CONST_CAST_EXPR
|| code == STATIC_CAST_EXPR)
{
name = operator_name_info[CAST_EXPR].mangled_name;
G.need_abi_warning = 1;
if (abi_version_crosses (6))
G.need_abi_warning = 1;
if (!abi_version_at_least (6))
name = operator_name_info[CAST_EXPR].mangled_name;
}
if (name == NULL)
......@@ -2929,7 +2945,7 @@ write_expression (tree expr)
case PREDECREMENT_EXPR:
if (abi_version_at_least (6))
write_char ('_');
else
if (abi_version_crosses (6))
G.need_abi_warning = 1;
/* Fall through. */
......@@ -3064,7 +3080,7 @@ write_template_arg (tree node)
{
if (abi_version_at_least (6))
node = BASELINK_FUNCTIONS (node);
else
if (abi_version_crosses (6))
/* We wrongly wrapped a class-scope function in X/E. */
G.need_abi_warning = 1;
}
......@@ -3077,10 +3093,9 @@ write_template_arg (tree node)
if (abi_version_at_least (6))
write_char ('J');
else
{
write_char ('I');
G.need_abi_warning = 1;
}
write_char ('I');
if (abi_version_crosses (6))
G.need_abi_warning = 1;
for (i = 0; i < length; ++i)
write_template_arg (TREE_VEC_ELT (args, i));
write_char ('E');
......@@ -3100,12 +3115,11 @@ write_template_arg (tree node)
/* Until ABI version 3, the underscore before the mangled name
was incorrectly omitted. */
if (!abi_version_at_least (3))
{
G.need_abi_warning = 1;
write_char ('Z');
}
write_char ('Z');
else
write_string ("_Z");
if (abi_version_crosses (3))
G.need_abi_warning = 1;
write_encoding (node);
write_char ('E');
}
......@@ -3286,13 +3300,8 @@ start_mangling (const tree entity)
warning. */
static void
finish_mangling_internal (const bool warn)
finish_mangling_internal (void)
{
if (warn_abi && warn && G.need_abi_warning)
warning (OPT_Wabi, "the mangled name of %qD will change in a future "
"version of GCC",
G.entity);
/* Clear all the substitutions. */
vec_safe_truncate (G.substitutions, 0);
......@@ -3304,18 +3313,18 @@ finish_mangling_internal (const bool warn)
/* Like finish_mangling_internal, but return the mangled string. */
static inline const char *
finish_mangling (const bool warn)
finish_mangling (void)
{
finish_mangling_internal (warn);
finish_mangling_internal ();
return (const char *) obstack_finish (mangle_obstack);
}
/* Like finish_mangling_internal, but return an identifier. */
static tree
finish_mangling_get_identifier (const bool warn)
finish_mangling_get_identifier (void)
{
finish_mangling_internal (warn);
finish_mangling_internal ();
/* Don't obstack_finish here, and the next start_mangling will
remove the identifier. */
return get_identifier ((const char *) obstack_base (mangle_obstack));
......@@ -3373,7 +3382,7 @@ mangle_decl_string (const tree decl)
else
write_mangled_name (decl, true);
result = finish_mangling_get_identifier (/*warn=*/true);
result = finish_mangling_get_identifier ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_decl_string = '%s'\n\n",
IDENTIFIER_POINTER (result));
......@@ -3425,26 +3434,47 @@ mangle_decl (const tree decl)
&& !DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
&& !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
{
#ifdef ASM_OUTPUT_DEF
/* If the mangling will change in the future, emit an alias with the
future mangled name for forward-compatibility. */
int save_ver;
tree id2, alias;
#endif
tree id2;
SET_IDENTIFIER_GLOBAL_VALUE (id, decl);
if (IDENTIFIER_GLOBAL_VALUE (id) != decl)
inform (DECL_SOURCE_LOCATION (decl), "-fabi-version=6 (or =0) "
inform (DECL_SOURCE_LOCATION (decl), "a later -fabi-version= (or =0) "
"avoids this error with a change in mangling");
#ifdef ASM_OUTPUT_DEF
save_ver = flag_abi_version;
flag_abi_version = 0;
flag_abi_version = flag_abi_compat_version;
id2 = mangle_decl_string (decl);
id2 = targetm.mangle_decl_assembler_name (decl, id2);
flag_abi_version = save_ver;
alias = make_alias_for (decl, id2);
if (id2 == id)
return;
if (warn_abi)
{
if (flag_abi_compat_version != 0
&& abi_version_at_least (flag_abi_compat_version))
warning (OPT_Wabi, "the mangled name of %q+D changed between "
"-fabi-version=%d (%D) and -fabi-version=%d (%D)",
G.entity, flag_abi_compat_version, id2,
flag_abi_version, id);
else
warning (OPT_Wabi, "the mangled name of %q+D changes between "
"-fabi-version=%d (%D) and -fabi-version=%d (%D)",
G.entity, flag_abi_version, id,
flag_abi_compat_version, id2);
}
#ifdef ASM_OUTPUT_DEF
if (flag_abi_compat_version != 0
&& IDENTIFIER_GLOBAL_VALUE (id2))
return;
tree alias = make_alias_for (decl, id2);
SET_IDENTIFIER_GLOBAL_VALUE (id2, alias);
DECL_IGNORED_P (alias) = 1;
TREE_PUBLIC (alias) = TREE_PUBLIC (decl);
DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
......@@ -3471,7 +3501,7 @@ mangle_type_string (const tree type)
start_mangling (type);
write_type (type);
result = finish_mangling (/*warn=*/false);
result = finish_mangling ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_type_string = '%s'\n\n", result);
return result;
......@@ -3496,7 +3526,7 @@ mangle_special_for_type (const tree type, const char *code)
/* Add the type. */
write_type (type);
result = finish_mangling_get_identifier (/*warn=*/false);
result = finish_mangling_get_identifier ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_special_for_type = %s\n\n",
......@@ -3567,7 +3597,7 @@ mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
write_char ('_');
write_type (BINFO_TYPE (binfo));
result = finish_mangling_get_identifier (/*warn=*/false);
result = finish_mangling_get_identifier ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n",
IDENTIFIER_POINTER (result));
......@@ -3646,7 +3676,7 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
/* Scoped name. */
write_encoding (fn_decl);
result = finish_mangling_get_identifier (/*warn=*/false);
result = finish_mangling_get_identifier ();
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_thunk = %s\n\n", IDENTIFIER_POINTER (result));
return result;
......@@ -3739,7 +3769,7 @@ mangle_guard_variable (const tree variable)
start_mangling (variable);
write_string ("_ZGV");
write_guarded_var_name (variable);
return finish_mangling_get_identifier (/*warn=*/false);
return finish_mangling_get_identifier ();
}
/* Return an identifier for the name of a thread_local initialization
......@@ -3751,7 +3781,7 @@ mangle_tls_init_fn (const tree variable)
start_mangling (variable);
write_string ("_ZTH");
write_guarded_var_name (variable);
return finish_mangling_get_identifier (/*warn=*/false);
return finish_mangling_get_identifier ();
}
/* Return an identifier for the name of a thread_local wrapper
......@@ -3765,7 +3795,7 @@ mangle_tls_wrapper_fn (const tree variable)
start_mangling (variable);
write_string (TLS_WRAPPER_PREFIX);
write_guarded_var_name (variable);
return finish_mangling_get_identifier (/*warn=*/false);
return finish_mangling_get_identifier ();
}
/* Return true iff FN is a thread_local wrapper function. */
......@@ -3795,7 +3825,7 @@ mangle_ref_init_variable (const tree variable)
/* Avoid name clashes with aggregate initialization of multiple
references at once. */
write_unsigned_number (temp_count++);
return finish_mangling_get_identifier (/*warn=*/false);
return finish_mangling_get_identifier ();
}
......
......@@ -195,7 +195,7 @@ in the following sections.
-fvtv-counts -fvtv-debug @gol
-fvisibility-ms-compat @gol
-fext-numeric-literals @gol
-Wabi -Wconversion-null -Wctor-dtor-privacy @gol
-Wabi=@var{n} -Wconversion-null -Wctor-dtor-privacy @gol
-Wdelete-non-virtual-dtor -Wliteral-suffix -Wnarrowing @gol
-Wnoexcept -Wnon-virtual-dtor -Wreorder @gol
-Weffc++ -Wstrict-null-sentinel @gol
......@@ -2023,7 +2023,7 @@ Here is a list of options that are @emph{only} for compiling C++ programs:
@item -fabi-version=@var{n}
@opindex fabi-version
Use version @var{n} of the C++ ABI@. The default is version 2.
Use version @var{n} of the C++ ABI@. The default is version 0.
Version 0 refers to the version conforming most closely to
the C++ ABI specification. Therefore, the ABI obtained using version 0
......@@ -2031,7 +2031,8 @@ will change in different versions of G++ as ABI bugs are fixed.
Version 1 is the version of the C++ ABI that first appeared in G++ 3.2.
Version 2 is the version of the C++ ABI that first appeared in G++ 3.4.
Version 2 is the version of the C++ ABI that first appeared in G++
3.4, and was the default through G++ 4.9.
Version 3 corrects an error in mangling a constant address as a
template argument.
......@@ -2049,8 +2050,27 @@ behavior of C++11 scoped enums and the mangling of template argument
packs, const/static_cast, prefix ++ and --, and a class scope function
used as a template argument.
Version 7, which first appeared in G++ 4.8, that treats nullptr_t as a
builtin type and corrects the mangling of lambdas in default argument
scope.
Version 8, which first appeared in G++ 4.9, corrects the substitution
behavior of function types with function-cv-qualifiers.
See also @option{-Wabi}.
@item -fabi-compat-version=@var{n}
@opindex fabi-compat-version
Starting with GCC 4.5, on targets that support strong aliases, G++
works around mangling changes by creating an alias with the correct
mangled name when defining a symbol with an incorrect mangled name.
This switch specifies which ABI version to use for the alias.
With @option{-fabi-version=0} (the default), this defaults to 2. If
another ABI version is explicitly selected, this defaults to 0.
The compatibility version is also set by @option{-Wabi=@var{n}}.
@item -fno-access-control
@opindex fno-access-control
Turn off all access checking. This switch is mainly useful for working
......@@ -2445,8 +2465,15 @@ have meanings only for C++ programs:
@item -Wabi @r{(C, Objective-C, C++ and Objective-C++ only)}
@opindex Wabi
@opindex Wno-abi
Warn when G++ generates code that is probably not compatible with the
vendor-neutral C++ ABI@. Although an effort has been made to warn about
When an explicit @option{-fabi-version=@var{n}} option is used, causes
G++ to warn when it generates code that is probably not compatible with the
vendor-neutral C++ ABI@. Since G++ now defaults to
@option{-fabi-version=0}, @option{-Wabi} has no effect unless either
an older ABI version is selected (with @option{-fabi-version=@var{n}})
or an older compatibility version is selected (with
@option{-Wabi=@var{n}} or @option{-fabi-compat-version=@var{n}}).
Although an effort has been made to warn about
all such cases, there are probably some cases that are not warned about,
even though G++ is generating incompatible code. There may also be
cases where warnings are emitted even though the code that is generated
......@@ -2456,12 +2483,19 @@ You should rewrite your code to avoid these warnings if you are
concerned about the fact that code generated by G++ may not be binary
compatible with code generated by other compilers.
The known incompatibilities in @option{-fabi-version=2} (the default) include:
@option{-Wabi} can also be used with an explicit version number to
warn about compatibility with a particular @option{-fabi-version}
level, e.g. @option{-Wabi=2} to warn about changes relative to
@option{-fabi-version=2}. Specifying a version number also sets
@option{-fabi-compat-version=@var{n}}.
The known incompatibilities in @option{-fabi-version=2} (which was the
default from GCC 3.4 to 4.9) include:
@itemize @bullet
@item
A template with a non-type template parameter of reference type is
A template with a non-type template parameter of reference type was
mangled incorrectly:
@smallexample
extern int N;
......@@ -2469,14 +2503,45 @@ template <int &> struct S @{@};
void n (S<N>) @{2@}
@end smallexample
This is fixed in @option{-fabi-version=3}.
This was fixed in @option{-fabi-version=3}.
@item
SIMD vector types declared using @code{__attribute ((vector_size))} are
SIMD vector types declared using @code{__attribute ((vector_size))} were
mangled in a non-standard way that does not allow for overloading of
functions taking vectors of different sizes.
The mangling is changed in @option{-fabi-version=4}.
The mangling was changed in @option{-fabi-version=4}.
@item
@code{__attribute ((const))} and @code{noreturn} were mangled as type
qualifiers, and @code{decltype} of a plain declaration was folded away.
These mangling issues were fixed in @option{-fabi-version=5}.
@item
Scoped enumerators passed as arguments to a variadic function are
promoted like unscoped enumerators, causing @samp{va_arg} to complain.
On most targets this does not actually affect the parameter passing
ABI, as there is no way to pass an argument smaller than @samp{int}.
Also, the ABI changed the mangling of template argument packs,
@code{const_cast}, @code{static_cast}, prefix increment/decrement, and
a class scope function used as a template argument.
These issues were corrected in @option{-fabi-version=6}.
@item
Lambdas in default argument scope were mangled incorrectly, and the
ABI changed the mangling of nullptr_t.
These issues were corrected in @option{-fabi-version=7}.
@item
When mangling a function type with function-cv-qualifiers, the
un-qualified function type was incorrectly treated as a substitution
candidate.
This was fixed in @option{-fabi-version=8}.
@end itemize
It also warns about psABI-related changes. The known psABI changes at this
......
// { dg-do compile }
// { dg-options "-fabi-version=2 -Wno-abi" }
// { dg-options "-fabi-version=2 -Wabi" }
// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 15 Dec 2003 <nathan@codesourcery.com>
......@@ -9,5 +9,5 @@
extern int N;
template <int &> struct S {};
void n (S<N>) {}
void n (S<N>) {} // { dg-warning "mangle" }
// { dg-final { scan-assembler "\n_?_Z1n1SILZ1NEE\[: \t\n\]" } }
// Test mangling of type casts
// { dg-options "-fabi-version=0" }
// { dg-options "-fabi-version=0 -Wabi=5" }
// { dg-do compile }
template<int i> class A {};
template<bool b> class B {};
template<int i> void f(A<i> &, B<bool(i)> &) {}
template<int i> void g(A<i> &, B<static_cast<bool>(i)> &) {}
template<int i> void g(A<i> &, B<static_cast<bool>(i)> &) {} // { dg-warning "mangle" }
int main()
{
......
// Test mangling of type casts
// { dg-options "-fabi-version=2" }
// { dg-options "-fabi-version=2 -Wabi" }
// { dg-do compile }
template<int i> class A {};
template<bool b> class B {};
template<int i> void f(A<i> &, B<bool(i)> &) {}
template<int i> void g(A<i> &, B<static_cast<bool>(i)> &) {}
template<int i> void g(A<i> &, B<static_cast<bool>(i)> &) {} // { dg-warning "mangle" }
int main()
{
......
// Testcase for mangling of parameters used other than in a trailing return type
// { dg-do compile { target c++11 } }
// { dg-options "-fabi-version=5" }
// { dg-options "-fabi-version=5 -Wabi=4" }
template<class T> void f(T p, decltype(p)) { } // L = 1
template<class T> void g(T p, decltype(p) (*)()) { } // L = 1
template<class T> void f(T p, decltype(p)) { } // L = 1 { dg-warning "mangle" }
template<class T> void g(T p, decltype(p) (*)()) { } // L = 1 { dg-warning "mangle" }
// G++ incorrectly rejects these currently.
// template<class T> void h(T p, auto (*)()->decltype(p)); // L = 1
// template<class T> void i(T p, auto (*)(T q)->decltype(q)); // L = 0
// template<class T> void j(T p, auto (*)(decltype(p))->T); // L = 2
template<class T> void k(T p, int (*(*)(T* p))[sizeof(p)]) {} // L = 1
template<class T> void k(T p, int (*(*)(T* p))[sizeof(p)]) {} // L = 1 { dg-warning "mangle" }
int garg();
int (*karg (int*))[sizeof(int)];
int main()
{
// { dg-final { scan-assembler "_Z1fIiEvT_DtfL0p_E" } }
// { dg-final { scan-assembler "\n_?_Z1fIiEvT_DtfL0p_E\[: \t\n\]" } }
f (1,0);
// { dg-final { scan-assembler "_Z1gIiEvT_PFDtfL0p_EvE" } }
// { dg-final { scan-assembler "\n_?_Z1gIiEvT_PFDtfL0p_EvE\[: \t\n\]" } }
g (1,garg);
// h (1,0);
// i (1,0);
// j (1,0);
// { dg-final { scan-assembler "_Z1kIiEvT_PFPAszfL0p__iPS0_E" } }
// { dg-final { scan-assembler "\n_?_Z1kIiEvT_PFPAszfL0p__iPS0_E\[: \t\n\]" } }
k (1,karg);
}
// PR c++/49932
// { dg-do compile { target c++11 } }
// { dg-options "-fabi-version=0" }
// { dg-options "-fabi-version=0 -Wabi=2" }
template < typename T >
auto
f1( T x ) // ICE on here
f1( T x ) // { dg-warning "mangle" }
-> typename decltype( x )::type {}
template < typename T >
......@@ -19,5 +19,5 @@ void g()
f2( S() );
}
// { dg-final { scan-assembler "_Z2f1I1SENDtfp_E4typeET_" } }
// { dg-final { scan-assembler "_Z2f2I1SENDTcvT__EE4typeES1_" } }
// { dg-final { scan-assembler "\n_?_Z2f1I1SENDtfp_E4typeET_\[: \t\n\]" } }
// { dg-final { scan-assembler "\n_?_Z2f2I1SENDTcvT__EE4typeES1_\[: \t\n\]" } }
// { dg-options "-fabi-version=0" }
// { dg-options "-fabi-version=0 -Wabi=2" }
template <unsigned int> struct helper {};
// { dg-final { scan-assembler "_Z6check1IiEvP6helperIXszscT_Li1EEE" } }
template <class T> void check1( helper<sizeof(static_cast<T>(1))> * ) { }
// { dg-final { scan-assembler "_Z6check2IiXadL_Z1iEEEvP6helperIXszccPT_T0_EE" } }
template <class T, T* p> void check2( helper<sizeof(const_cast<T*>(p))> * ) { }
// { dg-final { scan-assembler "_Z6check3IiEvP6helperIXszrcPT_Li0EEE" } }
// { dg-final { scan-assembler "\n_?_Z6check1IiEvP6helperIXszscT_Li1EEE\[: \t\n\]" } }
template <class T> void check1( helper<sizeof(static_cast<T>(1))> * ) { } // { dg-warning "mangle" }
// { dg-final { scan-assembler "\n_?_Z6check2IiXadL_Z1iEEEvP6helperIXszccPT_T0_EE\[: \t\n\]" } }
template <class T, T* p> void check2( helper<sizeof(const_cast<T*>(p))> * ) { } // { dg-warning "mangle" }
// { dg-final { scan-assembler "\n_?_Z6check3IiEvP6helperIXszrcPT_Li0EEE\[: \t\n\]" } }
template <class T> void check3( helper<sizeof(reinterpret_cast<T*>(0))> * ) { }
// { dg-final { scan-assembler "_Z6check4I1AXadL_Z1aEEEvP6helperIXszdcPT_T0_EE" } }
// { dg-final { scan-assembler "\n_?_Z6check4I1AXadL_Z1aEEEvP6helperIXszdcPT_T0_EE\[: \t\n\]" } }
template <class T, T* p> void check4( helper<sizeof(dynamic_cast<T*>(p))> * ) { }
struct A{} a;
......
// { dg-do compile { target c++11 } }
// { dg-options "-fabi-version=0" }
// { dg-options "-fabi-version=0 -Wabi=2" }
int i;
// { dg-final { scan-assembler "_Z2f1IiEDTppfp_ET_" } }
template <class T> auto f1 (T t) -> decltype(t++) { return i; }
// { dg-final { scan-assembler "_Z2f2IiEDTpp_fp_ET_" } }
template <class T> auto f2 (T t) -> decltype(++t) { return i; }
template <class T> auto f2 (T t) -> decltype(++t) { return i; } // { dg-warning "mangle" }
// { dg-final { scan-assembler "_Z2f3IiEDTmmfp_ET_" } }
template <class T> auto f3 (T t) -> decltype(t--) { return i; }
// { dg-final { scan-assembler "_Z2f4IiEDTmm_fp_ET_" } }
template <class T> auto f4 (T t) -> decltype(--t) { return i; }
template <class T> auto f4 (T t) -> decltype(--t) { return i; } // { dg-warning "mangle" }
int main()
{
......
// { dg-do compile { target c++11 } }
// { dg-options "-fabi-version=0" }
// { dg-options "-fabi-version=0 -Wabi=2" }
template<typename T> int cmp1(T a, T b);
int cmp2(char a, char b);
template<typename T, int (*cmp)(T, T)> struct A { };
// { dg-final { scan-assembler "_Z1fIcEvR1AIT_X4cmp1EE" } }
template <typename T> void f (A<T,cmp1> &);
// { dg-final { scan-assembler "_Z1fIcEvR1AIT_L_Z4cmp2ccEE" } }
template <typename T> void f (A<T,cmp2> &);
// { dg-final { scan-assembler "\n_?_Z1fIcEvR1AIT_X4cmp1EE\[: \t\n\]" } }
template <typename T> void f (A<T,cmp1> &) {}
// { dg-final { scan-assembler "\n_?_Z1fIcEvR1AIT_L_Z4cmp2ccEE\[: \t\n\]" } }
template <typename T> void f (A<T,cmp2> &) {} // { dg-warning "mangle" }
void g()
{
A<char,cmp1> a;
......
// { dg-do compile { target c++11 } }
// { dg-options "-fabi-version=0" }
// { dg-options "-fabi-version=0 -Wabi=2" }
template<typename T, int (*cmp)(T, T)> struct A { };
struct B {
......@@ -10,9 +10,9 @@ struct B {
// { dg-final { scan-assembler "_ZN1B1gIcEEvR1AIT_XsrS_4cmp1EE" } }
template <typename T> static void g (A<T,B::cmp1> &);
// { dg-final { scan-assembler "_ZN1B1fIcEEvR1AIT_L_ZNS_4cmp2EccEE" } }
template <typename T> static void f (A<T,cmp2> &);
template <typename T> static void f (A<T,cmp2> &); // { dg-warning "mangle" }
// { dg-final { scan-assembler "_ZN1B1gIcEEvR1AIT_L_ZNS_4cmp2EccEE" } }
template <typename T> static void g (A<T,B::cmp2> &);
template <typename T> static void g (A<T,B::cmp2> &); // { dg-warning "mangle" }
};
void g()
......
......@@ -2,10 +2,10 @@
// as a substitution candidate for a function type with function-cv-quals.
// Test for the conformant behavior.
// { dg-options -fabi-version=0 }
// { dg-options "-fabi-version=0 -Wabi=7" }
template <class T, class U> struct A { };
// { dg-final { scan-assembler "_Z1fP1AIKFvvEFvvEE" } }
void f (A<void()const, void()> *){}
// { dg-final { scan-assembler "_Z1gP1AIFvvEKFvvEE" } }
void g (A<void(), void()const> *){}
// { dg-final { scan-assembler "\n_?_Z1fP1AIKFvvEFvvEE\[: \t\n\]" } }
void f (A<void()const, void()> *){} // { dg-warning "mangled name" }
// { dg-final { scan-assembler "\n_?_Z1gP1AIFvvEKFvvEE\[: \t\n\]" } }
void g (A<void(), void()const> *){} // { dg-warning "mangled name" }
......@@ -2,10 +2,10 @@
// as a substitution candidate for a function type with function-cv-quals.
// Test for that for backward compatibility.
// { dg-options -fabi-version=7 }
// { dg-options "-fabi-version=7 -Wabi" }
template <class T, class U> struct A { };
// { dg-final { scan-assembler "_Z1fP1AIKFvvES0_E" } }
void f (A<void()const, void()> *){}
// { dg-final { scan-assembler "_Z1gP1AIFvvEKS0_E" } }
void g (A<void(), void()const> *){}
// { dg-final { scan-assembler "\n_?_Z1fP1AIKFvvES0_E\[: \t\n\]" } }
void f (A<void()const, void()> *){} // { dg-warning "mangle" }
// { dg-final { scan-assembler "\n_?_Z1gP1AIFvvEKS0_E\[: \t\n\]" } }
void g (A<void(), void()const> *){} // { dg-warning "mangle" }
// { dg-do run { target c++11 } }
// { dg-options "-fabi-version=0 -Wabi=2" }
enum class A: short { a1, a2, a3 };
void f(int i, ...)
{
__builtin_va_list ap;
__builtin_va_start (ap, i);
if (__builtin_va_arg (ap, A) != A::a1) __builtin_abort(); // { dg-warning "passed" }
if (__builtin_va_arg (ap, A) != A::a2) __builtin_abort(); // { dg-warning "passed" }
if (__builtin_va_arg (ap, A) != A::a3) __builtin_abort(); // { dg-warning "passed" }
if (__builtin_va_arg (ap, A) != A::a1) __builtin_abort(); // { dg-warning "passed" }
if (__builtin_va_arg (ap, A) != A::a2) __builtin_abort(); // { dg-warning "passed" }
if (__builtin_va_arg (ap, A) != A::a3) __builtin_abort(); // { dg-warning "passed" }
if (__builtin_va_arg (ap, A) != A::a1) __builtin_abort(); // { dg-warning "passed" }
if (__builtin_va_arg (ap, A) != A::a2) __builtin_abort(); // { dg-warning "passed" }
if (__builtin_va_arg (ap, A) != A::a3) __builtin_abort(); // { dg-warning "passed" }
}
int main()
{
f(9, A::a1, A::a2, A::a3, A::a1, A::a2, A::a3, A::a1, A::a2, A::a3); // { dg-warning "passed" }
}
......@@ -10,12 +10,10 @@ enum struct A : short { X };
void foo(int x, ...) {
va_list vl;
__builtin_va_start(vl, x);
enum A t = __builtin_va_arg(vl, enum A); // { dg-warning "promote" }
enum A t = __builtin_va_arg(vl, enum A); // { dg-warning "scoped|promote" }
__builtin_va_end(vl);
}
int main() {
foo(0, A::X); // { dg-warning "will not promote" }
foo(0, A::X); // { dg-warning "scoped" }
}
// { dg-prune-output "note" }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment