aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2020-10-20 12:17:21 -0700
committerNathan Sidwell <nathan@acm.org>2020-10-20 12:20:10 -0700
commit15b8e2af42168a41636186c53d1e833302195601 (patch)
treeafbc7517b3692877b3cda065eb72f1be29f45702
parentd962ef77dadea87b2bf30487bddda00c350bf0ba (diff)
downloadgcc-15b8e2af42168a41636186c53d1e833302195601.zip
gcc-15b8e2af42168a41636186c53d1e833302195601.tar.gz
gcc-15b8e2af42168a41636186c53d1e833302195601.tar.bz2
c++: block-scope extern decl with default args
In adding the DECL_LOCAL_DECL handling, I'd forgotten that the parm-decls also need cloning -- and resetting of their DECL_CONTEXT. Also, any default args need droping when adding an alias, as those are not propagated. The std's not totally clear on this latter point when there's no exising namespace decl, but that seems like the right thing and is what clang does. gcc/cp/ * name-lookup.c (push_local_extern_decl_alias): Reconstextualize alias' parm decls. Drop any default args. gcc/testsuite/ * g++.dg/lookup/local-extern.C: New.
-rw-r--r--gcc/cp/name-lookup.c46
-rw-r--r--gcc/testsuite/g++.dg/lookup/local-extern.C13
2 files changed, 59 insertions, 0 deletions
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index e951fb7..4637427 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -2969,6 +2969,52 @@ push_local_extern_decl_alias (tree decl)
{
/* No existing namespace-scope decl. Make one. */
alias = copy_decl (decl);
+ if (TREE_CODE (alias) == FUNCTION_DECL)
+ {
+ /* Recontextualize the parms. */
+ for (tree *chain = &DECL_ARGUMENTS (alias);
+ *chain; chain = &DECL_CHAIN (*chain))
+ {
+ *chain = copy_decl (*chain);
+ DECL_CONTEXT (*chain) = alias;
+ }
+
+ tree type = TREE_TYPE (alias);
+ for (tree args = TYPE_ARG_TYPES (type);
+ args; args = TREE_CHAIN (args))
+ if (TREE_PURPOSE (args))
+ {
+ /* There are default args. Lose them. */
+ tree nargs = NULL_TREE;
+ tree *chain = &nargs;
+ for (args = TYPE_ARG_TYPES (type);
+ args; args = TREE_CHAIN (args))
+ if (args == void_list_node)
+ {
+ *chain = args;
+ break;
+ }
+ else
+ {
+ *chain
+ = build_tree_list (NULL_TREE, TREE_VALUE (args));
+ chain = &TREE_CHAIN (*chain);
+ }
+
+ tree fn_type = build_function_type (TREE_TYPE (type), nargs);
+
+ fn_type = apply_memfn_quals
+ (fn_type, type_memfn_quals (type));
+
+ fn_type = build_cp_fntype_variant
+ (fn_type, type_memfn_rqual (type),
+ TYPE_RAISES_EXCEPTIONS (type),
+ TYPE_HAS_LATE_RETURN_TYPE (type));
+
+ TREE_TYPE (alias) = fn_type;
+ break;
+ }
+ }
/* This is the real thing. */
DECL_LOCAL_DECL_P (alias) = false;
diff --git a/gcc/testsuite/g++.dg/lookup/local-extern.C b/gcc/testsuite/g++.dg/lookup/local-extern.C
new file mode 100644
index 0000000..1d6d861
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/local-extern.C
@@ -0,0 +1,13 @@
+int foo ()
+{
+ extern int baz (int i = 5);
+ return baz ();
+}
+
+int baz (int i = 0);
+
+int bar ()
+{
+ extern int baz (int i = 6);
+ return baz ();
+}