Implement DR 757...
authorJason Merrill <jason@redhat.com>
Mon, 10 Aug 2009 20:47:55 +0000 (16:47 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 10 Aug 2009 20:47:55 +0000 (16:47 -0400)
Implement DR 757: It's OK for a decl to use a type without linkage
so long as the decl is defined in the current translation unit.
* decl2.c (no_linkage_decls): New vector.
(mark_used): Add decls that use types with no linkage.
(cp_write_global_declarations): Check that they are defined.
(decl_defined_p, no_linkage_error): New fns.
* cp-tree.h (DECL_NO_LINKAGE_CHECKED): New macro.
(struct lang_decl_base): Add flag.
* decl.c (grokfndecl): Don't check type linkage.
(grokvardecl): If the type has no linkage, just make sure
DECL_LANG_SPECIFIC is set.
* pt.c (check_instantiated_arg): Don't check type linkage.
* name-lookup.c (is_local_extern): New fn.
* name-lookup.h: Declare it.

From-SVN: r150634

19 files changed:
gcc/cp/ChangeLog
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/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/anon-struct4.C
gcc/testsuite/g++.dg/lookup/anon2.C
gcc/testsuite/g++.dg/other/anon3.C
gcc/testsuite/g++.dg/other/linkage2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/arg2.C
gcc/testsuite/g++.dg/template/local4.C
gcc/testsuite/g++.old-deja/g++.law/operators32.C
gcc/testsuite/g++.old-deja/g++.other/anon9.C
gcc/testsuite/g++.old-deja/g++.other/linkage1.C
gcc/testsuite/g++.old-deja/g++.other/linkage2.C
gcc/testsuite/g++.old-deja/g++.pt/enum6.C

index a7cc6b1..dc9f1ca 100644 (file)
@@ -1,3 +1,20 @@
+2009-08-10  Jason Merrill  <jason@redhat.com>
+
+       Implement DR 757: It's OK for a decl to use a type without linkage
+       so long as the decl is defined in the current translation unit.
+       * decl2.c (no_linkage_decls): New vector.
+       (mark_used): Add decls that use types with no linkage.
+       (cp_write_global_declarations): Check that they are defined.
+       (decl_defined_p, no_linkage_error): New fns.
+       * cp-tree.h (DECL_NO_LINKAGE_CHECKED): New macro.
+       (struct lang_decl_base): Add flag.
+       * decl.c (grokfndecl): Don't check type linkage.
+       (grokvardecl): If the type has no linkage, just make sure
+       DECL_LANG_SPECIFIC is set.
+       * pt.c (check_instantiated_arg): Don't check type linkage.
+       * name-lookup.c (is_local_extern): New fn.
+       * name-lookup.h: Declare it.
+
 2009-08-05  Jason Merrill  <jason@redhat.com>
 
        PR c++/40948
index c507ac8..ae39110 100644 (file)
@@ -1579,8 +1579,9 @@ struct GTY(()) lang_decl_base {
   unsigned anticipated_p : 1;             /* fn or type */
   unsigned friend_attr : 1;               /* fn or type */
   unsigned template_conv_p : 1;                   /* template only? */
+  unsigned no_linkage_checked : 1;         /* var or fn */
   unsigned u2sel : 1;
-  /* 2 spare bits */
+  /* 1 spare bit */
 };
 
 /* True for DECL codes which have template info and access.  */
@@ -1982,6 +1983,14 @@ struct GTY(()) lang_decl {
   (DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL)) \
    ->u.base.initialized_in_class)
 
+/* Nonzero if we've checked whether DECL uses types without linkage in a
+   potentially invalid way.
+   ??? Instead, should fix mark_used to only set TREE_USED when we're
+   really using something, and just return if it's already set.  */
+#define DECL_NO_LINKAGE_CHECKED(DECL) \
+  (DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL)) \
+   ->u.base.no_linkage_checked)
+
 /* Nonzero for DECL means that this decl is just a friend declaration,
    and should not be added to the list of members for this class.  */
 #define DECL_FRIEND_P(NODE) (DECL_LANG_SPECIFIC (NODE)->u.base.friend_attr)
