]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR ipa/61324
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 11 Dec 2014 21:48:48 +0000 (21:48 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 11 Dec 2014 21:48:48 +0000 (21:48 +0000)
* testsuite/g++.dg/pr61324.C: New testcase by Trevor Saunders.
* testsuite/g++.dg/tm/pr51411-2.C: Update se the extern function is
not eliminated early.
* testsuite/gcc.target/i386/pr57756.c: Turn extern inline into static
inline.

* passes.c (execute_todo): Update call of remove_unreachable_nodes.
* ipa-chkp.c (chkp_produce_thunks): Use TODO_remove_functions.
* cgraphunit.c (symbol_table::process_new_functions): Add
IPA_SSA_AFTER_INLINING.
(ipa_passes): Update call of remove_unreachable_nodes.
(symbol_table::compile): Remove call of remove_unreachable_nodes.
* ipa-inline.c (inline_small_functions): Do not ICE with
-flto-partition=none
(ipa_inline): Update symtab->state; fix formatting
update call of remove_unreachable_nodes.
* cgraphclones.c (symbol_table::materialize_all_clones): Likewise.
* cgraph.h (enum symtab_state): Add IPA_SSA_AFTER_INLINING.
(remove_unreachable_nodes): Update.
* ipa.c (process_references): Keep external references only
when optimizing.
(walk_polymorphic_call_targets): Keep possible polymorphic call
target only when devirtualizing.
(symbol_table::remove_unreachable_nodes): Remove BEFORE_INLINING_P
parameter.
(ipa_single_use): Update comment.
* ipa-pure-const.c (cdtor_p): New function.
(propagate_pure_const): Track if some cdtor was turned pure/const.
(execute): Return TODO_remove_functions if needed.
* ipa-comdats.c (ipa_comdats): Update comment.

* lto.c (read_cgraph_and_symbols): Update call of
remove_unreachable_nodes.
(do_whole_program_analysis): Remove call of
symtab->remove_unreachable_nodes

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@218640 138bc75d-0d04-0410-961f-82ee72b054a4

16 files changed:
gcc/ChangeLog
gcc/cgraph.h
gcc/cgraphclones.c
gcc/cgraphunit.c
gcc/ipa-chkp.c
gcc/ipa-comdats.c
gcc/ipa-inline.c
gcc/ipa-pure-const.c
gcc/ipa.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/passes.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/pr61324.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/pr51411-2.C
gcc/testsuite/gcc.target/i386/pr57756.c

index 7f233e8626ea7c8375f63e8d4d35b3b95bfd09b3..c0de7443afc734449f9334b0047dc40a50d56a77 100644 (file)
@@ -1,3 +1,32 @@
+2014-12-11  Jan Hubicka  <hubicka@ucw.cz>
+
+       PR ipa/61324
+       * passes.c (execute_todo): Update call of remove_unreachable_nodes.
+       * ipa-chkp.c (chkp_produce_thunks): Use TODO_remove_functions.
+       * cgraphunit.c (symbol_table::process_new_functions): Add
+       IPA_SSA_AFTER_INLINING.
+       (ipa_passes): Update call of remove_unreachable_nodes.
+       (symbol_table::compile): Remove call of remove_unreachable_nodes.
+       * ipa-inline.c (inline_small_functions): Do not ICE with
+       -flto-partition=none
+       (ipa_inline): Update symtab->state; fix formatting
+       update call of remove_unreachable_nodes.
+       * passes.c (execute_todo): Update call of remove_unreachable_nodes.
+       * cgraphclones.c (symbol_table::materialize_all_clones): Likewise.
+       * cgraph.h (enum symtab_state): Add IPA_SSA_AFTER_INLINING.
+       (remove_unreachable_nodes): Update.
+       * ipa.c (process_references): Keep external references only
+       when optimizing.
+       (walk_polymorphic_call_targets): Keep possible polymorphic call
+       target only when devirtualizing.
+       (symbol_table::remove_unreachable_nodes): Remove BEFORE_INLINING_P
+       parameter.
+       (ipa_single_use): Update comment.
+       * ipa-pure-const.c (cdtor_p): New function.
+       (propagate_pure_const): Track if some cdtor was turned pure/const.
+       (execute): Return TODO_remove_functions if needed.
+       * ipa-comdats.c (ipa_comdats): Update comment.
+
 2014-12-11  Aldy Hernandez  <aldyh@redhat.com>
 
        * dwarf2out.c (gen_lexical_block_die): Remove unused `depth'
index 891b92500e7539a81d0829332cac8e262d01dec7..a2fc56300a7c378436a8b8e93a08cb94391b9c2f 100644 (file)
@@ -1801,12 +1801,15 @@ enum symtab_state
   PARSING,
   /* Callgraph is being constructed.  It is safe to add new functions.  */
   CONSTRUCTION,
-  /* Callgraph is being at LTO time.  */
+  /* Callgraph is being streamed-in at LTO time.  */
   LTO_STREAMING,
-  /* Callgraph is built and IPA passes are being run.  */
+  /* Callgraph is built and early IPA passes are being run.  */
   IPA,
   /* Callgraph is built and all functions are transformed to SSA form.  */
   IPA_SSA,
+  /* All inline decisions are done; it is now possible to remove extern inline
+     functions and virtual call targets.  */
+  IPA_SSA_AFTER_INLINING,
   /* Functions are now ordered and being passed to RTL expanders.  */
   EXPANSION,
   /* All cgraph expansion is done.  */
@@ -1876,7 +1879,7 @@ public:
   }
 
   /* Perform reachability analysis and reclaim all unreachable nodes.  */
-  bool remove_unreachable_nodes (bool before_inlining_p, FILE *file);
+  bool remove_unreachable_nodes (FILE *file);
 
   /* Optimization of function bodies might've rendered some variables as
      unnecessary so we want to avoid these from being compiled.  Re-do
index 13bb0e95b44a0c1cc1d5a2b70df4a375c07e779c..43d81a9f0ab539306704099839a81301dec26541 100644 (file)
@@ -1146,7 +1146,7 @@ symbol_table::materialize_all_clones (void)
 #ifdef ENABLE_CHECKING
   cgraph_node::verify_cgraph_nodes ();
 #endif
-  symtab->remove_unreachable_nodes (false, symtab->dump_file);
+  symtab->remove_unreachable_nodes (symtab->dump_file);
 }
 
 #include "gt-cgraphclones.h"
index fed1a3e0053723fe76579c39580b495283ad55c3..53abd173fa67c1153f230c04287d9581890aa45f 100644 (file)
@@ -327,6 +327,7 @@ symbol_table::process_new_functions (void)
 
        case IPA:
        case IPA_SSA:
+       case IPA_SSA_AFTER_INLINING:
          /* When IPA optimization already started, do all essential
             transformations that has been already performed on the whole
             cgraph but not on this function.  */
@@ -335,7 +336,7 @@ symbol_table::process_new_functions (void)
          if (!node->analyzed)
            node->analyze ();
          push_cfun (DECL_STRUCT_FUNCTION (fndecl));
-         if (state == IPA_SSA
+         if ((state == IPA_SSA || state == IPA_SSA_AFTER_INLINING)
              && !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
            g->get_passes ()->execute_early_local_passes ();
          else if (inline_summary_vec != NULL)
@@ -507,6 +508,7 @@ cgraph_node::add_new_function (tree fndecl, bool lowered)
 
       case IPA:
       case IPA_SSA:
+      case IPA_SSA_AFTER_INLINING:
       case EXPANSION:
        /* Bring the function into finalized state and enqueue for later
           analyzing and compilation.  */
@@ -2053,7 +2055,7 @@ ipa_passes (void)
 
   /* This extra symtab_remove_unreachable_nodes pass tends to catch some
      devirtualization and other changes where removal iterate.  */
-  symtab->remove_unreachable_nodes (true, symtab->dump_file);
+  symtab->remove_unreachable_nodes (symtab->dump_file);
 
   /* If pass_all_early_optimizations was not scheduled, the state of
      the cgraph will not be properly updated.  Update it now.  */
@@ -2194,10 +2196,6 @@ symbol_table::compile (void)
       return;
     }
 
-  /* This pass remove bodies of extern inline functions we never inlined.
-     Do this later so other IPA passes see what is really going on.
-     FIXME: This should be run just after inlining by pasmanager.  */
-  remove_unreachable_nodes (false, dump_file);
   global_info_ready = true;
   if (dump_file)
     {
index 46b2139758aaf2e918bfe73b484856a942f49c2c..c6bd15ff61a731945b4bfa3874bf60cf672e1e27 100644 (file)
@@ -647,9 +647,7 @@ chkp_produce_thunks (void)
        chkp_function_mark_instrumented (node->decl);
     }
 
-  symtab->remove_unreachable_nodes (true, dump_file);
-
-  return 0;
+  return TODO_remove_functions;
 }
 
 const pass_data pass_data_ipa_chkp_versioning =
index af2aef8efad20cd19a6071267b5b43e4cb7b67ae..306f55f8f869fb8ccd3f0731f3cf0ab5626911f7 100644 (file)
@@ -327,7 +327,14 @@ ipa_comdats (void)
          && !symbol->alias
          && symbol->real_symbol_p ())
        {
-         tree group = *map.get (symbol);
+         tree *val = map.get (symbol);
+
+         /* A NULL here means that SYMBOL is unreachable in the definition
+            of ipa-comdats. Either ipa-comdats is wrong about this or someone
+            forgot to cleanup and remove unreachable functions earlier.  */
+         gcc_assert (val);
+
+         tree group = *val;
 
          if (group == error_mark_node)
            continue;
index 9f600b092c2ea0c1f0d3c4b8a5dc2c86114dfcdd..8954e49353392613dc9e9dd791ba514a7199b0bf 100644 (file)
@@ -1731,9 +1731,9 @@ inline_small_functions (void)
                   " to be inlined into %s/%i in %s:%i\n"
                   " Estimated badness is %"PRId64", frequency %.2f.\n",
                   edge->caller->name (), edge->caller->order,
-                  flag_wpa ? "unknown"
+                  edge->call_stmt ? "unknown"
                   : gimple_filename ((const_gimple) edge->call_stmt),
-                  flag_wpa ? -1
+                  edge->call_stmt ? -1
                   : gimple_lineno ((const_gimple) edge->call_stmt),
                   badness.to_int (),
                   edge->frequency / (double)CGRAPH_FREQ_BASE);
@@ -2188,9 +2188,12 @@ ipa_inline (void)
 
   inline_small_functions ();
 
-  /* Do first after-inlining removal.  We want to remove all "stale" extern inline
-     functions and virtual functions so we really know what is called once.  */
-  symtab->remove_unreachable_nodes (false, dump_file);
+  gcc_assert (symtab->state == IPA_SSA);
+  symtab->state = IPA_SSA_AFTER_INLINING;
+  /* Do first after-inlining removal.  We want to remove all "stale" extern
+     inline functions and virtual functions so we really know what is called
+     once.  */
+  symtab->remove_unreachable_nodes (dump_file);
   free (order);
 
   /* Inline functions with a property that after inlining into all callers the
@@ -2199,7 +2202,8 @@ ipa_inline (void)
      are met.  */
   if (dump_file)
     fprintf (dump_file,
-            "\nDeciding on functions to be inlined into all callers and removing useless speculations:\n");
+            "\nDeciding on functions to be inlined into all callers and "
+            "removing useless speculations:\n");
 
   /* Inlining one function called once has good chance of preventing
      inlining other function into the same callee.  Ideally we should
@@ -2247,10 +2251,11 @@ ipa_inline (void)
              int num_calls = 0;
              node->call_for_symbol_thunks_and_aliases (sum_callers, &num_calls,
                                                      true);
-             while (node->call_for_symbol_thunks_and_aliases (inline_to_all_callers,
-                                                            &num_calls, true))
+             while (node->call_for_symbol_thunks_and_aliases
+                      (inline_to_all_callers, &num_calls, true))
                ;
-             remove_functions = true;
+             if (num_calls)
+               remove_functions = true;
            }
        }
     }
index 13e3a258c9b048ec92a61fb44ba75af3e897342d..94c3f81dfc885408c7a25b92ab622a9c635de318 100644 (file)
@@ -1160,10 +1160,21 @@ self_recursive_p (struct cgraph_node *node)
   return false;
 }
 
+/* Return true if N is cdtor that is not const or pure.  In this case we may
+   need to remove unreachable function if it is marked const/pure.  */
+
+static bool
+cdtor_p (cgraph_node *n, void *)
+{
+  if (DECL_STATIC_CONSTRUCTOR (n->decl) || DECL_STATIC_DESTRUCTOR (n->decl))
+    return !TREE_READONLY (n->decl) && !DECL_PURE_P (n->decl);
+  return false;
+}
+
 /* Produce transitive closure over the callgraph and compute pure/const
    attributes.  */
 
-static void
+static bool
 propagate_pure_const (void)
 {
   struct cgraph_node *node;
@@ -1173,6 +1184,7 @@ propagate_pure_const (void)
   int order_pos;
   int i;
   struct ipa_dfs_info * w_info;
+  bool remove_p = false;
 
   order_pos = ipa_reduced_postorder (order, true, false, NULL);
   if (dump_file)
@@ -1447,6 +1459,8 @@ propagate_pure_const (void)
                               this_looping ? "looping " : "",
                               w->name ());
                  }
+               remove_p |= w->call_for_symbol_and_aliases (cdtor_p,
+                                                           NULL, true);
                w->set_const_flag (true, this_looping);
                break;
 
@@ -1459,6 +1473,8 @@ propagate_pure_const (void)
                               this_looping ? "looping " : "",
                               w->name ());
                  }
+               remove_p |= w->call_for_symbol_and_aliases (cdtor_p,
+                                                           NULL, true);
                w->set_pure_flag (true, this_looping);
                break;
 
@@ -1472,6 +1488,7 @@ propagate_pure_const (void)
 
   ipa_free_postorder_info ();
   free (order);
+  return remove_p;
 }
 
 /* Produce transitive closure over the callgraph and compute nothrow
@@ -1581,6 +1598,7 @@ pass_ipa_pure_const::
 execute (function *)
 {
   struct cgraph_node *node;
+  bool remove_p;
 
   symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
   symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
@@ -1589,14 +1607,14 @@ execute (function *)
   /* Nothrow makes more function to not lead to return and improve
      later analysis.  */
   propagate_nothrow ();
-  propagate_pure_const ();
+  remove_p = propagate_pure_const ();
 
   /* Cleanup. */
   FOR_EACH_FUNCTION (node)
     if (has_function_state (node))
       free (get_function_state (node));
   funct_state_vec.release ();
-  return 0;
+  return remove_p ? TODO_remove_functions : 0;
 }
 
 static bool
index 4f87b75946cfb070b62e4c176b90a3418b7b06ab..bed20e9d664cfb885517fd2a696009d7d735f0c6 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -123,21 +123,33 @@ process_references (symtab_node *snode,
   for (i = 0; snode->iterate_reference (i, ref); i++)
     {
       symtab_node *node = ref->referred;
+      symtab_node *body = node->ultimate_alias_target ();
 
       if (node->definition && !node->in_other_partition
          && ((!DECL_EXTERNAL (node->decl) || node->alias)
              || (((before_inlining_p
-                   && (symtab->state < IPA_SSA
-                       || !lookup_attribute ("always_inline",
-                                             DECL_ATTRIBUTES (node->decl)))))
-                 /* We use variable constructors during late complation for
+                   && (TREE_CODE (node->decl) != FUNCTION_DECL
+                       || opt_for_fn (body->decl, optimize)
+                       || (symtab->state < IPA_SSA
+                           && lookup_attribute
+                                ("always_inline",
+                                 DECL_ATTRIBUTES (body->decl))))))
+                 /* We use variable constructors during late compilation for
                     constant folding.  Keep references alive so partitioning
                     knows about potential references.  */
                  || (TREE_CODE (node->decl) == VAR_DECL
                      && flag_wpa
                      && ctor_for_folding (node->decl)
                         != error_mark_node))))
-       reachable->add (node);
+       {
+         /* Be sure that we will not optimize out alias target
+            body.  */
+         if (DECL_EXTERNAL (node->decl)
+             && node->alias
+             && before_inlining_p)
+           reachable->add (body);
+         reachable->add (node);
+       }
       enqueue_node (node, first, reachable);
     }
 }
@@ -178,15 +190,23 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
                    (method_class_type (TREE_TYPE (n->decl))))
            continue;
 
+          symtab_node *body = n->function_symbol ();
+
          /* Prior inlining, keep alive bodies of possible targets for
             devirtualization.  */
           if (n->definition
               && (before_inlining_p
-                  && (symtab->state < IPA_SSA
-                      || !lookup_attribute ("always_inline",
-                                            DECL_ATTRIBUTES (n->decl)))))
-            reachable->add (n);
-
+                  && opt_for_fn (body->decl, optimize)
+                  && opt_for_fn (body->decl, flag_devirtualize)))
+             {
+                /* Be sure that we will not optimize out alias target
+                   body.  */
+                if (DECL_EXTERNAL (n->decl)
+                    && n->alias
+                    && before_inlining_p)
+                  reachable->add (body);
+               reachable->add (n);
+             }
          /* Even after inlining we want to keep the possible targets in the
             boundary, so late passes can still produce direct call even if
             the chance for inlining is lost.  */
@@ -246,8 +266,6 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
      After inlining we release their bodies and turn them into unanalyzed
      nodes even when they are reachable.
 
-     BEFORE_INLINING_P specify whether we are before or after inlining.
-
    - virtual functions are kept in callgraph even if they seem unreachable in
      hope calls to them will be devirtualized. 
 
@@ -293,7 +311,7 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
    we set AUX pointer of processed symbols in the boundary to constant 2.  */
 
 bool
-symbol_table::remove_unreachable_nodes (bool before_inlining_p, FILE *file)
+symbol_table::remove_unreachable_nodes (FILE *file)
 {
   symtab_node *first = (symtab_node *) (void *) 1;
   struct cgraph_node *node, *next;
@@ -302,6 +320,8 @@ symbol_table::remove_unreachable_nodes (bool before_inlining_p, FILE *file)
   hash_set<symtab_node *> reachable;
   hash_set<tree> body_needed_for_clonning;
   hash_set<void *> reachable_call_targets;
+  bool before_inlining_p = symtab->state < (!optimize ? IPA_SSA
+                                           : IPA_SSA_AFTER_INLINING);
 
   timevar_push (TV_IPA_UNREACHABLE);
   build_type_inheritance_graph ();
@@ -414,19 +434,25 @@ symbol_table::remove_unreachable_nodes (bool before_inlining_p, FILE *file)
                }
              for (e = cnode->callees; e; e = e->next_callee)
                {
+                 symtab_node *body = e->callee->function_symbol ();
                  if (e->callee->definition
                      && !e->callee->in_other_partition
                      && (!e->inline_failed
                          || !DECL_EXTERNAL (e->callee->decl)
                          || e->callee->alias
-                         || before_inlining_p))
+                         || (before_inlining_p
+                             && (opt_for_fn (body->decl, optimize)
+                                 || (symtab->state < IPA_SSA
+                                     && lookup_attribute
+                                         ("always_inline",
+                                          DECL_ATTRIBUTES (body->decl)))))))
                    {
                      /* Be sure that we will not optimize out alias target
                         body.  */
                      if (DECL_EXTERNAL (e->callee->decl)
                          && e->callee->alias
                          && before_inlining_p)
-                       reachable.add (e->callee->function_symbol ());
+                       reachable.add (body);
                      reachable.add (e->callee);
                    }
                  enqueue_node (e->callee, &first, &reachable);
@@ -1219,14 +1245,15 @@ propagate_single_user (varpool_node *vnode, cgraph_node *function,
            function = BOTTOM;
        }
       else
-        function = meet (function, dyn_cast <varpool_node *> (ref->referring), single_user_map);
+       function = meet (function, dyn_cast <varpool_node *> (ref->referring),
+                        single_user_map);
     }
   return function;
 }
 
 /* Pass setting used_by_single_function flag.
-   This flag is set on variable when there is only one function that may possibly
-   referr to it.  */
+   This flag is set on variable when there is only one function that may
+   possibly referr to it.  */
 
 static unsigned int
 ipa_single_use (void)
@@ -1304,7 +1331,10 @@ ipa_single_use (void)
       if (var->aux != BOTTOM)
        {
 #ifdef ENABLE_CHECKING
-         if (!single_user_map.get (var))
+         /* Not having the single user known means that the VAR is
+            unreachable.  Either someone forgot to remove unreachable
+            variables or the reachability here is wrong.  */
+
           gcc_assert (single_user_map.get (var));
 #endif
          if (dump_file)
index 5f509f01b6ec14639238739a85ca8f7f8995db92..7f1088fa1454da4f677f669217f3b18e7b765e82 100644 (file)
@@ -1,3 +1,11 @@
+2014-12-11  Jan Hubicka  <hubicka@ucw.cz>
+
+       PR ipa/61324
+       * lto.c (read_cgraph_and_symbols): Update call of
+       remove_unreachable_nodes.
+       (do_whole_program_analysis): Remove call of
+       symtab->remove_unreachable_nodes
+
 2014-12-08  Trevor Saunders  <tsaunders@mozilla.com>
 
        * lto.c (read_cgraph_and_symbols): allocate gimple_canonical_types
index 1ff02f86ff89fcd8369aef55b4c276dee568b2c6..324538a0cb8b355352a38b1723a9c5d575b63bce 100644 (file)
@@ -3098,7 +3098,7 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames)
   /* Removal of unreachable symbols is needed to make verify_symtab to pass;
      we are still having duplicated comdat groups containing local statics.
      We could also just remove them while merging.  */
-  symtab->remove_unreachable_nodes (true, dump_file);
+  symtab->remove_unreachable_nodes (dump_file);
   ggc_collect ();
   symtab->state = IPA_SSA;
 
@@ -3255,7 +3255,6 @@ do_whole_program_analysis (void)
   symtab->state = IPA_SSA;
 
   execute_ipa_pass_list (g->get_passes ()->all_regular_ipa_passes);
-  symtab->remove_unreachable_nodes (false, dump_file);
 
   if (symtab->dump_file)
     {
index 74b40e5d80b3ea80ab18d8825d830c54d01b2068..3f9f7df11edddc1a9d91ee21e785280acc0c8423 100644 (file)
@@ -2003,7 +2003,7 @@ execute_todo (unsigned int flags)
   if (flags & TODO_remove_functions)
     {
       gcc_assert (!cfun);
-      symtab->remove_unreachable_nodes (true, dump_file);
+      symtab->remove_unreachable_nodes (dump_file);
     }
 
   if ((flags & TODO_dump_symtab) && dump_file && !current_function_decl)
index 4507037087e121bff820b635610b5fbb9f749f41..e85830cadc52a036a6214b9b13a043adbdb7736e 100644 (file)
@@ -1,3 +1,12 @@
+2014-12-11  Jan Hubicka  <hubicka@ucw.cz>
+
+       PR ipa/61324
+       * testsuite/g++.dg/pr61324.C: New testcase by Trevor Saunders.
+       * testsuite/g++.dg/tm/pr51411-2.C: Update se the extern function is
+       not eliminated early.
+       * testsuite/gcc.target/i386/pr57756.c: Turn extern inline into static
+       inline.
+
 2014-12-11  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/42108
diff --git a/gcc/testsuite/g++.dg/pr61324.C b/gcc/testsuite/g++.dg/pr61324.C
new file mode 100644 (file)
index 0000000..6102574
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-O -fkeep-inline-functions -fno-use-cxa-atexit" }
+void foo ();
+
+struct S
+{
+  ~S ()
+  {
+    foo ();
+  }
+};
+
+S s;
index 4105d66ec9d77fa217fbf13be063b9b8a5481ab9..3147d2f1d8737119aaf966e6078408f10543ae3e 100644 (file)
@@ -26,6 +26,7 @@ public:
     bool compare(const basic_string& __str) const {
         return 0;
     }
+    void key ();
 };
 
 typedef basic_string<char> string;
@@ -35,7 +36,7 @@ inline bool operator<(const basic_string<_CharT, _Traits>& __lhs, const basic_st
     return __lhs.compare(__rhs);
 }
 
-extern template class basic_string<char>;
+template class basic_string<char>;
 
 }
 
index f3faa4f816e2574f0d0706e4dd55a1b3cc3a01d3..7edd4b5d697e107bdb583b6b78bec393ee91d0fc 100644 (file)
@@ -9,7 +9,7 @@ __inline int callee () /* { dg-error "inlining failed in call to always_inline"
 }
 
 __attribute__((target("sse")))
-__inline int caller ()
+static __inline int caller ()
 {
   return callee(); /* { dg-error "called from here" }  */
 }