[Dropping Richard, as I don't think his input is necessary further]
Hi Rainer,
here are two patches, to be applied in sequence (replacing earlier
versions of the patch).
The first is merely a testsuite correction of the earlier patch to
inhibit the cxa_atexit-specific tests where it matters. (I don't think
it matters in the ABI ones, if the library does not provide them, we
won't hit a declaration that could differ)
The second fixes the atexit issue (and array entity with cxa_atexit) you
encountered on solaris 11.3.
With these two patches I could build the xtreme-header-2_a.ii you
provided on an i386-solaris2.11 xcompiler (I can only compile there, not
got a complete runtime to run the tests).
Please let me know how these behave, thanks.
patch 3a:
c++: cross-module __cxa_atexit use [PR 98531]
The compiler's use of lazily-declared library functions must insert
said functions into a symbol table, so that they can be correctly
merged across TUs at the module-level. We have too many different
ways of declaring such library functions. This fixes __cxa_atexit (or
its system-specific variations), pushing (or merging) the decl into
the appropriate namespace. Because we're pushing a lazy builtin,
check_redeclaration_exception_specification needed a tweak to allow a
such a builtin's eh spec to differ from what the user may have already
declared. (I suspect no all headers declare atexit as noexcept.)
We can't test the -fno-use-cxa-atexit path with modules, as that
requires a followup patch to a closely related piece (which also
affects cxa_atexit targets in other circumstances).
PR c++/98531
gcc/cp/
* cp-tree.h (push_abi_namespace, pop_abi_namespace): Declare.
* decl.c (push_abi_namespace, pop_abi_namespace): Moved
from rtti.c, add default namespace arg.
(check_redeclaration_exception_specification): Allow a lazy
builtin's eh spec to differ from an lready-declared user
declaration.
(declare_global_var): Use push/pop_abi_namespace.
(get_atexit_node): Push the fndecl into a namespace.
* rtti.c (push_abi_namespace, pop_abi_namespace): Moved to
decl.c.
gcc/testsuite/
* g++.dg/modules/pr98531-1.h: New.
* g++.dg/modules/pr98531-1_a.H: New.
* g++.dg/modules/pr98531-1_b.C: New.
* g++.dg/abi/pr98531-1.C: New.
* g++.dg/abi/pr98531-2.C: New.
* g++.dg/abi/pr98531-3.C: New.
* g++.dg/abi/pr98531-4.C: New.
patch 3b:
c++: cleanup function name [PR 98531]
The next piece of 98531 is that in some cases we need to create a
cleanup function to do the work (when the object is an array, or we're
using regular atexit). We were not pushing that function's decl
anywhere (not giving it a context) so streaming it failed.
This is a partial fix. You'll notice we're naming these from a per-TU
counter. I've captured that in PR98893.
gcc/cp/
* decl.c (start_cleanup_fn): Push function into
namespace.
gcc/testsuite/
* g++.dg/modules/pr98531-2.h: New.
* g++.dg/modules/pr98531-2_a.H: New.
* g++.dg/modules/pr98531-2_b.C: New.
* g++.dg/modules/pr98531-3.h: New.
* g++.dg/modules/pr98531-3_a.H: New.
* g++.dg/modules/pr98531-3_b.C: New.
--
Nathan Sidwell
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f31319904eb..bb06b6e44a9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -193,7 +193,9 @@ enum cp_tree_index
CPTI_MODULE_HWM,
/* Nodes after here change during compilation, or should not be in
- the module's global tree table. */
+ the module's global tree table. Such nodes must be locatable
+ via name lookup or type-construction, as those are the only
+ cross-TU matching capabilities remaining. */
/* We must find these via the global namespace. */
CPTI_STD,
@@ -6622,6 +6624,9 @@ extern tree make_typename_type (tree, tree, enum tag_types, tsubst_flags_t);
extern tree build_typename_type (tree, tree, tree, tag_types);
extern tree make_unbound_class_template (tree, tree, tree, tsubst_flags_t);
extern tree make_unbound_class_template_raw (tree, tree, tree);
+extern unsigned push_abi_namespace (tree node = abi_node);
+extern void pop_abi_namespace (unsigned flags,
+ tree node = abi_node);
extern tree build_library_fn_ptr (const char *, tree, int);
extern tree build_cp_library_fn_ptr (const char *, tree, int);
extern tree push_library_fn (tree, tree, tree, int);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 1a114a2e2d0..edabeb989b3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1209,7 +1209,8 @@ check_redeclaration_exception_specification (tree new_decl,
all declarations, including the definition and an explicit
specialization, of that function shall have an
exception-specification with the same set of type-ids. */
- if (! DECL_IS_UNDECLARED_BUILTIN (old_decl)
+ if (!DECL_IS_UNDECLARED_BUILTIN (old_decl)
+ && !DECL_IS_UNDECLARED_BUILTIN (new_decl)
&& !comp_except_specs (new_exceptions, old_exceptions, ce_normal))
{
const char *const msg
@@ -4696,6 +4697,30 @@ cxx_init_decl_processing (void)
using_eh_for_cleanups ();
}
+/* Enter an abi node in global-module context. returns a cookie to
+ give to pop_abi_namespace. */
+
+unsigned
+push_abi_namespace (tree node)
+{
+ push_nested_namespace (node);
+ push_visibility ("default", 2);
+ unsigned flags = module_kind;
+ module_kind = 0;
+ return flags;
+}
+
+/* Pop an abi namespace, FLAGS is the cookie push_abi_namespace gave
+ you. */
+
+void
+pop_abi_namespace (unsigned flags, tree node)
+{
+ module_kind = flags;
+ pop_visibility (2);
+ pop_nested_namespace (node);
+}
+
/* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give
the decl, LOC is the location to give the decl, NAME is the
initialization string and TYPE_DEP indicates whether NAME depended
@@ -8668,21 +8693,19 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
static tree
declare_global_var (tree name, tree type)
{
- tree decl;
-
- push_to_top_level ();
- decl = build_decl (input_location, VAR_DECL, name, type);
+ auto cookie = push_abi_namespace (global_namespace);
+ tree decl = build_decl (input_location, VAR_DECL, name, type);
TREE_PUBLIC (decl) = 1;
DECL_EXTERNAL (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
- DECL_CONTEXT (decl) = FROB_CONTEXT (global_namespace);
+ DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
/* If the user has explicitly declared this variable (perhaps
because the code we are compiling is part of a low-level runtime
library), then it is possible that our declaration will be merged
with theirs by pushdecl. */
decl = pushdecl (decl);
cp_finish_decl (decl, NULL_TREE, false, NULL_TREE, 0);
- pop_from_top_level ();
+ pop_abi_namespace (cookie, global_namespace);
return decl;
}
@@ -8727,6 +8750,7 @@ get_atexit_node (void)
tree fn_ptr_type;
const char *name;
bool use_aeabi_atexit;
+ tree ctx = global_namespace;
if (atexit_node)
return atexit_node;
@@ -8761,10 +8785,23 @@ get_atexit_node (void)
fn_type = build_function_type_list (integer_type_node,
argtype0, argtype1, argtype2,
NULL_TREE);
+ /* ... which needs noexcept. */
+ fn_type = build_exception_variant (fn_type, noexcept_true_spec);
if (use_aeabi_atexit)
- name = "__aeabi_atexit";
+ {
+ name = "__aeabi_atexit";
+ push_to_top_level ();
+ int n = push_namespace (get_identifier ("__aeabiv1"), false);
+ ctx = current_namespace;
+ while (n--)
+ pop_namespace ();
+ pop_from_top_level ();
+ }
else
- name = "__cxa_atexit";
+ {
+ name = "__cxa_atexit";
+ ctx = abi_node;
+ }
}
else
{
@@ -8778,12 +8815,23 @@ get_atexit_node (void)
/* Build the final atexit type. */
fn_type = build_function_type_list (integer_type_node,
fn_ptr_type, NULL_TREE);
+ /* ... which needs noexcept. */
+ fn_type = build_exception_variant (fn_type, noexcept_true_spec);
name = "atexit";
}
/* Now, build the function declaration. */
push_lang_context (lang_name_c);
+ auto cookie = push_abi_namespace (ctx);
atexit_fndecl = build_library_fn_ptr (name, fn_type, ECF_LEAF | ECF_NOTHROW);
+ DECL_CONTEXT (atexit_fndecl) = FROB_CONTEXT (current_namespace);
+ /* Install as hidden builtin so we're (a) more relaxed about
+ exception spec matching and (b) will not give a confusing location
+ in diagnostic and (c) won't magically appear in user-visible name
+ lookups. */
+ DECL_SOURCE_LOCATION (atexit_fndecl) = BUILTINS_LOCATION;
+ atexit_fndecl = pushdecl (atexit_fndecl, /*hiding=*/true);
+ pop_abi_namespace (cookie, ctx);
mark_used (atexit_fndecl);
pop_lang_context ();
atexit_node = decay_conversion (atexit_fndecl, tf_warning_or_error);
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index d3cb9ad4425..b41d95469c6 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -143,24 +143,6 @@ static bool typeinfo_in_lib_p (tree);
static int doing_runtime = 0;
-static unsigned
-push_abi_namespace (void)
-{
- push_nested_namespace (abi_node);
- push_visibility ("default", 2);
- unsigned flags = module_kind;
- module_kind = 0;
- return flags;
-}
-
-static void
-pop_abi_namespace (unsigned flags)
-{
- module_kind = flags;
- pop_visibility (2);
- pop_nested_namespace (abi_node);
-}
-
/* Declare language defined type_info type and a pointer to const
type_info. This is incomplete here, and will be completed when
the user #includes <typeinfo>. There are language defined
diff --git a/gcc/testsuite/g++.dg/abi/pr98531-1.C b/gcc/testsuite/g++.dg/abi/pr98531-1.C
new file mode 100644
index 00000000000..dc9ad99fccf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr98531-1.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+// PR 98531 Making __cxa_atexit (or atexit) more visible means it
+// must be consistent with the std library's declarations
+
+struct C
+{
+ ~C () noexcept;
+ C () noexcept;
+};
+
+C &frob ()
+{
+ static C c; // Requires atexit functionality
+
+ return c;
+}
+
+// Make sure this agrees with what we introduced above
+#include <cxxabi.h>
+#include <cstdlib>
diff --git a/gcc/testsuite/g++.dg/abi/pr98531-2.C b/gcc/testsuite/g++.dg/abi/pr98531-2.C
new file mode 100644
index 00000000000..4bdf9b9ca0f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr98531-2.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+// PR 98531 Making __cxa_atexit (or atexit) more visible means it
+// must be consistent with the std library's declarations
+
+// Make sure this agrees with what we introduce below
+#include <cxxabi.h>
+#include <cstdlib>
+
+struct C
+{
+ ~C () noexcept;
+ C () noexcept;
+};
+
+C &frob ()
+{
+ static C c; // Requires atexit functionality
+
+ return c;
+}
diff --git a/gcc/testsuite/g++.dg/abi/pr98531-3.C b/gcc/testsuite/g++.dg/abi/pr98531-3.C
new file mode 100644
index 00000000000..de6129dc808
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr98531-3.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -fno-use-cxa-atexit }
+// PR 98531 Making __cxa_atexit (or atexit) more visible means it
+// must be consistent with the std library's declarations
+
+extern "C" int atexit (void (*) (void));
+
+struct C
+{
+ ~C () noexcept;
+ C () noexcept;
+};
+
+C &frob ()
+{
+ static C c; // Requires atexit functionality
+
+ return c;
+}
+
+
diff --git a/gcc/testsuite/g++.dg/abi/pr98531-4.C b/gcc/testsuite/g++.dg/abi/pr98531-4.C
new file mode 100644
index 00000000000..ec64ee07a17
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr98531-4.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -fno-use-cxa-atexit }
+// PR 98531 Making __cxa_atexit (or atexit) more visible means it
+// must be consistent with the std library's declarations
+
+struct C
+{
+ ~C () noexcept;
+ C () noexcept;
+};
+
+C &frob ()
+{
+ static C c; // Requires atexit functionality
+
+ return c;
+}
+
+extern "C" int atexit (void (*) (void));
diff --git a/gcc/testsuite/g++.dg/modules/pr98531-1.h b/gcc/testsuite/g++.dg/modules/pr98531-1.h
new file mode 100644
index 00000000000..62d4c1d1f90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr98531-1.h
@@ -0,0 +1,13 @@
+
+struct __waiters
+{
+ __waiters() noexcept;
+ ~__waiters () noexcept;
+
+ static __waiters &_S_for()
+ {
+ static __waiters w;
+
+ return w;
+ }
+};
diff --git a/gcc/testsuite/g++.dg/modules/pr98531-1_a.H b/gcc/testsuite/g++.dg/modules/pr98531-1_a.H
new file mode 100644
index 00000000000..cbd2090b4c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr98531-1_a.H
@@ -0,0 +1,6 @@
+// { dg-require-cxa-atexit "" }
+// { dg-additional-options "-fmodule-header -fuse-cxa-atexit" }
+// PR c++ 98531 no-context __cxa_atexit
+// { dg-module-cmi {} }
+
+#include "pr98531-1.h"
diff --git a/gcc/testsuite/g++.dg/modules/pr98531-1_b.C b/gcc/testsuite/g++.dg/modules/pr98531-1_b.C
new file mode 100644
index 00000000000..096cdc8c08a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr98531-1_b.C
@@ -0,0 +1,5 @@
+// { dg-require-cxa-atexit "" }
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fuse-cxa-atexit" }
+
+#include "pr98531-1.h"
+import "pr98531-1_a.H";
diff --git c/gcc/cp/decl.c w/gcc/cp/decl.c
index edabeb989b3..f4ded1c706b 100644
--- c/gcc/cp/decl.c
+++ w/gcc/cp/decl.c
@@ -8890,10 +8890,6 @@ static tree
start_cleanup_fn (void)
{
char name[32];
- tree fntype;
- tree fndecl;
- bool use_cxa_atexit = flag_use_cxa_atexit
- && !targetm.cxx.use_atexit_for_cxa_atexit ();
push_to_top_level ();
@@ -8903,8 +8899,9 @@ start_cleanup_fn (void)
/* Build the name of the function. */
sprintf (name, "__tcf_%d", start_cleanup_cnt++);
/* Build the function declaration. */
- fntype = TREE_TYPE (get_atexit_fn_ptr_type ());
- fndecl = build_lang_decl (FUNCTION_DECL, get_identifier (name), fntype);
+ tree fntype = TREE_TYPE (get_atexit_fn_ptr_type ());
+ tree fndecl = build_lang_decl (FUNCTION_DECL, get_identifier (name), fntype);
+ DECL_CONTEXT (fndecl) = FROB_CONTEXT (current_namespace);
/* It's a function with internal linkage, generated by the
compiler. */
TREE_PUBLIC (fndecl) = 0;
@@ -8915,16 +8912,16 @@ start_cleanup_fn (void)
emissions this way. */
DECL_DECLARED_INLINE_P (fndecl) = 1;
DECL_INTERFACE_KNOWN (fndecl) = 1;
- /* Build the parameter. */
- if (use_cxa_atexit)
+ if (flag_use_cxa_atexit && !targetm.cxx.use_atexit_for_cxa_atexit ())
{
+ /* Build the parameter. */
tree parmdecl = cp_build_parm_decl (fndecl, NULL_TREE, ptr_type_node);
TREE_USED (parmdecl) = 1;
DECL_READ_P (parmdecl) = 1;
DECL_ARGUMENTS (fndecl) = parmdecl;
}
- pushdecl (fndecl);
+ fndecl = pushdecl (fndecl, /*hidden=*/true);
start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED);
pop_lang_context ();
diff --git c/gcc/testsuite/g++.dg/modules/pr98531-2.h w/gcc/testsuite/g++.dg/modules/pr98531-2.h
new file mode 100644
index 00000000000..62d4c1d1f90
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr98531-2.h
@@ -0,0 +1,13 @@
+
+struct __waiters
+{
+ __waiters() noexcept;
+ ~__waiters () noexcept;
+
+ static __waiters &_S_for()
+ {
+ static __waiters w;
+
+ return w;
+ }
+};
diff --git c/gcc/testsuite/g++.dg/modules/pr98531-2_a.H w/gcc/testsuite/g++.dg/modules/pr98531-2_a.H
new file mode 100644
index 00000000000..757d68af297
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr98531-2_a.H
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodule-header -fno-use-cxa-atexit" }
+// PR c++ 98531 no-context __cxa_atexit
+// { dg-module-cmi {} }
+
+#include "pr98531-2.h"
diff --git c/gcc/testsuite/g++.dg/modules/pr98531-2_b.C w/gcc/testsuite/g++.dg/modules/pr98531-2_b.C
new file mode 100644
index 00000000000..b5fa4492e8a
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr98531-2_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy -fno-use-cxa-atexit" }
+
+#include "pr98531-2.h"
+import "pr98531-2_a.H";
diff --git c/gcc/testsuite/g++.dg/modules/pr98531-3.h w/gcc/testsuite/g++.dg/modules/pr98531-3.h
new file mode 100644
index 00000000000..a1a2f8a2e02
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr98531-3.h
@@ -0,0 +1,13 @@
+
+struct __waiters
+{
+ __waiters() noexcept;
+ ~__waiters () noexcept;
+
+ static __waiters &_S_for()
+ {
+ static __waiters w[2];
+
+ return w[0];
+ }
+};
diff --git c/gcc/testsuite/g++.dg/modules/pr98531-3_a.H w/gcc/testsuite/g++.dg/modules/pr98531-3_a.H
new file mode 100644
index 00000000000..1c6267ae376
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr98531-3_a.H
@@ -0,0 +1,5 @@
+// { dg-additional-options -fmodule-header }
+// PR c++ 98531 no-context __tcf_0
+// { dg-module-cmi {} }
+
+#include "pr98531-3.h"
diff --git c/gcc/testsuite/g++.dg/modules/pr98531-3_b.C w/gcc/testsuite/g++.dg/modules/pr98531-3_b.C
new file mode 100644
index 00000000000..7e3e16d34fd
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr98531-3_b.C
@@ -0,0 +1,4 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+#include "pr98531-3.h"
+import "pr98531-3_a.H";