aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2006-06-14 17:44:36 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2006-06-14 17:44:36 +0000
commitace4831de98f6caf6450cf57528f5a15eec6c9e1 (patch)
tree222304b644d89c1c1cd28e8b5be65b80e93e6bf3
parentc3b11a40d026d3b25038f3300180e1b58a9b3b99 (diff)
downloadgcc-ace4831de98f6caf6450cf57528f5a15eec6c9e1.zip
gcc-ace4831de98f6caf6450cf57528f5a15eec6c9e1.tar.gz
gcc-ace4831de98f6caf6450cf57528f5a15eec6c9e1.tar.bz2
re PR c++/27227 (rejects valid code with some extern "C")
PR c++/27227 * decl.c (decls_match): Allow an extern "C" variable declarations from different namespaces to match. (duplicate_decls): Disallow redeclaring a variable with a different linkage specification. PR c++/27227 * g++.dg/lookup/linkage1.C: New test. * g++.dg/lookup/linkage2.C: Likewise. From-SVN: r114647
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/decl.c46
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/lookup/linkage1.C4
-rw-r--r--gcc/testsuite/g++.dg/lookup/linkage2.C7
5 files changed, 65 insertions, 6 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 129f5df..b7eee4f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2006-06-13 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/27227
+ * decl.c (decls_match): Allow an extern "C" variable declarations
+ from different namespaces to match.
+ (duplicate_decls): Disallow redeclaring a variable with a
+ different linkage specification.
+
2006-06-13 Jakub Jelinek <jakub@redhat.com>
PR middle-end/27793
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 206fced..2d92fe3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -999,7 +999,13 @@ decls_match (tree newdecl, tree olddecl)
/* Need to check scope for variable declaration (VAR_DECL).
For typedef (TYPE_DECL), scope is ignored. */
if (TREE_CODE (newdecl) == VAR_DECL
- && CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl))
+ && CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl)
+ /* [dcl.link]
+ Two declarations for an object with C language linkage
+ with the same name (ignoring the namespace that qualify
+ it) that appear in different namespace scopes refer to
+ the same object. */
+ && !(DECL_EXTERN_C_P (olddecl) && DECL_EXTERN_C_P (newdecl)))
return 0;
if (TREE_TYPE (newdecl) == error_mark_node)
@@ -1453,14 +1459,42 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
warning (0, "prototype for %q+#D", newdecl);
warning (0, "%Jfollows non-prototype definition here", olddecl);
}
- else if (TREE_CODE (olddecl) == FUNCTION_DECL
+ else if ((TREE_CODE (olddecl) == FUNCTION_DECL
+ || TREE_CODE (olddecl) == VAR_DECL)
&& DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl))
{
- /* extern "C" int foo ();
- int foo () { bar (); }
- is OK. */
+ /* [dcl.link]
+ If two declarations of the same function or object
+ specify different linkage-specifications ..., the program
+ is ill-formed.... Except for functions with C++ linkage,
+ a function declaration without a linkage specification
+ shall not precede the first linkage specification for
+ that function. A function can be declared without a
+ linkage specification after an explicit linkage
+ specification has been seen; the linkage explicitly
+ specified in the earlier declaration is not affected by
+ such a function declaration.
+
+ DR 563 raises the question why the restrictions on
+ functions should not also apply to objects. Older
+ versions of G++ silently ignore the linkage-specification
+ for this example:
+
+ namespace N {
+ extern int i;
+ extern "C" int i;
+ }
+
+ which is clearly wrong. Therefore, we now treat objects
+ like functions. */
if (current_lang_depth () == 0)
- SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl));
+ {
+ /* There is no explicit linkage-specification, so we use
+ the linkage from the previous declaration. */
+ if (!DECL_LANG_SPECIFIC (newdecl))
+ retrofit_lang_decl (newdecl);
+ SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl));
+ }
else
{
error ("previous declaration of %q+#D with %qL linkage",
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8b79955..2760477 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2006-06-14 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/27227
+ * g++.dg/lookup/linkage1.C: New test.
+ * g++.dg/lookup/linkage2.C: Likewise.
+
2006-06-14 Andreas Krebbel <krebbel1@de.ibm.com>
PR middle-end/27959
diff --git a/gcc/testsuite/g++.dg/lookup/linkage1.C b/gcc/testsuite/g++.dg/lookup/linkage1.C
new file mode 100644
index 0000000..6f6bdfd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/linkage1.C
@@ -0,0 +1,4 @@
+// DR 563
+
+extern int i; // { dg-error "linkage" }
+extern "C" int i; // { dg-error "linkage" }
diff --git a/gcc/testsuite/g++.dg/lookup/linkage2.C b/gcc/testsuite/g++.dg/lookup/linkage2.C
new file mode 100644
index 0000000..994264d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/linkage2.C
@@ -0,0 +1,7 @@
+// PR c++/27227
+
+namespace x {
+ extern "C" const int y;
+}
+using x::y;
+extern "C" int const y=0;