c++/modules: Forbid exposures of TU-local entities in inline variables [PR119551]
An inline variable has vague linkage, and needs to be conditionally emitted in TUs that reference it. Unfortunately this clashes with [basic.link] p14.2, which says that we ignore the initialisers of all variables (including inline ones), since importers will not have access to the referenced TU-local entities to write the definition. This patch makes such exposures be ill-formed. One case that continues to work is if the exposure is part of the dynamic initialiser of an inline variable; in such cases, the definition has been built as part of the module interface unit anyway, and importers don't need to write it out again, so such exposures are "harmless". PR c++/119551 gcc/cp/ChangeLog: * module.cc (trees_out::write_var_def): Only ignore non-inline variable initializers. gcc/testsuite/ChangeLog: * g++.dg/modules/internal-5_a.C: Add cases that should be ignored. * g++.dg/modules/internal-5_b.C: Test these new cases, and make the testcase more robust. * g++.dg/modules/internal-11.C: New test. * g++.dg/modules/internal-12_a.C: New test. * g++.dg/modules/internal-12_b.C: New test. Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
This commit is contained in:
parent
9aa78d7712
commit
0210bedf48
6 changed files with 68 additions and 4 deletions
|
@ -12679,9 +12679,10 @@ trees_in::read_function_def (tree decl, tree maybe_template)
|
|||
void
|
||||
trees_out::write_var_def (tree decl)
|
||||
{
|
||||
/* The initializer of a variable or variable template is ignored for
|
||||
determining exposures. */
|
||||
auto ovr = make_temp_override (dep_hash->ignore_tu_local, VAR_P (decl));
|
||||
/* The initializer of a non-inline variable or variable template is
|
||||
ignored for determining exposures. */
|
||||
auto ovr = make_temp_override (dep_hash->ignore_tu_local,
|
||||
VAR_P (decl) && !DECL_INLINE_VAR_P (decl));
|
||||
|
||||
tree init = DECL_INITIAL (decl);
|
||||
tree_node (init);
|
||||
|
|
24
gcc/testsuite/g++.dg/modules/internal-11.C
Normal file
24
gcc/testsuite/g++.dg/modules/internal-11.C
Normal file
|
@ -0,0 +1,24 @@
|
|||
// PR c++/119551
|
||||
// { dg-additional-options "-fmodules" }
|
||||
// { dg-module-cmi !M }
|
||||
|
||||
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 "exposes TU-local entity" }
|
||||
|
||||
// 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" }
|
13
gcc/testsuite/g++.dg/modules/internal-12_a.C
Normal file
13
gcc/testsuite/g++.dg/modules/internal-12_a.C
Normal file
|
@ -0,0 +1,13 @@
|
|||
// PR c++/119551
|
||||
// { dg-additional-options "-fmodules" }
|
||||
// { dg-module-cmi M }
|
||||
// Test that emitting variables referencing TU-local entities
|
||||
// builds and runs correctly.
|
||||
|
||||
export module M;
|
||||
|
||||
static int tu_local_var = 5;
|
||||
static int* tu_local_func() { return &tu_local_var; }
|
||||
|
||||
export int* a = &tu_local_var;
|
||||
export inline int* b = tu_local_func();
|
14
gcc/testsuite/g++.dg/modules/internal-12_b.C
Normal file
14
gcc/testsuite/g++.dg/modules/internal-12_b.C
Normal file
|
@ -0,0 +1,14 @@
|
|||
// PR c++/119551
|
||||
// { dg-module-do run }
|
||||
// { dg-additional-options "-fmodules" }
|
||||
|
||||
import M;
|
||||
|
||||
int main() {
|
||||
if (*a != 5)
|
||||
__builtin_abort();
|
||||
if (*b != 5)
|
||||
__builtin_abort();
|
||||
if (a != b)
|
||||
__builtin_abort();
|
||||
}
|
|
@ -37,7 +37,7 @@ template void function_tmpl<ok_inst_tag>();
|
|||
template <> void function_tmpl<ok_inst_tag*>() {}
|
||||
|
||||
|
||||
// The initializer for a variable or variable template
|
||||
// The initializer for a (non-inline) variable or variable template
|
||||
export int var
|
||||
= (internal_t{}, internal_tmpl_t<int>{},
|
||||
internal_ovl(internal_x), internal_tmpl<int>(), 0);
|
||||
|
@ -53,9 +53,15 @@ template <typename T> int var_tmpl<T*> // { dg-warning "refers to TU-local enti
|
|||
template int var_tmpl<ok_inst_tag>;
|
||||
template <> int var_tmpl<ok_inst_tag*> = 0;
|
||||
|
||||
export int* ptr = &internal_x;
|
||||
export template <typename T> int* ptr_tmpl = &internal_x; // { dg-warning "refers to TU-local entity" }
|
||||
|
||||
export int& constant_ref = internal_x;
|
||||
static_assert (&constant_ref == &internal_x);
|
||||
|
||||
// Support exposures in inline vars with dynamic initialisers
|
||||
export inline int dynamic_var = (internal_ovl(internal_x), 0);
|
||||
|
||||
|
||||
// Friend declarations in a class definition
|
||||
export struct klass { // { dg-bogus "TU-local" }
|
||||
|
|
|
@ -15,11 +15,14 @@ int main() {
|
|||
function_tmpl<ok_inst_tag*>();
|
||||
int b = var_tmpl<ok_inst_tag>;
|
||||
int c = var_tmpl<ok_inst_tag*>;
|
||||
int d = *ptr;
|
||||
int e = dynamic_var;
|
||||
|
||||
// But don't ignore exposures in these cases
|
||||
function_tmpl<int>(); // { dg-message "required from here" }
|
||||
int x = var_tmpl<int>; // { dg-message "required from here" }
|
||||
int y = var_tmpl<int*>; // { dg-message "required from here" }
|
||||
int z = *ptr_tmpl<int>; // { dg-message "required from here" }
|
||||
|
||||
// And decls initialized to a TU-local value are not constant here
|
||||
// Unfortunately the error does not currently point to this decl
|
||||
|
@ -27,4 +30,7 @@ int main() {
|
|||
// { dg-error "is not a constant expression" "" { target *-*-* } 0 }
|
||||
}
|
||||
|
||||
// The errors occur in a different file, so we just test that all the
|
||||
// needed "required from here"s are found above.
|
||||
// { dg-error "instantiation exposes TU-local entity" "" { target *-*-* } 0 }
|
||||
// { dg-bogus "required from here" "" { target *-*-* } 0 }
|
||||
|
|
Loading…
Add table
Reference in a new issue