OSDN Git Service

gcc/ada/
[pf3gnuchains/gcc-fork.git] / gcc / c-pragma.c
index e71ab07..2f2095e 100644 (file)
@@ -1,12 +1,12 @@
 /* Handle #pragma, system V.4 style.  Supports #pragma weak and #pragma pack.
    Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006 Free Software Foundation, Inc.
+   2006, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -160,6 +159,8 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
     }
   else if (token == CPP_NUMBER)
     {
+      if (TREE_CODE (x) != INTEGER_CST)
+       GCC_BAD ("invalid constant in %<#pragma pack%> - ignored");
       align = TREE_INT_CST_LOW (x);
       action = set;
       if (pragma_lex (&x) != CPP_CLOSE_PAREN)
@@ -190,6 +191,8 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
            }
          else if (token == CPP_NUMBER && action == push && align == -1)
            {
+             if (TREE_CODE (x) != INTEGER_CST)
+               GCC_BAD ("invalid constant in %<#pragma pack%> - ignored");
              align = TREE_INT_CST_LOW (x);
              if (align == -1)
                action = set;
@@ -241,6 +244,146 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy))
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
+struct def_pragma_macro_value GTY(())
+{
+  struct def_pragma_macro_value *prev;
+  cpp_macro *value;
+};
+
+struct def_pragma_macro GTY(())
+{
+  hashval_t hash;
+  const char *name;
+  struct def_pragma_macro_value value;
+};
+
+static GTY((param_is (struct def_pragma_macro))) htab_t pushed_macro_table;
+
+#ifdef HANDLE_PRAGMA_PUSH_POP_MACRO
+/* Hash table control functions for pushed_macro_table.  */
+static hashval_t
+dpm_hash (const void *p)
+{
+  return ((const struct def_pragma_macro *)p)->hash;
+}
+
+static int
+dpm_eq (const void *pa, const void *pb)
+{
+  const struct def_pragma_macro *const a = (const struct def_pragma_macro *) pa,
+    *const b = (const struct def_pragma_macro *) pb;
+  return a->hash == b->hash && strcmp (a->name, b->name) == 0;
+}
+
+/* #pragma push_macro("MACRO_NAME")
+   #pragma pop_macro("MACRO_NAME") */
+
+static void
+handle_pragma_push_macro (cpp_reader *reader)
+{
+  tree x, id = 0;
+  enum cpp_ttype token;
+  struct def_pragma_macro dummy, *c;
+  const char *macroname;
+  void **slot;
+
+  if (pragma_lex (&x) != CPP_OPEN_PAREN)
+    GCC_BAD ("missing %<(%> after %<#pragma push_macro%> - ignored");
+
+  token = pragma_lex (&id);
+
+  /* Silently ignore */
+  if (token == CPP_CLOSE_PAREN)
+    return;
+  if (token != CPP_STRING)
+    GCC_BAD ("invalid constant in %<#pragma push_macro%> - ignored");
+
+  if (pragma_lex (&x) != CPP_CLOSE_PAREN)
+    GCC_BAD ("missing %<)%> after %<#pragma push_macro%> - ignored");
+
+  if (pragma_lex (&x) != CPP_EOF)
+    warning (OPT_Wpragmas, "junk at end of %<#pragma push_macro%>");
+
+  /* Check for empty string, and silently ignore.  */
+  if (TREE_STRING_LENGTH (id) < 1)
+    return;
+  macroname = TREE_STRING_POINTER (id);
+
+  if (pushed_macro_table == NULL)
+    pushed_macro_table = htab_create_ggc (15, dpm_hash, dpm_eq, 0);
+
+  dummy.hash = htab_hash_string (macroname);
+  dummy.name = macroname;
+  slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
+                                  dummy.hash, INSERT);
+  c = (struct def_pragma_macro *) *slot;
+  if (c == NULL)
+    {
+      *slot = c = GGC_NEW (struct def_pragma_macro);
+      c->hash = dummy.hash;
+      c->name = ggc_alloc_string (macroname, TREE_STRING_LENGTH (id) - 1);
+      c->value.prev = NULL;
+    }
+  else
+    {
+      struct def_pragma_macro_value *v;
+      v = GGC_NEW (struct def_pragma_macro_value);
+      *v = c->value;
+      c->value.prev = v;
+    }
+
+  c->value.value = cpp_push_definition (reader, macroname);
+}
+
+static void
+handle_pragma_pop_macro (cpp_reader *reader)
+{
+  tree x, id = 0;
+  enum cpp_ttype token;
+  struct def_pragma_macro dummy, *c;
+  const char *macroname;
+  void **slot = NULL;
+
+  if (pragma_lex (&x) != CPP_OPEN_PAREN)
+    GCC_BAD ("missing %<(%> after %<#pragma pop_macro%> - ignored");
+
+  token = pragma_lex (&id);
+
+  /* Silently ignore */
+  if (token == CPP_CLOSE_PAREN)
+    return;
+  if (token != CPP_STRING)
+    GCC_BAD ("invalid constant in %<#pragma pop_macro%> - ignored");
+
+  if (pragma_lex (&x) != CPP_CLOSE_PAREN)
+    GCC_BAD ("missing %<)%> after %<#pragma pop_macro%> - ignored");
+
+  if (pragma_lex (&x) != CPP_EOF)
+    warning (OPT_Wpragmas, "junk at end of %<#pragma pop_macro%>");
+
+  /* Check for empty string, and silently ignore.  */
+  if (TREE_STRING_LENGTH (id) < 1)
+    return;
+  macroname = TREE_STRING_POINTER (id);
+
+  dummy.hash = htab_hash_string (macroname);
+  dummy.name = macroname;
+  if (pushed_macro_table)
+    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
+                                    dummy.hash, NO_INSERT);
+  if (slot == NULL)
+    return;
+  c = (struct def_pragma_macro *) *slot;
+
+  cpp_pop_definition (reader, c->name, c->value.value);
+
+  if (c->value.prev)
+    c->value = *c->value.prev;
+  else
+    htab_clear_slot (pushed_macro_table, slot);
+}
+#endif /* HANDLE_PRAGMA_PUSH_POP_MACRO */
+
 static GTY(()) tree pending_weaks;
 
 #ifdef HANDLE_PRAGMA_WEAK
