Bootstrapped and regtested on x86_64-pc-linux-gnu (so far just modules.exp), OK for trunk and 15 if full regtest succeeds?
-- >8 -- In r15-9136-g0210bedf481a9f we started erroring for inline variables that exposed TU-local entities in their definition, as such variables would need to have their definitions emitted in importers but would not know about the TU-local entities they referenced. A case we mised was potentially-constant references, which disable streaming of their definitions in make_dependency so as to comply with [expr.const] p9.2. This meant that we didn't see the definition referencing a TU-local entity, leading to nonsensical results. PR c++/119551 PR c++/119996 gcc/cp/ChangeLog: * module.cc (depset::hash::make_dependency): Also mark inline variables referencing TU-local values as exposures here. (depset::hash::finalize_dependencies): Add error message for inline variables. gcc/testsuite/ChangeLog: * g++.dg/modules/internal-13.C: New test. Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> --- gcc/cp/module.cc | 27 +++++++++++++----- gcc/testsuite/g++.dg/modules/internal-13.C | 33 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/internal-13.C diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index a2e0d6d2571..7e3b24e2e42 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -14062,9 +14062,10 @@ depset::hash::make_dependency (tree decl, entity_kind ek) streaming the definition in such cases. */ dep->clear_flag_bit<DB_DEFN_BIT> (); - if (DECL_DECLARED_CONSTEXPR_P (decl)) - /* Also, a constexpr variable initialized to a TU-local - value is an exposure. */ + if (DECL_DECLARED_CONSTEXPR_P (decl) + || DECL_INLINE_VAR_P (decl)) + /* A constexpr variable initialized to a TU-local value, + or an inline value (PR c++/119996), is an exposure. */ dep->set_flag_bit<DB_EXPOSURE_BIT> (); } } @@ -15025,12 +15026,24 @@ depset::hash::finalize_dependencies () break; } - if (!explained && VAR_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl)) + if (!explained + && VAR_P (decl) + && (DECL_DECLARED_CONSTEXPR_P (decl) + || DECL_INLINE_VAR_P (decl))) { auto_diagnostic_group d; - error_at (DECL_SOURCE_LOCATION (decl), - "%qD is declared %<constexpr%> and is initialized to " - "a TU-local value", decl); + if (DECL_DECLARED_CONSTEXPR_P (decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "%qD is declared %<constexpr%> and is initialized to " + "a TU-local value", decl); + else + { + /* This can only occur with references. */ + gcc_checking_assert (TYPE_REF_P (TREE_TYPE (decl))); + error_at (DECL_SOURCE_LOCATION (decl), + "%qD is a reference declared %<inline%> and is " + "constant-initialized to a TU-local value", decl); + } bool informed = is_tu_local_value (decl, DECL_INITIAL (decl), /*explain=*/true); gcc_checking_assert (informed); diff --git a/gcc/testsuite/g++.dg/modules/internal-13.C b/gcc/testsuite/g++.dg/modules/internal-13.C new file mode 100644 index 00000000000..ce1454e17bc --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/internal-13.C @@ -0,0 +1,33 @@ +// PR c++/119996 +// { dg-additional-options "-fmodules" } +// { dg-module-cmi !M } +// Similar to internal-11.C, but for potentially-constant variables. + +export module M; + +static int tu_local = 5; +static int& foo() { return tu_local; } + +// For implementation reasons, we adjust [basic.link] p14.2 to restrict ignored +// exposures to non-inline variables, since for inline variables without +// dynamic initialisation we need to emit their initialiser for importer use. + +int& a = tu_local; // OK +inline int& b = tu_local; // { dg-error "initialized to a TU-local value" } +inline auto& bf = foo; // { dg-error "initialized to a TU-local value" } + +// But dynamic initialisers are fine, importers will just treat them as external. +inline int& c = foo(); // OK + +// For consistency, we follow the same rules with templates, noting that +// we still need to emit definitions with dynamic initializers so we error. +template <typename T> int& d = tu_local; // OK +template <typename T> inline int& e = tu_local; // { dg-error "exposes TU-local entity" } +template <typename T> inline int& f = foo(); // { dg-error "exposes TU-local entity" } +template <typename T> inline auto& ff = foo; // { dg-error "exposes TU-local entity" } + +// Note that non-references are OK, because an integer or enumeration +// value is never TU-local: we fold these expressions early +// (as we should, by [basic.link] p14.4). +static const int const_val = 123; +inline const int potentially_constant = const_val; // OK -- 2.47.0