index be1b5b7..898542f 100644 (file)
@@ -6747,36 +6747,6 @@ grokfndecl (tree ctype,
                || decl_function_context (TYPE_MAIN_DECL (ctype))))
     publicp = 0;
 
-  if (publicp)
-    {
-      /* [basic.link]: A name with no linkage (notably, the name of a class
-        or enumeration declared in a local scope) shall not be used to
-        declare an entity with linkage.
-
-        Only check this for public decls for now.  See core 319, 389.  */
-      t = no_linkage_check (TREE_TYPE (decl),
-                           /*relaxed_p=*/false);
-      if (t)
-       {
-         if (TYPE_ANONYMOUS_P (t))
-           {
-             if (DECL_EXTERN_C_P (decl))
-               /* Allow this; it's pretty common in C.  */;
-             else
-               {
-                 permerror (input_location, "non-local function %q#D uses anonymous type",
-                             decl);
-                 if (DECL_ORIGINAL_TYPE (TYPE_NAME (t)))
-                   permerror (input_location, "%q+#D does not refer to the unqualified "
-                              "type, so it is not used for linkage",
-                              TYPE_NAME (t));
-               }
-           }
-         else
-           permerror (input_location, "non-local function %q#D uses local type %qT", decl, t);
-       }
-    }
-
   TREE_PUBLIC (decl) = publicp;
   if (! publicp)
     {
@@ -7021,36 +6991,13 @@ grokvardecl (tree type,
 
   if (TREE_PUBLIC (decl))
     {
-      /* [basic.link]: A name with no linkage (notably, the name of a class
-        or enumeration declared in a local scope) shall not be used to
-        declare an entity with linkage.
-
-        Only check this for public decls for now.  */
-      tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false);
-      if (t)
-       {
-         if (TYPE_ANONYMOUS_P (t))
-           {
-             if (DECL_EXTERN_C_P (decl))
-               /* Allow this; it's pretty common in C.  */
-                 ;
-             else
-               {
-                 /* DRs 132, 319 and 389 seem to indicate types with
-                    no linkage can only be used to declare extern "C"
-                    entities.  Since it's not always an error in the
-                    ISO C++ 90 Standard, we only issue a warning.  */
-                 warning (0, "non-local variable %q#D uses anonymous type",
-                          decl);
-                 if (DECL_ORIGINAL_TYPE (TYPE_NAME (t)))
-                   warning (0, "%q+#D does not refer to the unqualified "
-                            "type, so it is not used for linkage",
-                            TYPE_NAME (t));
-               }
-           }
-         else
-           warning (0, "non-local variable %q#D uses local type %qT", decl, t);
-       }
+      /* If the type of the decl has no linkage, make sure that we'll
+        notice that in mark_used.  */
+      if (DECL_LANG_SPECIFIC (decl) == NULL
+         && TREE_PUBLIC (decl)
+         && !DECL_EXTERN_C_P (decl)
+         && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false))
+       retrofit_lang_decl (decl);
     }
   else
     DECL_INTERFACE_KNOWN (decl) = 1;
index df79e9c..610d62d 100644 (file)
@@ -84,6 +84,7 @@ static void write_out_vars (tree);
 static void import_export_class (tree);
 static tree get_guard_bits (tree);
 static void determine_visibility_from_class (tree, tree);
+static bool decl_defined_p (tree);
 
 /* A list of static class variables.  This is needed, because a
    static class variable can be declared inside the class without
@@ -94,6 +95,10 @@ static GTY(()) VEC(tree,gc) *pending_statics;
    may need to emit outline anyway.  */
 static GTY(()) VEC(tree,gc) *deferred_fns;
 
+/* A list of decls that use types with no linkage, which we need to make
+   sure are defined.  */
+static GTY(()) VEC(tree,gc) *no_linkage_decls;
+
 /* Nonzero if we're done parsing and into end-of-file activities.  */
 
 int at_eof;
@@ -3332,6 +3337,40 @@ build_java_method_aliases (void)
     }
 }
 