@@ -723,6 +866,306 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
   GCC_BAD ("unknown option after %<#pragma GCC diagnostic%> kind");
 }
 
+/*  Parse #pragma GCC target (xxx) to set target specific options.  */
+static void
+handle_pragma_target(cpp_reader *ARG_UNUSED(dummy))
+{
+  enum cpp_ttype token;
+  tree x;
+  bool close_paren_needed_p = false;
+
+  if (cfun)
+    {
+      error ("#pragma GCC option is not allowed inside functions");
+      return;
+    }
+
+  token = pragma_lex (&x);
+  if (token == CPP_OPEN_PAREN)
+    {
+      close_paren_needed_p = true;
+      token = pragma_lex (&x);
+    }
+
+  if (token != CPP_STRING)
+    {
+      GCC_BAD ("%<#pragma GCC option%> is not a string");
+      return;
+    }
+
+  /* Strings are user options.  */
+  else
+    {
+      tree args = NULL_TREE;
+
+      do
+       {
+         /* Build up the strings now as a tree linked list.  Skip empty
+            strings.  */
+         if (TREE_STRING_LENGTH (x) > 0)
+           args = tree_cons (NULL_TREE, x, args);
+
+         token = pragma_lex (&x);
+         while (token == CPP_COMMA)
+           token = pragma_lex (&x);
+       }
+      while (token == CPP_STRING);
+
+      if (close_paren_needed_p)
+       {
+         if (token == CPP_CLOSE_PAREN)
+           token = pragma_lex (&x);
+         else
+           GCC_BAD ("%<#pragma GCC target (string [,string]...)%> does "
+                    "not have a final %<)%>.");
+       }
+
+      if (token != CPP_EOF)
+       {
+         error ("#pragma GCC target string... is badly formed");
+         return;
+       }
+
+      /* put arguments in the order the user typed them.  */
+      args = nreverse (args);
+
+      if (targetm.target_option.pragma_parse (args, NULL_TREE))
+       current_target_pragma = args;
+    }
+}
+
+/* Handle #pragma GCC optimize to set optimization options.  */
+static void
+handle_pragma_optimize (cpp_reader *ARG_UNUSED(dummy))
+{
+  enum cpp_ttype token;
+  tree x;
+  bool close_paren_needed_p = false;
+  tree optimization_previous_node = optimization_current_node;
+
+  if (cfun)
+    {
+      error ("#pragma GCC optimize is not allowed inside functions");
+      return;
+    }
+
+  token = pragma_lex (&x);
+  if (token == CPP_OPEN_PAREN)
+    {
+      close_paren_needed_p = true;
+      token = pragma_lex (&x);
+    }
+
+  if (token != CPP_STRING && token != CPP_NUMBER)
+    {
+      GCC_BAD ("%<#pragma GCC optimize%> is not a string or number");
+      return;
+    }
+
+  /* Strings/numbers are user options.  */
+  else
+    {
+      tree args = NULL_TREE;
+
+      do
+       {
+         /* Build up the numbers/strings now as a list.  */
+         if (token != CPP_STRING || TREE_STRING_LENGTH (x) > 0)
+           args = tree_cons (NULL_TREE, x, args);
+
+         token = pragma_lex (&x);
+         while (token == CPP_COMMA)
+           token = pragma_lex (&x);
+       }
+      while (token == CPP_STRING || token == CPP_NUMBER);
+
+      if (close_paren_needed_p)
+       {
+         if (token == CPP_CLOSE_PAREN)
+           token = pragma_lex (&x);
+         else
+           GCC_BAD ("%<#pragma GCC optimize (string [,string]...)%> does "
+                    "not have a final %<)%>.");
+       }
+
+      if (token != CPP_EOF)
+       {
+         error ("#pragma GCC optimize string... is badly formed");
+         return;
+       }
+
+      /* put arguments in the order the user typed them.  */
+      args = nreverse (args);
+
+      parse_optimize_options (args, false);
+      current_optimize_pragma = chainon (current_optimize_pragma, args);
+      optimization_current_node = build_optimization_node ();
+      c_cpp_builtins_optimize_pragma (parse_in,
+                                     optimization_previous_node,
+                                     optimization_current_node);
+    }
+}
+
+/* Stack of the #pragma GCC options created with #pragma GCC push_option.  Save
+   both the binary representation of the options and the TREE_LIST of
+   strings that will be added to the function's attribute list.  */
+typedef struct opt_stack GTY(())
+{
+  struct opt_stack *prev;
+  tree target_binary;
+  tree target_strings;
+  tree optimize_binary;
+  tree optimize_strings;
+} opt_stack;
+
+static GTY(()) struct opt_stack * options_stack;
+
+/* Handle #pragma GCC push_options to save the current target and optimization
+   options.  */
+
+static void
+handle_pragma_push_options (cpp_reader *ARG_UNUSED(dummy))
+{
+  enum cpp_ttype token;
+  tree x = 0;
+  opt_stack *p;
+
+  token = pragma_lex (&x);
+  if (token != CPP_EOF)
+    {
+      warning (OPT_Wpragmas, "junk at end of %<#pragma push_options%>");
+      return;
+    }
+
+  p = GGC_NEW (opt_stack);
+  p->prev = options_stack;
+  options_stack = p;
+
+  /* Save optimization and target flags in binary format.  */
+  p->optimize_binary = build_optimization_node ();
+  p->target_binary = build_target_option_node ();
+
+  /* Save optimization and target flags in string list format.  */
+  p->optimize_strings = copy_list (current_optimize_pragma);
+  p->target_strings = copy_list (current_target_pragma);
+}
+
+/* Handle #pragma GCC pop_options to restore the current target and
+   optimization options from a previous push_options.  */
+
+static void
+handle_pragma_pop_options (cpp_reader *ARG_UNUSED(dummy))
+{
+  enum cpp_ttype token;
+  tree x = 0;
+  opt_stack *p;
+
+  token = pragma_lex (&x);
+  if (token != CPP_EOF)
+    {
+      warning (OPT_Wpragmas, "junk at end of %<#pragma pop_options%>");
+      return;
+    }
+
+  if (! options_stack)
+    {
+      warning (OPT_Wpragmas,
+              "%<#pragma GCC pop_options%> without a corresponding "
+              "%<#pragma GCC push_options%>");
+      return;
+    }
+
+  p = options_stack;
+  options_stack = p->prev;
+
+  if (p->target_binary != target_option_current_node)
+    {
+      (void) targetm.target_option.pragma_parse (NULL_TREE, p->target_binary);
+      target_option_current_node = p->target_binary;
+    }
+
+  if (p->optimize_binary != optimization_current_node)
+    {
+      tree old_optimize = optimization_current_node;
+      cl_optimization_restore (TREE_OPTIMIZATION (p->optimize_binary));
+      c_cpp_builtins_optimize_pragma (parse_in, old_optimize,
+                                     p->optimize_binary);
+      optimization_current_node = p->optimize_binary;
+    }
+
+  current_target_pragma = p->target_strings;
+  current_optimize_pragma = p->optimize_strings;
+}
+
+/* Handle #pragma GCC reset_options to restore the current target and
+   optimization options to the original options used on the command line.  */
+
+static void
+handle_pragma_reset_options (cpp_reader *ARG_UNUSED(dummy))
+{
+  enum cpp_ttype token;
+  tree x = 0;
+  tree new_optimize = optimization_default_node;
+  tree new_target = target_option_default_node;
+
+  token = pragma_lex (&x);
+  if (token != CPP_EOF)
+    {
+      warning (OPT_Wpragmas, "junk at end of %<#pragma reset_options%>");
+      return;
+    }
+
+  if (new_target != target_option_current_node)
+    {
+      (void) targetm.target_option.pragma_parse (NULL_TREE, new_target);
+      target_option_current_node = new_target;
+    }
+
+  if (new_optimize != optimization_current_node)
+    {
+      tree old_optimize = optimization_current_node;
+      cl_optimization_restore (TREE_OPTIMIZATION (new_optimize));
+      c_cpp_builtins_optimize_pragma (parse_in, old_optimize, new_optimize);
+      optimization_current_node = new_optimize;
+    }
+
+  current_target_pragma = NULL_TREE;
+  current_optimize_pragma = NULL_TREE;
+}
+
+/* Print a plain user-specified message.  */
+
+static void
+handle_pragma_message (cpp_reader *ARG_UNUSED(dummy))
+{
+  enum cpp_ttype token;
+  tree x, message = 0;
+
+  token = pragma_lex (&x);
+  if (token == CPP_OPEN_PAREN)
+    {
+      token = pragma_lex (&x);
+      if (token == CPP_STRING)
+        message = x;
+      else
+        GCC_BAD ("expected a string after %<#pragma message%>");
+      if (pragma_lex (&x) != CPP_CLOSE_PAREN)
+        GCC_BAD ("malformed %<#pragma message%>, ignored");
+    }
+  else if (token == CPP_STRING)
+    message = x;
+  else
+    GCC_BAD ("expected a string after %<#pragma message%>");
+
+  gcc_assert (message);
+
+  if (pragma_lex (&x) != CPP_EOF)
+    warning (OPT_Wpragmas, "junk at end of %<#pragma message%>");
+
+  if (TREE_STRING_LENGTH (message) > 1)
+    inform (input_location, "#pragma message: %s", TREE_STRING_POINTER (message));
+}
+
 /* A vector of registered pragma callbacks.  */
 
 DEF_VEC_O (pragma_handler);
