Happy to defer this till GCC16 if preferred. -- >8 --
This fills in a hole left in r15-6378-g9016c5ac94c557 with regards to detection of TU-local lambdas. Now that LAMBDA_EXPR_EXTRA_SCOPE is properly set for most lambdas we can use it to detect lambdas that are TU-local. Lambdas in concept definitions I believe should not be considered TU-local, since they are always unevaluated and should never be emitted. This patch gives these lambdas a mangling scope (though it will never be actually used in name mangling). Namespace-scope alias declarations currently do not have an extra scope set either, so this patch will cause them to be falsely detected as TU-local and error. However, I believe this is better than the alternative, as such lambdas cannot be properly referred to from other TUs now anyway causing strange issues down the line if they were allowed. (Clang makes such lambdas internal linkage.) If in the future we ever correctly give an extra scope to these lambdas they will automatically start working in modules again, but in the meantime they should be avoided (or wrapped in an unnamed namespace). gcc/cp/ChangeLog: * cp-tree.h (finish_concept_definition): Adjust parameters. (start_concept_definition): Declare. * module.cc (depset::hash::is_tu_local_entity): Use LAMBDA_EXPR_EXTRA_SCOPE to detect TU-local lambdas. * parser.cc (cp_parser_concept_definition): Start a lambda scope for concept definitions. * pt.cc (tsubst_lambda_expr): Namespace-scope lambdas may now have extra scope. (finish_concept_definition): Split into... (start_concept_definition): ...this new function. gcc/testsuite/ChangeLog: * g++.dg/modules/internal-4_b.C: Remove XFAILs, add new XFAIL for lambda alias. * g++.dg/modules/lambda-9.h: New test. * g++.dg/modules/lambda-9_a.H: New test. * g++.dg/modules/lambda-9_b.C: New test. Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> --- gcc/cp/cp-tree.h | 3 ++- gcc/cp/module.cc | 7 ++++--- gcc/cp/parser.cc | 14 +++++++++++++- gcc/cp/pt.cc | 21 +++++++++++++++------ gcc/testsuite/g++.dg/modules/internal-4_b.C | 6 +++++- gcc/testsuite/g++.dg/modules/lambda-9.h | 2 ++ gcc/testsuite/g++.dg/modules/lambda-9_a.H | 4 ++++ gcc/testsuite/g++.dg/modules/lambda-9_b.C | 6 ++++++ 8 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/lambda-9.h create mode 100644 gcc/testsuite/g++.dg/modules/lambda-9_a.H create mode 100644 gcc/testsuite/g++.dg/modules/lambda-9_b.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 824b7bb61ae..ec8935243de 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8679,7 +8679,8 @@ struct diagnosing_failed_constraint extern cp_expr finish_constraint_or_expr (location_t, cp_expr, cp_expr); extern cp_expr finish_constraint_and_expr (location_t, cp_expr, cp_expr); extern cp_expr finish_constraint_primary_expr (cp_expr); -extern tree finish_concept_definition (cp_expr, tree, tree); +extern tree start_concept_definition (cp_expr); +extern tree finish_concept_definition (tree, tree, tree); extern tree combine_constraint_expressions (tree, tree); extern tree append_constraint (tree, tree); extern tree get_constraints (const_tree); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 5350e6c4bad..aa0fee1c6cf 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13365,9 +13365,10 @@ depset::hash::is_tu_local_entity (tree decl, bool explain/*=false*/) tree main_decl = TYPE_MAIN_DECL (type); if (!DECL_CLASS_SCOPE_P (main_decl) && !decl_function_context (main_decl) - /* FIXME: Lambdas defined outside initializers. We'll need to more - thoroughly set LAMBDA_TYPE_EXTRA_SCOPE to check this. */ - && !LAMBDA_TYPE_P (type)) + /* LAMBDA_EXPR_EXTRA_SCOPE will be set for lambdas defined in + contexts where they would not be TU-local. */ + && !(LAMBDA_TYPE_P (type) + && LAMBDA_TYPE_EXTRA_SCOPE (type))) { if (explain) inform (loc, "%qT has no name and is not defined within a class, " diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index c851185a86d..f29d2fd0b00 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -31680,8 +31680,20 @@ cp_parser_concept_definition (cp_parser *parser) return error_mark_node; } + tree decl = start_concept_definition (id); + if (decl == error_mark_node) + { + cp_parser_skip_to_end_of_statement (parser); + cp_parser_consume_semicolon_at_end_of_statement (parser); + return error_mark_node; + } + processing_constraint_expression_sentinel parsing_constraint; + + start_lambda_scope (decl); tree init = cp_parser_constraint_expression (parser); + finish_lambda_scope (); + if (init == error_mark_node) cp_parser_skip_to_end_of_statement (parser); @@ -31689,7 +31701,7 @@ cp_parser_concept_definition (cp_parser *parser) but continue as if it were. */ cp_parser_consume_semicolon_at_end_of_statement (parser); - return finish_concept_definition (id, init, attrs); + return finish_concept_definition (decl, init, attrs); } // -------------------------------------------------------------------------- // diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index cba7b97ef70..2c508c04f4d 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -20098,7 +20098,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (LAMBDA_EXPR_EXTRA_SCOPE (t)) record_lambda_scope (r); - else if (TYPE_NAMESPACE_SCOPE_P (TREE_TYPE (t))) + if (TYPE_NAMESPACE_SCOPE_P (TREE_TYPE (t))) /* If we're pushed into another scope (PR105652), fix it. */ TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_NAME (type)) = TYPE_CONTEXT (TREE_TYPE (t)); @@ -29886,12 +29886,10 @@ placeholder_type_constraint_dependent_p (tree t) return false; } -/* Build and return a concept definition. Like other templates, the - CONCEPT_DECL node is wrapped by a TEMPLATE_DECL. This returns the - the TEMPLATE_DECL. */ +/* Prepare and return a concept definition. */ tree -finish_concept_definition (cp_expr id, tree init, tree attrs) +start_concept_definition (cp_expr id) { gcc_assert (identifier_p (id)); gcc_assert (processing_template_decl); @@ -29923,9 +29921,20 @@ finish_concept_definition (cp_expr id, tree init, tree attrs) /* Initially build the concept declaration; its type is bool. */ tree decl = build_lang_decl_loc (loc, CONCEPT_DECL, *id, boolean_type_node); DECL_CONTEXT (decl) = current_scope (); - DECL_INITIAL (decl) = init; TREE_PUBLIC (decl) = true; + return decl; +} + +/* Finish building a concept definition. Like other templates, the + CONCEPT_DECL node is wrapped by a TEMPLATE_DECL. This returns the + the TEMPLATE_DECL. */ + +tree +finish_concept_definition (tree decl, tree init, tree attrs) +{ + DECL_INITIAL (decl) = init; + if (attrs) cplus_decl_attributes (&decl, attrs, 0); diff --git a/gcc/testsuite/g++.dg/modules/internal-4_b.C b/gcc/testsuite/g++.dg/modules/internal-4_b.C index 86bec294fc8..99eda6fbceb 100644 --- a/gcc/testsuite/g++.dg/modules/internal-4_b.C +++ b/gcc/testsuite/g++.dg/modules/internal-4_b.C @@ -80,7 +80,7 @@ void in_function_body() { struct {} x; } // OK auto in_initializer = []{}; // OK #if __cplusplus >= 202002L -decltype([]{}) d_lambda; // { dg-error "exposes TU-local entity" "" { xfail *-*-* } } +decltype([]{}) d_lambda; // { dg-error "exposes TU-local entity" "" { target c++20 } } template <typename T> concept in_constraint_expression = requires { @@ -89,6 +89,10 @@ concept in_constraint_expression = requires { // but I don't think that is intended. []{}; // { dg-bogus "exposes TU-local entity" } }; + +// Again, by the standard this should probably be legal, but currently +// we cannot properly mangle lambdas in namespace-scope aliases. +using alias_lambda = decltype([]{}); // { dg-bogus "exposes TU-local entity" "" { xfail c++20 } } #endif // (But consider unnamed types with names for linkage purposes as having names) diff --git a/gcc/testsuite/g++.dg/modules/lambda-9.h b/gcc/testsuite/g++.dg/modules/lambda-9.h new file mode 100644 index 00000000000..4de9b7861c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-9.h @@ -0,0 +1,2 @@ +template <typename T> +concept C = requires { []{}; }; diff --git a/gcc/testsuite/g++.dg/modules/lambda-9_a.H b/gcc/testsuite/g++.dg/modules/lambda-9_a.H new file mode 100644 index 00000000000..da0fa3b31f2 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-9_a.H @@ -0,0 +1,4 @@ +// { dg-additional-options "-fmodule-header -std=c++20" } +// { dg-module-cmi {} } + +#include "lambda-9.h" diff --git a/gcc/testsuite/g++.dg/modules/lambda-9_b.C b/gcc/testsuite/g++.dg/modules/lambda-9_b.C new file mode 100644 index 00000000000..6f2186421f7 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lambda-9_b.C @@ -0,0 +1,6 @@ +// { dg-additional-options "-fmodules -std=c++20 -fno-module-lazy" } + +#include "lambda-9.h" +import "lambda-9_a.H"; + +static_assert(C<int>); -- 2.47.0