+/* Returns true iff there is a definition available for variable or
+   function DECL.  */
+
+static bool
+decl_defined_p (tree decl)
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    return (DECL_INITIAL (decl) != NULL_TREE);
+  else
+    {
+      gcc_assert (TREE_CODE (decl) == VAR_DECL);
+      return !DECL_EXTERNAL (decl);
+    }
+}
+
+/* Complain that DECL uses a type with no linkage but is never defined.  */
+
+static void
+no_linkage_error (tree decl)
+{
+  tree t = no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false);
+  if (TYPE_ANONYMOUS_P (t))
+    {
+      permerror (0, "%q+#D, declared using anonymous type, "
+                "is used but never defined", decl);
+      if (is_typedef_decl (TYPE_NAME (t)))
+       permerror (0, "%q+#D does not refer to the unqualified type, "
+                  "so it is not used for linkage", TYPE_NAME (t));
+    }
+  else
+    permerror (0, "%q+#D, declared using local type %qT, "
+              "is used but never defined", decl, t);
+}
+
 /* This routine is called at the end of compilation.
    Its job is to create all the code needed to initialize and
    destroy the global aggregates.  We do the destruction
@@ -3613,6 +3652,11 @@ cp_write_global_declarations (void)
        }
     }
 
+  /* So must decls that use a type with no linkage.  */
+  for (i = 0; VEC_iterate (tree, no_linkage_decls, i, decl); ++i)
+    if (!decl_defined_p (decl))
+      no_linkage_error (decl);
+
   /* We give C linkage to static constructors and destructors.  */
   push_lang_context (lang_name_c);
 
@@ -3851,6 +3895,32 @@ mark_used (tree decl)
   if (processing_template_decl)
     return;
 
+  /* DR 757: A type without linkage shall not be used as the type of a
+     variable or function with linkage, unless
+   o the variable or function has extern "C" linkage (7.5 [dcl.link]), or
+   o the variable or function is not used (3.2 [basic.def.odr]) or is
+   defined in the same translation unit.  */
+  if (TREE_PUBLIC (decl)
+      && (TREE_CODE (decl) == FUNCTION_DECL
+         || TREE_CODE (decl) == VAR_DECL)
+      && DECL_LANG_SPECIFIC (decl)
+      && !DECL_NO_LINKAGE_CHECKED (decl))
+    {
+      DECL_NO_LINKAGE_CHECKED (decl) = true;
+      if (!DECL_EXTERN_C_P (decl)
+         && !DECL_ARTIFICIAL (decl)
+         && !decl_defined_p (decl)
+         && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false))
+       {
+         if (is_local_extern (decl))
+           /* There's no way to define a local extern, and adding it to
+              the vector interferes with GC, so give an error now.  */
+           no_linkage_error (decl);
+         else
+           VEC_safe_push (tree, gc, no_linkage_decls, decl);
+       }
+    }
+
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)
       && !TREE_ASM_WRITTEN (decl))
     /* Remember it, so we can check it was defined.  */
index c2d8779..feb2cf2 100644 (file)
@@ -4392,6 +4392,34 @@ lookup_name_innermost_nonclass_level (tree name)
   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
 }
 
+/* Returns true iff DECL is a block-scope extern declaration of a function
+   or variable.  */
+
+bool
+is_local_extern (tree decl)
+{
+  cxx_binding *binding;
+
+  /* For functions, this is easy.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    return DECL_LOCAL_FUNCTION_P (decl);
+
+  if (TREE_CODE (decl) != VAR_DECL)
+    return false;
+  if (!current_function_decl)
+    return false;
+
+  /* For variables, this is not easy.  We need to look at the binding stack
+     for the identifier to see whether the decl we have is a local.  */
+  for (binding = IDENTIFIER_BINDING (DECL_NAME (decl));
+       binding && binding->scope->kind != sk_namespace;
+       binding = binding->previous)
+    if (binding->value == decl)
+      return LOCAL_BINDING_P (binding);
+
+  return false;
+}
+
 /* Like lookup_name_innermost_nonclass_level, but for types.  */
 
 static tree
index 2203a84..7a3625a 100644 (file)
@@ -318,6 +318,7 @@ extern tree remove_hidden_names (tree);
 extern tree lookup_qualified_name (tree, tree, bool, bool);
 extern tree lookup_name_nonclass (tree);
 extern tree lookup_name_innermost_nonclass_level (tree);
