diff options
author | Nathaniel Shead <nathanieloshead@gmail.com> | 2025-04-29 17:31:55 +1000 |
---|---|---|
committer | Nathaniel Shead <nathanieloshead@gmail.com> | 2025-05-01 09:50:20 +1000 |
commit | 22ccaded63e96e5a42f4e3676dbbb57aa05b36f9 (patch) | |
tree | be5968436bbd57075b1bc594a34888bacd4ea22e /gcc | |
parent | 299d48ff4a34c00a6ef964b694fb9b1312683049 (diff) | |
download | gcc-22ccaded63e96e5a42f4e3676dbbb57aa05b36f9.zip gcc-22ccaded63e96e5a42f4e3676dbbb57aa05b36f9.tar.gz gcc-22ccaded63e96e5a42f4e3676dbbb57aa05b36f9.tar.bz2 |
c++/modules: Catch exposures of TU-local values through inline references [PR119996]
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 <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/module.cc | 27 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/internal-13.C | 33 |
2 files changed, 53 insertions, 7 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index a2e0d6d..7e3b24e 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 0000000..ce1454e --- /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 |