c++: block-scope externs get an alias [PR95677,PR31775,PR95677]
authorNathan Sidwell <nathan@acm.org>
Wed, 7 Oct 2020 12:46:24 +0000 (05:46 -0700)
committerNathan Sidwell <nathan@acm.org>
Wed, 7 Oct 2020 13:04:14 +0000 (06:04 -0700)
commit4e62aca0e0520e4ed2532f2d8153581190621c1a
treeb7dc85222f79352e26770977dfcc28a0f5b4bf55
parente089e43365f7f2a90979e2316aea25d44823f5a3
c++: block-scope externs get an alias [PR95677,PR31775,PR95677]

This patch improves block-scope extern handling by always injecting a
hidden copy into the enclosing namespace (or using a match already
there).  This hidden copy will be revealed if the user explicitly
declares it later.  We can get from the DECL_LOCAL_DECL_P local extern
to the alias via DECL_LOCAL_DECL_ALIAS.  This fixes several bugs and
removes the kludgy per-function extern_decl_map.  We only do this
pushing for non-dependent local externs -- dependent ones will be
pushed during instantiation.

User code that expected to be able to handle incompatible local
externs in different block-scopes will no longer work.  That code is
ill-formed.  (always was, despite what 31775 claimed).  I had to
adjust a number of testcases that fell into this.

I tried using DECL_VALUE_EXPR, but that didn't work out.  Due to
constexpr requirements we have to do the replacement very late (it
happens in the gimplifier).   Consider:

extern int l[]; // #1
constexpr bool foo ()
{
   extern int l[3]; // this does not complete the type of decl #1
   constexpr int *p = &l[2]; // ok
   return !p;
}

This requirement, coupled with our use of the common folding machinery
makes pr97306 hard to fix, as we end up with an expression containing
the two different decls for 'l', and only the c++ FE knows how to
reconcile those.  I punted on this.

gcc/cp/
* cp-tree.h (struct language_function): Delete extern_decl_map.
(DECL_LOCAL_DECL_ALIAS): New.
* name-lookup.h (is_local_extern): Delete.
* name-lookup.c (set_local_extern_decl_linkage): Replace with ...
(push_local_extern_decl): ... this new function.
(do_pushdecl): Call new function after pushing new decl.  Unhide
hidden non-functions.
(is_local_extern): Delete.
* decl.c (layout_var_decl): Do not allow VLA local externs.
* decl2.c (mark_used): Also mark DECL_LOCAL_DECL_ALIAS. Drop old
local-extern treatment.
* parser.c (cp_parser_oacc_declare): Deal with local extern aliases.
* pt.c (tsubst_expr): Adjust local extern instantiation.
* cp-gimplify.c (cp_genericize_r): Remap DECL_LOCAL_DECLs.
gcc/testsuite/
* g++.dg/cpp0x/lambda/lambda-sfinae1.C: Avoid ill-formed local extern
* g++.dg/init/pr42844.C: Add expected error.
* g++.dg/lookup/extern-redecl1.C: Likewise.
* g++.dg/lookup/koenig15.C: Avoid ill-formed.
* g++.dg/lto/pr95677.C: New.
* g++.dg/other/nested-extern-1.C: Correct expected behabviour.
* g++.dg/other/nested-extern-2.C: Likewise.
* g++.dg/other/nested-extern.cc: Split ...
* g++.dg/other/nested-extern-1.cc: ... here ...
* g++.dg/other/nested-extern-2.cc: ... here.
* g++.dg/template/scope5.C: Avoid ill-formed
* g++.old-deja/g++.law/missed-error2.C: Allow extension.
* g++.old-deja/g++.pt/crash3.C: Add expected error.
21 files changed:
gcc/cp/cp-gimplify.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-sfinae1.C
gcc/testsuite/g++.dg/init/pr42844.C
gcc/testsuite/g++.dg/lookup/extern-redecl1.C
gcc/testsuite/g++.dg/lookup/koenig15.C
gcc/testsuite/g++.dg/lto/pr95677.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/nested-extern-1.C
gcc/testsuite/g++.dg/other/nested-extern-1.cc [new file with mode: 0644]
gcc/testsuite/g++.dg/other/nested-extern-2.C
gcc/testsuite/g++.dg/other/nested-extern-2.cc [new file with mode: 0644]
gcc/testsuite/g++.dg/other/nested-extern.cc [deleted file]
gcc/testsuite/g++.dg/template/scope5.C
gcc/testsuite/g++.old-deja/g++.law/missed-error2.C
gcc/testsuite/g++.old-deja/g++.pt/crash3.C