aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-04-13 16:42:25 -0400
committerJason Merrill <jason@redhat.com>2022-04-13 20:24:36 -0400
commit1824da60663b4532199ecd051d8ba6da8995821d (patch)
tree52bc8b3bc1d5569d87d6895f6d7af0da58d8c59e
parentd4e00ccef6c706a4a4a6446bffaf4111f98d5771 (diff)
downloadgcc-1824da60663b4532199ecd051d8ba6da8995821d.zip
gcc-1824da60663b4532199ecd051d8ba6da8995821d.tar.gz
gcc-1824da60663b4532199ecd051d8ba6da8995821d.tar.bz2
c++: local fn and generic lambda [PR97219]
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. 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.
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/name-lookup.cc18
-rw-r--r--gcc/cp/pt.cc4
-rw-r--r--gcc/cp/semantics.cc6
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-local-fn1.C17
5 files changed, 42 insertions, 4 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2f71885..e9a3d09 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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. */
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 118da09..7b0638d 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -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"
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 63c0870..adc863d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -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*/);
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f5ec808..f08c0b6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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);
}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-local-fn1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-local-fn1.C
new file mode 100644
index 0000000..06919c5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-local-fn1.C
@@ -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);
+}