@@ -730,6 +1173,63 @@ DEF_VEC_ALLOC_O (pragma_handler, heap);
 
 static VEC(pragma_handler, heap) *registered_pragmas;
 
+typedef struct
+{
+  const char *space;
+  const char *name;
+} pragma_ns_name;
+
+DEF_VEC_O (pragma_ns_name);
+DEF_VEC_ALLOC_O (pragma_ns_name, heap);
+
+static VEC(pragma_ns_name, heap) *registered_pp_pragmas;
+
+struct omp_pragma_def { const char *name; unsigned int id; };
+static const struct omp_pragma_def omp_pragmas[] = {
+  { "atomic", PRAGMA_OMP_ATOMIC },
+  { "barrier", PRAGMA_OMP_BARRIER },
+  { "critical", PRAGMA_OMP_CRITICAL },
+  { "flush", PRAGMA_OMP_FLUSH },
+  { "for", PRAGMA_OMP_FOR },
+  { "master", PRAGMA_OMP_MASTER },
+  { "ordered", PRAGMA_OMP_ORDERED },
+  { "parallel", PRAGMA_OMP_PARALLEL },
+  { "section", PRAGMA_OMP_SECTION },
+  { "sections", PRAGMA_OMP_SECTIONS },
+  { "single", PRAGMA_OMP_SINGLE },
+  { "task", PRAGMA_OMP_TASK },
+  { "taskwait", PRAGMA_OMP_TASKWAIT },
+  { "threadprivate", PRAGMA_OMP_THREADPRIVATE }
+};
+
+void
+c_pp_lookup_pragma (unsigned int id, const char **space, const char **name)
+{
+  const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas);
+  int i;
+
+  for (i = 0; i < n_omp_pragmas; ++i)
+    if (omp_pragmas[i].id == id)
+      {
+       *space = "omp";
+       *name = omp_pragmas[i].name;
+       return;
+      }
+
+  if (id >= PRAGMA_FIRST_EXTERNAL
+      && (id < PRAGMA_FIRST_EXTERNAL
+         + VEC_length (pragma_ns_name, registered_pp_pragmas)))
+    {
+      *space = VEC_index (pragma_ns_name, registered_pp_pragmas,
+                         id - PRAGMA_FIRST_EXTERNAL)->space;
+      *name = VEC_index (pragma_ns_name, registered_pp_pragmas,
+                        id - PRAGMA_FIRST_EXTERNAL)->name;
+      return;
+    }
+
+  gcc_unreachable ();
+}
+
 /* Front-end wrappers for pragma registration to avoid dragging
    cpplib.h in almost everywhere.  */
 
