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.
CWG2988 suggests that lambdas in concept definitions 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).
PR c++/116568
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 XFAIL, add lambda alias
testcase.
* 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 <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
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);
gcc_checking_assert (TREE_CODE (scope) == VAR_DECL
|| TREE_CODE (scope) == FIELD_DECL
|| TREE_CODE (scope) == PARM_DECL
- || TREE_CODE (scope) == TYPE_DECL);
+ || TREE_CODE (scope) == TYPE_DECL
+ || TREE_CODE (scope) == CONCEPT_DECL);
/* Lambdas attached to fields are keyed to the class. */
if (TREE_CODE (scope) == FIELD_DECL)
scope = TYPE_NAME (DECL_CONTEXT (scope));
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, "
return;
/* We only need to deal with lambdas attached to var, field,
- parm, or type decls. */
+ parm, type, or concept decls. */
if (TREE_CODE (ctx) != VAR_DECL
&& TREE_CODE (ctx) != FIELD_DECL
&& TREE_CODE (ctx) != PARM_DECL
- && TREE_CODE (ctx) != TYPE_DECL)
+ && TREE_CODE (ctx) != TYPE_DECL
+ && TREE_CODE (ctx) != CONCEPT_DECL)
return;
/* For fields, key it to the containing type to handle deduplication
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);
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);
}
// -------------------------------------------------------------------------- //
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));
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);
/* 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);
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 } }
+using alias_lambda = decltype([]{}); // { dg-error "exposes TU-local entity" "" { target c++20 } }
template <typename T>
concept in_constraint_expression = requires {
// Strictly by the standard this is currently ill-formed
// (this is a constraint-expression not an initializer)
- // but I don't think that is intended.
+ // but I don't think that is intended; see CWG2988.
[]{}; // { dg-bogus "exposes TU-local entity" }
};
#endif
--- /dev/null
+// CWG2988
+template <typename T>
+concept C = requires { []{}; };
--- /dev/null
+// { dg-additional-options "-fmodule-header -std=c++20" }
+// { dg-module-cmi {} }
+
+#include "lambda-9.h"
--- /dev/null
+// { dg-additional-options "-fmodules -std=c++20 -fno-module-lazy" }
+
+#include "lambda-9.h"
+import "lambda-9_a.H";
+
+static_assert(C<int>);