+extern bool is_local_extern (tree);
 extern tree lookup_function_nonclass (tree, VEC(tree,gc) *, bool);
 extern void push_local_binding (tree, tree, int);
 extern bool pushdecl_class_level (tree);
index c0c61c5..36f1b00 100644 (file)
@@ -12215,7 +12215,7 @@ tsubst_copy_and_build (tree t,
 }
 
 /* Verify that the instantiated ARGS are valid. For type arguments,
-   make sure that the type's linkage is ok. For non-type arguments,
+   make sure that the type is not variably modified. For non-type arguments,
    make sure they are constants if they are integral or enumerations.
    Emit an error under control of COMPLAIN, and return TRUE on error.  */
 
@@ -12236,30 +12236,7 @@ check_instantiated_arg (tree tmpl, tree t, tsubst_flags_t complain)
     }
   else if (TYPE_P (t))
     {
-      /* [basic.link]: A name with no linkage (notably, the name
-        of a class or enumeration declared in a local scope)
-        shall not be used to declare an entity with linkage.
-        This implies that names with no linkage cannot be used as
-        template arguments.  */
-      tree nt = no_linkage_check (t, /*relaxed_p=*/false);
-
-      if (nt)
-       {
-         /* DR 488 makes use of a type with no linkage cause
-            type deduction to fail.  */
-         if (complain & tf_error)
-           {
-             if (TYPE_ANONYMOUS_P (nt))
-               error ("%qT is/uses anonymous type", t);
-             else
-               error ("template argument for %qD uses local type %qT",
-                      tmpl, t);
-           }
-         return true;
-       }
-      /* In order to avoid all sorts of complications, we do not
-        allow variably-modified types as template arguments.  */
-      else if (variably_modified_type_p (t, NULL_TREE))
+      if (variably_modified_type_p (t, NULL_TREE))
        {
          if (complain & tf_error)
            error ("%qT is a variably modified type", t);
index 2f7c1b2..bea2eaa 100644 (file)
@@ -1,3 +1,18 @@
+2009-08-10  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/other/linkage2.C: New test for types-without-linkage
+       handling.
+       * g++.dg/ext/anon-struct4.C: No error about anonymous type.
+       * g++.dg/lookup/anon2.C: Likewise.
+       * g++.dg/other/anon3.C: Likewise.
+       * g++.dg/template/arg2.C: Likewise.
+       * g++.dg/template/local4.C: Likewise.
+       * g++.old-deja/g++.law/operators32.C: Likewise.
+       * g++.old-deja/g++.other/linkage2.C: Likewise.
+       * g++.old-deja/g++.pt/enum6.C: Likewise.
+       * g++.old-deja/g++.other/anon9.C: Use the undefined decls.
+       * g++.old-deja/g++.other/linkage1.C: Likewise.
+
 2009-08-10  Manuel López-Ibáñez  <manu@gcc.gnu.org>
 
        * gcc.dg/dg.exp: Test also c-c++-common dir.
index 4f0fcd1..53302d8 100644 (file)
@@ -1,4 +1,3 @@
 // PR c++/14401
 
 struct { struct { int& i ; } bar ; } foo ; // { dg-error "uninitialized" "uninit" }
-// { dg-warning "anonymous" "anon" { target *-*-* } 3 }
index d556ba0..3143b62 100644 (file)
@@ -1,9 +1,9 @@
 // { dg-do compile }
 // { dg-options "" }
 
-// Make sure we issue a diagnostic if a type with no linkage is used
-// to declare a a variable that has linkage.
+// Make sure we don't issue a diagnostic if a type with no linkage is used
+// to declare a a variable that has linkage if that variable is defined.
 
-struct { int i; } a; // { dg-warning "anonymous type" }
+struct { int i; } a;
 
 void foo() { a.i; }
index 87116eb..87cbfb5 100644 (file)
@@ -4,4 +4,4 @@
 
 // { dg-do compile }
 
-enum { a = 3 } x; // { dg-warning "anonymous type" }
+enum { a = 3 } x;
diff --git a/gcc/testsuite/g++.dg/other/linkage2.C b/gcc/testsuite/g++.dg/other/linkage2.C
new file mode 100644 (file)
index 0000000..4e3e6f1
--- /dev/null
@@ -0,0 +1,31 @@
+// DR 743: A type without linkage shall not be used as the type of a
+//     variable or function with linkage, unless
+//   o the variable or function has extern "C" linkage (7.5 [dcl.link]), or
+//   o the variable or function is not used (3.2 [basic.def.odr]) or is
+//   defined in the same translation unit.
+
+template <typename T> struct B {
+  void g(T){}
+  void h(T);                   // { dg-error "never defined" }
+  friend void i(B, T){}
+  static T t1;                 // { dg-error "never defined" }
+  static T t2;
+};
+
+template <typename T> T B<T>::t2 = { };
+
+enum {} e1;                    // OK, defined
+extern enum {} e2;             // { dg-error "never defined" }
+extern "C" enum {} e3;         // OK, extern "C"
+
+void f() {
+  struct A { int x; };  // no linkage
+  A a = {1};
+  B<A> ba;              // declares B<A>::g(A) and B<A>::h(A)
+  ba.t1 = a;           // error, B<T>::t never defined
+  ba.t2 = a;           // OK
+  ba.g(a);              // OK
+  ba.h(a);              // error, B<T>::h never defined
+  i(ba, a);             // OK
+  e1+e2+e3;
+}
index 9fb7a68..1314b25 100644 (file)
@@ -10,5 +10,5 @@ template <typename T> class X {};
 void fn ()
 {
   class L {};
-  X<L> f; // { dg-error "uses local type|trying to instantiate|no type|invalid type" "" }
+  X<L> f;
 }
index cfa3736..41e2370 100644 (file)
@@ -4,5 +4,5 @@ template <typename T> void foo() {}
 
 int main () {
   struct S {};
-  foo<S> (); // { dg-error "match" } 
+  foo<S> ();
 }
index 91de03e..89f0b66 100644 (file)
@@ -49,7 +49,7 @@ foo() {std::cout << "foo created" << std::endl; }
 };
 
 foo **f2;
-allocate2d(d1, d2, f2);// { dg-error "" }  type.*// ERROR -    trying to.*
-ffree(d1, f2);// { dg-error "" }  type.*// ERROR -    trying to.*
+allocate2d(d1, d2, f2);
+ffree(d1, f2);
 
 }