@@ -739,13 +1239,29 @@ c_register_pragma_1 (const char *space, const char *name,
 {
   unsigned id;
 
-  VEC_safe_push (pragma_handler, heap, registered_pragmas, &handler);
-  id = VEC_length (pragma_handler, registered_pragmas);
-  id += PRAGMA_FIRST_EXTERNAL - 1;
+  if (flag_preprocess_only)
+    {
+      pragma_ns_name ns_name;
+
+      if (!allow_expansion)
+       return;
+
+      ns_name.space = space;
+      ns_name.name = name;
+      VEC_safe_push (pragma_ns_name, heap, registered_pp_pragmas, &ns_name);
+      id = VEC_length (pragma_ns_name, registered_pp_pragmas);
+      id += PRAGMA_FIRST_EXTERNAL - 1;
+    }
+  else
+    {
+      VEC_safe_push (pragma_handler, heap, registered_pragmas, &handler);
+      id = VEC_length (pragma_handler, registered_pragmas);
+      id += PRAGMA_FIRST_EXTERNAL - 1;
 
-  /* The C++ front end allocates 6 bits in cp_token; the C front end
-     allocates 7 bits in c_token.  At present this is sufficient.  */
-  gcc_assert (id < 64);
+      /* The C++ front end allocates 6 bits in cp_token; the C front end
+        allocates 7 bits in c_token.  At present this is sufficient.  */
+      gcc_assert (id < 64);
+    }
 
   cpp_register_deferred_pragma (parse_in, space, name, id,
                                allow_expansion, false);
@@ -779,24 +1295,8 @@ c_invoke_pragma_handler (unsigned int id)
 void
 init_pragma (void)
 {
-  if (flag_openmp && !flag_preprocess_only)
-    {
-      struct omp_pragma_def { const char *name; unsigned int id; };
-      static const struct omp_pragma_def omp_pragmas[] = {
-       { "atomic", PRAGMA_OMP_ATOMIC },
-       { "barrier", PRAGMA_OMP_BARRIER },
-       { "critical", PRAGMA_OMP_CRITICAL },
-       { "flush", PRAGMA_OMP_FLUSH },
-       { "for", PRAGMA_OMP_FOR },
-       { "master", PRAGMA_OMP_MASTER },
-       { "ordered", PRAGMA_OMP_ORDERED },
-       { "parallel", PRAGMA_OMP_PARALLEL },
-       { "section", PRAGMA_OMP_SECTION },
-       { "sections", PRAGMA_OMP_SECTIONS },
-       { "single", PRAGMA_OMP_SINGLE },
-       { "threadprivate", PRAGMA_OMP_THREADPRIVATE }
-      };
-
+  if (flag_openmp)
+    {
       const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas);
       int i;
 
@@ -805,8 +1305,9 @@ init_pragma (void)
                                      omp_pragmas[i].id, true, true);
     }
 
-  cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess",
-                               PRAGMA_GCC_PCH_PREPROCESS, false, false);
+  if (!flag_preprocess_only)
+    cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess",
+                                 PRAGMA_GCC_PCH_PREPROCESS, false, false);
 
 #ifdef HANDLE_PRAGMA_PACK
 #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
