[pushed] c++: local fn and generic lambda [PR97219]
Commit Message
When instantiating the op() for a generic lambda, we can no longer do name
lookup inside function scopes enclosing the lambda, so we need to remember
the lookup result from processing the definition of the lambda. So the code
in finish_call_expr to throw away the lookup result and instead look it up
again at instantiation time needs to be adjusted. The approach I take is to
only discard the result if the local extern comes from dependent scope; once
the enclosing function template is instantiated and we're regenerating the
lambda, then we can remember the result of lookup. We also need any default
arguments to be instantiated at that point.
Tested x86_64-pc-linux-gnu, applying to trunk.
PR c++/97219
gcc/cp/ChangeLog:
* name-lookup.cc (dependent_local_decl_p): New.
* cp-tree.h (dependent_local_decl_p): Declare.
* semantics.cc (finish_call_expr): Use it.
* pt.cc (tsubst_arg_types): Also substitute default args
for local externs.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1y/lambda-generic-local-fn1.C: New test.
---
gcc/cp/cp-tree.h | 1 +
gcc/cp/name-lookup.cc | 18 ++++++++++++++++++
gcc/cp/pt.cc | 4 +++-
gcc/cp/semantics.cc | 6 +++---
.../g++.dg/cpp1y/lambda-generic-local-fn1.C | 17 +++++++++++++++++
5 files changed, 42 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-local-fn1.C
base-commit: d4e00ccef6c706a4a4a6446bffaf4111f98d5771
@@ -8243,6 +8243,7 @@ extern tree fold_builtin_source_location (location_t);
/* in name-lookup.cc */
extern tree strip_using_decl (tree);
extern void diagnose_name_conflict (tree, tree);
+extern bool dependent_local_decl_p (tree);
/* Tell the binding oracle what kind of binding we are looking for. */
@@ -8976,4 +8976,22 @@ cp_emit_debug_info_for_using (tree t, tree context)
}
}
+/* True if D is a local declaration in dependent scope. Assumes that it is
+ (part of) the current lookup result for its name. */
+
+bool
+dependent_local_decl_p (tree d)
+{
+ if (!DECL_LOCAL_DECL_P (d))
+ return false;
+
+ cxx_binding *b = IDENTIFIER_BINDING (DECL_NAME (d));
+ cp_binding_level *l = b->scope;
+ while (!l->this_entity)
+ l = l->level_chain;
+ return uses_template_parms (l->this_entity);
+}
+
+
+
#include "gt-cp-name-lookup.h"
@@ -15182,7 +15182,9 @@ tsubst_arg_types (tree arg_types,
/* Except that we do substitute default arguments under tsubst_lambda_expr,
since the new op() won't have any associated template arguments for us
to refer to later. */
- if (lambda_fn_in_template_p (in_decl))
+ if (lambda_fn_in_template_p (in_decl)
+ || (in_decl && TREE_CODE (in_decl) == FUNCTION_DECL
+ && DECL_LOCAL_DECL_P (in_decl)))
default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl,
false/*fn*/, false/*constexpr*/);
@@ -2690,13 +2690,13 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
if (processing_template_decl)
{
- /* If FN is a local extern declaration or set thereof, look them up
- again at instantiation time. */
+ /* If FN is a local extern declaration (or set thereof) in a template,
+ look it up again at instantiation time. */
if (is_overloaded_fn (fn))
{
tree ifn = get_first_fn (fn);
if (TREE_CODE (ifn) == FUNCTION_DECL
- && DECL_LOCAL_DECL_P (ifn))
+ && dependent_local_decl_p (ifn))
orig_fn = DECL_NAME (ifn);
}
new file mode 100644
@@ -0,0 +1,17 @@
+// PR c++/97219
+// { dg-do compile { target c++14 } }
+
+struct B;
+
+template <typename T>
+auto f(T *) {
+ void q(B *, void * = static_cast<T *>(0));
+ return [](auto *p) { q(p); };
+}
+
+void q(void *) = delete;
+
+int main(void) {
+ B *bp = 0;
+ f(bp)(bp);
+}