index a364db8..f4b1923 100644 (file)
@@ -4,3 +4,8 @@
 
 typedef const struct { int i; } T; // { dg-error "" } referenced below
 void f (T* t);                 // { dg-error "" } uses unnamed type
+
+int main()
+{
+  f(0);
+}
index e9b5a9d..de9a6ac 100644 (file)
@@ -3,13 +3,16 @@ typedef struct {
   int i;
 } *p;
 
-void f (p) { }                 // { dg-error "uses anonymous type" }
-p q;                           // { dg-warning "uses anonymous type" } 
+void f (p) { }
+p q;
 
 int main()
 {
-  extern p j;                  // { dg-warning "uses anonymous type" }
+  extern p j;                  // { dg-error "anonymous type" }
+  j+1;
   struct A { int j; };
-  extern A a;                  // { dg-warning "uses local type" }
-  extern void f (A);           // { dg-error "uses local type" }
+  extern A a;                  // { dg-error "local type" }
+  a.j+1;
+  extern void f (A);           // { dg-error "local type" }
+  f(a);
 }
index 2385b22..64f74f7 100644 (file)
@@ -7,7 +7,7 @@ extern GDBM_FILE gdbm_open();
 }
 
 typedef struct { int dummy[10]; } *FAIL_FILE;
-extern FAIL_FILE fail_open(); // { dg-error "" } non-local function
+extern FAIL_FILE fail_open(); // OK because it's never used
 
 typedef struct { int dummy[10]; } *SUCCESS_FILE, S;
 extern SUCCESS_FILE success_open();
index 254b48b..561254d 100644 (file)
@@ -8,7 +8,7 @@ void fn(T)
 {
   enum tern { H, L, X, U };
 
-  vector<tern> ternvec; // { dg-error "" } composed from a local type
+  vector<tern> ternvec;
 }
 
 template void fn(int);