@@ -815,6 +1316,10 @@ init_pragma (void)
   c_register_pragma (0, "pack", handle_pragma_pack);
 #endif
 #endif
+#ifdef HANDLE_PRAGMA_PUSH_POP_MACRO
+  c_register_pragma (0 ,"push_macro", handle_pragma_push_macro);
+  c_register_pragma (0 ,"pop_macro", handle_pragma_pop_macro);
+#endif
 #ifdef HANDLE_PRAGMA_WEAK
   c_register_pragma (0, "weak", handle_pragma_weak);
 #endif
@@ -823,10 +1328,17 @@ init_pragma (void)
 #endif
 
   c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic);
+  c_register_pragma ("GCC", "target", handle_pragma_target);
+  c_register_pragma ("GCC", "optimize", handle_pragma_optimize);
+  c_register_pragma ("GCC", "push_options", handle_pragma_push_options);
+  c_register_pragma ("GCC", "pop_options", handle_pragma_pop_options);
+  c_register_pragma ("GCC", "reset_options", handle_pragma_reset_options);
 
   c_register_pragma_with_expansion (0, "redefine_extname", handle_pragma_redefine_extname);
   c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);
 
+  c_register_pragma_with_expansion (0, "message", handle_pragma_message);
+
 #ifdef REGISTER_TARGET_PRAGMAS
   REGISTER_TARGET_PRAGMAS ();
 #endif