diff gcc/c-family/c-pragma.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents 561a7518be6b
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/c-family/c-pragma.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/c-family/c-pragma.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,6 +1,5 @@
 /* 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, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1992-2017 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,22 +20,17 @@
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
-#include "function.h"		/* For cfun.  FIXME: Does the parser know
-				   when it is inside a function, so that
-				   we don't have to look at cfun?  */
-#include "cpplib.h"
+#include "target.h"
+#include "function.h"		/* For cfun.  */
+#include "c-common.h"
+#include "memmodel.h"
+#include "tm_p.h"		/* For REGISTER_TARGET_PRAGMAS.  */
+#include "stringpool.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "attribs.h"
+#include "varasm.h"
 #include "c-pragma.h"
-#include "flags.h"
-#include "c-common.h"
-#include "output.h"
-#include "tm_p.h"		/* For REGISTER_TARGET_PRAGMAS (why is
-				   this not a target hook?).  */
-#include "vec.h"
-#include "vecprim.h"
-#include "target.h"
-#include "diagnostic.h"
 #include "opts.h"
 #include "plugin.h"
 
@@ -45,11 +39,11 @@
 #define GCC_BAD2(gmsgid, arg) \
   do { warning (OPT_Wpragmas, gmsgid, arg); return; } while (0)
 
-typedef struct GTY(()) align_stack {
+struct GTY(()) align_stack {
   int		       alignment;
   tree		       id;
   struct align_stack * prev;
-} align_stack;
+};
 
 static GTY(()) struct align_stack * alignment_stack;
 
@@ -72,9 +66,7 @@
 static void
 push_alignment (int alignment, tree id)
 {
-  align_stack * entry;
-
-  entry = ggc_alloc_align_stack ();
+  align_stack * entry = ggc_alloc<align_stack> ();
 
   entry->alignment  = alignment;
   entry->id	    = id;
@@ -223,6 +215,7 @@
 	    align = maximum_field_alignment;
 	    break;
 	  }
+	/* FALLTHRU */
       default:
 	GCC_BAD2 ("alignment must be a small power of two, not %d", align);
       }
@@ -235,16 +228,14 @@
     }
 }
 
-typedef struct GTY(()) pending_weak_d
+struct GTY(()) pending_weak
 {
   tree name;
   tree value;
-} pending_weak;
+};
 
-DEF_VEC_O(pending_weak);
-DEF_VEC_ALLOC_O(pending_weak,gc);
 
-static GTY(()) VEC(pending_weak,gc) *pending_weaks;
+static GTY(()) vec<pending_weak, va_gc> *pending_weaks;
 
 static void apply_pragma_weak (tree, tree);
 static void handle_pragma_weak (cpp_reader *);
@@ -263,6 +254,7 @@
 
   if (SUPPORTS_WEAK && DECL_EXTERNAL (decl) && TREE_USED (decl)
       && !DECL_WEAK (decl) /* Don't complain about a redundant #pragma.  */
+      && DECL_ASSEMBLER_NAME_SET_P (decl)
       && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
     warning (OPT_Wpragmas, "applying #pragma weak %q+D after first use "
 	     "results in unspecified behavior", decl);
@@ -280,7 +272,7 @@
   /* Avoid asking for DECL_ASSEMBLER_NAME when it's not needed.  */
 
   /* No weak symbols pending, take the short-cut.  */
-  if (!pending_weaks)
+  if (vec_safe_is_empty (pending_weaks))
     return;
   /* If it's not visible outside this file, it doesn't matter whether
      it's weak.  */
@@ -289,16 +281,22 @@
   /* If it's not a function or a variable, it can't be weak.
      FIXME: what kinds of things are visible outside this file but
      aren't functions or variables?   Should this be an assert instead?  */
-  if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)
+  if (!VAR_OR_FUNCTION_DECL_P (decl))
     return;
 
-  id = DECL_ASSEMBLER_NAME (decl);
+  if (DECL_ASSEMBLER_NAME_SET_P (decl))
+    id = DECL_ASSEMBLER_NAME (decl);
+  else
+    {
+      id = DECL_ASSEMBLER_NAME (decl);
+      SET_DECL_ASSEMBLER_NAME (decl, NULL_TREE);
+    }
 
-  FOR_EACH_VEC_ELT (pending_weak, pending_weaks, i, pe)
+  FOR_EACH_VEC_ELT (*pending_weaks, i, pe)
     if (id == pe->name)
       {
 	apply_pragma_weak (decl, pe->value);
-	VEC_unordered_remove (pending_weak, pending_weaks, i);
+	pending_weaks->unordered_remove (i);
 	break;
       }
 }
@@ -311,8 +309,12 @@
   tree alias_id, id, decl;
   int i;
   pending_weak *pe;
+  symtab_node *target;
 
-  FOR_EACH_VEC_ELT (pending_weak, pending_weaks, i, pe)
+  if (vec_safe_is_empty (pending_weaks))
+    return;
+
+  FOR_EACH_VEC_ELT (*pending_weaks, i, pe)
     {
       alias_id = pe->name;
       id = pe->value;
@@ -320,13 +322,22 @@
       if (id == NULL)
 	continue;
 
+      target = symtab_node::get_for_asmname (id);
       decl = build_decl (UNKNOWN_LOCATION,
-			 FUNCTION_DECL, alias_id, default_function_type);
+			 target ? TREE_CODE (target->decl) : FUNCTION_DECL,
+			 alias_id, default_function_type);
 
       DECL_ARTIFICIAL (decl) = 1;
       TREE_PUBLIC (decl) = 1;
-      DECL_EXTERNAL (decl) = 1;
       DECL_WEAK (decl) = 1;
+      if (VAR_P (decl))
+	TREE_STATIC (decl) = 1;
+      if (!target)
+	{
+	  error ("%q+D aliased to undefined symbol %qE",
+		 decl, id);
+	  continue;
+	}
 
       assemble_alias (decl, id);
     }
@@ -356,22 +367,85 @@
   decl = identifier_global_value (name);
   if (decl && DECL_P (decl))
     {
+      if (!VAR_OR_FUNCTION_DECL_P (decl))
+	GCC_BAD2 ("%<#pragma weak%> declaration of %q+D not allowed,"
+		  " ignored", decl);
       apply_pragma_weak (decl, value);
       if (value)
-	assemble_alias (decl, value);
+	{
+	  DECL_EXTERNAL (decl) = 0;
+	  if (VAR_P (decl))
+	    TREE_STATIC (decl) = 1;
+	  assemble_alias (decl, value);
+	}
     }
   else
     {
-      pending_weak *pe;
-      pe = VEC_safe_push (pending_weak, gc, pending_weaks, NULL);
-      pe->name = name;
-      pe->value = value;
+      pending_weak pe = {name, value};
+      vec_safe_push (pending_weaks, pe);
     }
 }
 
+static enum scalar_storage_order_kind global_sso;
+
+void
+maybe_apply_pragma_scalar_storage_order (tree type)
+{
+  if (global_sso == SSO_NATIVE)
+    return;
+
+  gcc_assert (RECORD_OR_UNION_TYPE_P (type));
+
+  if (lookup_attribute ("scalar_storage_order", TYPE_ATTRIBUTES (type)))
+    return;
+
+  if (global_sso == SSO_BIG_ENDIAN)
+    TYPE_REVERSE_STORAGE_ORDER (type) = !BYTES_BIG_ENDIAN;
+  else if (global_sso == SSO_LITTLE_ENDIAN)
+    TYPE_REVERSE_STORAGE_ORDER (type) = BYTES_BIG_ENDIAN;
+  else
+    gcc_unreachable ();
+}
+
+static void
+handle_pragma_scalar_storage_order (cpp_reader *ARG_UNUSED(dummy))
+{
+  const char *kind_string;
+  enum cpp_ttype token;
+  tree x;
+
+  if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+    {
+      error ("scalar_storage_order is not supported because endianness "
+	     "is not uniform");
+      return;
+    }
+
+  if (c_dialect_cxx ())
+    {
+      if (warn_unknown_pragmas > in_system_header_at (input_location))
+	warning (OPT_Wunknown_pragmas,
+		 "%<#pragma scalar_storage_order%> is not supported for C++");
+      return;
+    }
+
+  token = pragma_lex (&x);
+  if (token != CPP_NAME)
+    GCC_BAD ("missing [big-endian|little-endian|default] after %<#pragma scalar_storage_order%>");
+  kind_string = IDENTIFIER_POINTER (x);
+  if (strcmp (kind_string, "default") == 0)
+    global_sso = default_sso;
+  else if (strcmp (kind_string, "big") == 0)
+    global_sso = SSO_BIG_ENDIAN;
+  else if (strcmp (kind_string, "little") == 0)
+    global_sso = SSO_LITTLE_ENDIAN;
+  else
+    GCC_BAD ("expected [big-endian|little-endian|default] after %<#pragma scalar_storage_order%>");
+}
+
 /* GCC supports two #pragma directives for renaming the external
    symbol associated with a declaration (DECL_ASSEMBLER_NAME), for
-   compatibility with the Solaris and Tru64 system headers.  GCC also
+   compatibility with the Solaris and VMS system headers.  GCC also
    has its own notation for this, __asm__("name") annotations.
 
    Corner cases of these features and their interaction:
@@ -401,15 +475,13 @@
       if it appears afterward, we have no way of knowing whether a modified
       DECL_ASSEMBLER_NAME is due to #pragma extern_prefix.)  */
 
-typedef struct GTY(()) pending_redefinition_d {
+struct GTY(()) pending_redefinition {
   tree oldname;
   tree newname;
-} pending_redefinition;
+};
 
-DEF_VEC_O(pending_redefinition);
-DEF_VEC_ALLOC_O(pending_redefinition,gc);
 
-static GTY(()) VEC(pending_redefinition,gc) *pending_redefine_extname;
+static GTY(()) vec<pending_redefinition, va_gc> *pending_redefine_extname;
 
 static void handle_pragma_redefine_extname (cpp_reader *);
 
@@ -417,8 +489,9 @@
 static void
 handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy))
 {
-  tree oldname, newname, decl, x;
+  tree oldname, newname, decls, x;
   enum cpp_ttype t;
+  bool found;
 
   if (pragma_lex (&oldname) != CPP_NAME)
     GCC_BAD ("malformed #pragma redefine_extname, ignored");
@@ -428,26 +501,41 @@
   if (t != CPP_EOF)
     warning (OPT_Wpragmas, "junk at end of %<#pragma redefine_extname%>");
 
-  decl = identifier_global_value (oldname);
-  if (decl
-      && (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
-      && (TREE_CODE (decl) == FUNCTION_DECL
-	  || TREE_CODE (decl) == VAR_DECL)
-      && has_c_linkage (decl))
+  found = false;
+  for (decls = c_linkage_bindings (oldname);
+       decls; )
     {
-      if (DECL_ASSEMBLER_NAME_SET_P (decl))
+      tree decl;
+      if (TREE_CODE (decls) == TREE_LIST)
 	{
-	  const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-	  name = targetm.strip_name_encoding (name);
-
-	  if (strcmp (name, IDENTIFIER_POINTER (newname)))
-	    warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to "
-		     "conflict with previous rename");
+	  decl = TREE_VALUE (decls);
+	  decls = TREE_CHAIN (decls);
 	}
       else
-	change_decl_assembler_name (decl, newname);
+	{
+	  decl = decls;
+	  decls = NULL_TREE;
+	}
+
+      if ((TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
+	  && VAR_OR_FUNCTION_DECL_P (decl))
+	{
+	  found = true;
+	  if (DECL_ASSEMBLER_NAME_SET_P (decl))
+	    {
+	      const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+	      name = targetm.strip_name_encoding (name);
+
+	      if (!id_equal (newname, name))
+		warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to "
+			 "conflict with previous rename");
+	    }
+	  else
+	    symtab->change_decl_assembler_name (decl, newname);
+	}
     }
-  else
+
+  if (!found)
     /* We have to add this to the rename list even if there's already
        a global value that doesn't meet the above criteria, because in
        C++ "struct foo {...};" puts "foo" in the current namespace but
@@ -456,14 +544,14 @@
     add_to_renaming_pragma_list (oldname, newname);
 }
 
-/* This is called from here and from ia64.c.  */
+/* This is called from here and from ia64-c.c.  */
 void
 add_to_renaming_pragma_list (tree oldname, tree newname)
 {
   unsigned ix;
   pending_redefinition *p;
 
-  FOR_EACH_VEC_ELT (pending_redefinition, pending_redefine_extname, ix, p)
+  FOR_EACH_VEC_SAFE_ELT (pending_redefine_extname, ix, p)
     if (oldname == p->oldname)
       {
 	if (p->newname != newname)
@@ -472,33 +560,12 @@
 	return;
       }
 
-  p = VEC_safe_push (pending_redefinition, gc, pending_redefine_extname, NULL);
-  p->oldname = oldname;
-  p->newname = newname;
+  pending_redefinition e = {oldname, newname};
+  vec_safe_push (pending_redefine_extname, e);
 }
 
-static GTY(()) tree pragma_extern_prefix;
-
-/* #pragma extern_prefix "prefix" */
-static void
-handle_pragma_extern_prefix (cpp_reader * ARG_UNUSED (dummy))
-{
-  tree prefix, x;
-  enum cpp_ttype t;
-
-  if (pragma_lex (&prefix) != CPP_STRING)
-    GCC_BAD ("malformed #pragma extern_prefix, ignored");
-  t = pragma_lex (&x);
-  if (t != CPP_EOF)
-    warning (OPT_Wpragmas, "junk at end of %<#pragma extern_prefix%>");
-
-  if (targetm.handle_pragma_extern_prefix)
-    /* Note that the length includes the null terminator.  */
-    pragma_extern_prefix = (TREE_STRING_LENGTH (prefix) > 1 ? prefix : NULL);
-  else if (warn_unknown_pragmas > in_system_header)
-    warning (OPT_Wunknown_pragmas,
-	     "#pragma extern_prefix not supported on this target");
-}
+/* The current prefix set by #pragma extern_prefix.  */
+GTY(()) tree pragma_extern_prefix;
 
 /* Hook from the front ends to apply the results of one of the preceding
    pragmas that rename variables.  */
@@ -511,7 +578,7 @@
 
   /* The renaming pragmas are only applied to declarations with
      external linkage.  */
-  if ((TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)
+  if (!VAR_OR_FUNCTION_DECL_P (decl)
       || (!TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
       || !has_c_linkage (decl))
     return asmname;
@@ -528,28 +595,26 @@
 		   "conflict with previous rename");
 
       /* Take any pending redefine_extname off the list.  */
-      FOR_EACH_VEC_ELT (pending_redefinition, pending_redefine_extname, ix, p)
+      FOR_EACH_VEC_SAFE_ELT (pending_redefine_extname, ix, p)
 	if (DECL_NAME (decl) == p->oldname)
 	  {
 	    /* Only warn if there is a conflict.  */
-	    if (strcmp (IDENTIFIER_POINTER (p->newname), oldname))
+	    if (!id_equal (p->newname, oldname))
 	      warning (OPT_Wpragmas, "#pragma redefine_extname ignored due to "
 		       "conflict with previous rename");
 
-	    VEC_unordered_remove (pending_redefinition,
-				  pending_redefine_extname, ix);
+	    pending_redefine_extname->unordered_remove (ix);
 	    break;
 	  }
-      return 0;
+      return NULL_TREE;
     }
 
   /* Find out if we have a pending #pragma redefine_extname.  */
-  FOR_EACH_VEC_ELT (pending_redefinition, pending_redefine_extname, ix, p)
+  FOR_EACH_VEC_SAFE_ELT (pending_redefine_extname, ix, p)
     if (DECL_NAME (decl) == p->oldname)
       {
 	tree newname = p->newname;
-	VEC_unordered_remove (pending_redefinition,
-			      pending_redefine_extname, ix);
+	pending_redefine_extname->unordered_remove (ix);
 
 	/* If we already have an asmname, #pragma redefine_extname is
 	   ignored (with a warning if it conflicts).  */
@@ -590,13 +655,13 @@
     }
 
   /* Nada.  */
-  return 0;
+  return NULL_TREE;
 }
 
 
 static void handle_pragma_visibility (cpp_reader *);
 
-static VEC (int, heap) *visstack;
+static vec<int> visstack;
 
 /* Push the visibility indicated by STR onto the top of the #pragma
    visibility stack.  KIND is 0 for #pragma GCC visibility, 1 for
@@ -608,8 +673,7 @@
 void
 push_visibility (const char *str, int kind)
 {
-  VEC_safe_push (int, heap, visstack,
-		 ((int) default_visibility) | (kind << 8));
+  visstack.safe_push (((int) default_visibility) | (kind << 8));
   if (!strcmp (str, "default"))
     default_visibility = VISIBILITY_DEFAULT;
   else if (!strcmp (str, "internal"))
@@ -629,14 +693,14 @@
 bool
 pop_visibility (int kind)
 {
-  if (!VEC_length (int, visstack))
+  if (!visstack.length ())
     return false;
-  if ((VEC_last (int, visstack) >> 8) != kind)
+  if ((visstack.last () >> 8) != kind)
     return false;
   default_visibility
-    = (enum symbol_visibility) (VEC_pop (int, visstack) & 0xff);
+    = (enum symbol_visibility) (visstack.pop () & 0xff);
   visibility_options.inpragma
-    = VEC_length (int, visstack) != 0;
+    = visstack.length () != 0;
   return true;
 }
 
@@ -689,17 +753,19 @@
 static void
 handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
 {
-  const char *kind_string, *option_string;
-  unsigned int option_index;
-  enum cpp_ttype token;
+  tree x;
+  location_t loc;
+  enum cpp_ttype token = pragma_lex (&x, &loc);
+  if (token != CPP_NAME)
+    {
+      warning_at (loc, OPT_Wpragmas,
+		  "missing [error|warning|ignored|push|pop]"
+		  " after %<#pragma GCC diagnostic%>");
+      return;
+    }
+
   diagnostic_t kind;
-  tree x;
-  struct cl_option_handlers handlers;
-
-  token = pragma_lex (&x);
-  if (token != CPP_NAME)
-    GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>");
-  kind_string = IDENTIFIER_POINTER (x);
+  const char *kind_string = IDENTIFIER_POINTER (x);
   if (strcmp (kind_string, "error") == 0)
     kind = DK_ERROR;
   else if (strcmp (kind_string, "warning") == 0)
@@ -717,23 +783,62 @@
       return;
     }
   else
-    GCC_BAD ("expected [error|warning|ignored|push|pop] after %<#pragma GCC diagnostic%>");
+    {
+      warning_at (loc, OPT_Wpragmas,
+		  "expected [error|warning|ignored|push|pop]"
+		  " after %<#pragma GCC diagnostic%>");
+      return;
+    }
 
-  token = pragma_lex (&x);
+  token = pragma_lex (&x, &loc);
   if (token != CPP_STRING)
-    GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind");
-  option_string = TREE_STRING_POINTER (x);
-  set_default_handlers (&handlers);
-  for (option_index = 0; option_index < cl_options_count; option_index++)
-    if (strcmp (cl_options[option_index].opt_text, option_string) == 0)
-      {
-	control_warning_option (option_index, (int) kind, kind != DK_IGNORED,
-				input_location, c_family_lang_mask, &handlers,
-				&global_options, &global_options_set,
-				global_dc);
-	return;
-      }
-  GCC_BAD ("unknown option after %<#pragma GCC diagnostic%> kind");
+    {
+      warning_at (loc, OPT_Wpragmas,
+		  "missing option after %<#pragma GCC diagnostic%> kind");
+      return;
+    }
+
+  const char *option_string = TREE_STRING_POINTER (x);
+  unsigned int lang_mask = c_common_option_lang_mask () | CL_COMMON;
+  /* option_string + 1 to skip the initial '-' */
+  unsigned int option_index = find_opt (option_string + 1, lang_mask);
+  if (option_index == OPT_SPECIAL_unknown)
+    {
+      warning_at (loc, OPT_Wpragmas,
+		  "unknown option after %<#pragma GCC diagnostic%> kind");
+      return;
+    }
+  else if (!(cl_options[option_index].flags & CL_WARNING))
+    {
+      warning_at (loc, OPT_Wpragmas,
+		  "%qs is not an option that controls warnings", option_string);
+      return;
+    }
+  else if (!(cl_options[option_index].flags & lang_mask))
+    {
+      char *ok_langs = write_langs (cl_options[option_index].flags);
+      char *bad_lang = write_langs (c_common_option_lang_mask ());
+      warning_at (loc, OPT_Wpragmas,
+		  "option %qs is valid for %s but not for %s",
+		  option_string, ok_langs, bad_lang);
+      free (ok_langs);
+      free (bad_lang);
+      return;
+    }
+
+  struct cl_option_handlers handlers;
+  set_default_handlers (&handlers, NULL);
+  const char *arg = NULL;
+  if (cl_options[option_index].flags & CL_JOINED)
+    arg = option_string + 1 + cl_options[option_index].opt_len;
+  /* FIXME: input_location isn't the best location here, but it is
+     what we used to do here before and changing it breaks e.g.
+     PR69543 and PR69558.  */
+  control_warning_option (option_index, (int) kind,
+			  arg, kind != DK_IGNORED,
+			  input_location, lang_mask, &handlers,
+			  &global_options, &global_options_set,
+			  global_dc);
 }
 
 /*  Parse #pragma GCC target (xxx) to set target specific options.  */
@@ -800,7 +905,7 @@
       args = nreverse (args);
 
       if (targetm.target_option.pragma_parse (args, NULL_TREE))
-	current_target_pragma = args;
+	current_target_pragma = chainon (current_target_pragma, args);
     }
 }
 
@@ -869,7 +974,7 @@
 
       parse_optimize_options (args, false);
       current_optimize_pragma = chainon (current_optimize_pragma, args);
-      optimization_current_node = build_optimization_node ();
+      optimization_current_node = build_optimization_node (&global_options);
       c_cpp_builtins_optimize_pragma (parse_in,
 				      optimization_previous_node,
 				      optimization_current_node);
@@ -879,13 +984,13 @@
 /* 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 GTY(()) opt_stack {
+struct GTY(()) opt_stack {
   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;
 
@@ -897,7 +1002,6 @@
 {
   enum cpp_ttype token;
   tree x = 0;
-  opt_stack *p;
 
   token = pragma_lex (&x);
   if (token != CPP_EOF)
@@ -906,13 +1010,13 @@
       return;
     }
 
-  p = ggc_alloc_opt_stack ();
+  opt_stack *p = ggc_alloc<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 ();
+  p->optimize_binary = build_optimization_node (&global_options);
+  p->target_binary = build_target_option_node (&global_options);
 
   /* Save optimization and target flags in string list format.  */
   p->optimize_strings = copy_list (current_optimize_pragma);
@@ -1114,7 +1218,7 @@
 {
   if (c_dialect_cxx ())
     {
-      if (warn_unknown_pragmas > in_system_header)
+      if (warn_unknown_pragmas > in_system_header_at (input_location))
 	warning (OPT_Wunknown_pragmas,
 		 "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported"
 		 " for C++");
@@ -1123,14 +1227,14 @@
 
   if (!targetm.decimal_float_supported_p ())
     {
-      if (warn_unknown_pragmas > in_system_header)
+      if (warn_unknown_pragmas > in_system_header_at (input_location))
 	warning (OPT_Wunknown_pragmas,
 		 "%<#pragma STDC FLOAT_CONST_DECIMAL64%> is not supported"
 		 " on this target");
       return;
     }
 
-  pedwarn (input_location, OPT_pedantic,
+  pedwarn (input_location, OPT_Wpedantic,
 	   "ISO C does not support %<#pragma STDC FLOAT_CONST_DECIMAL64%>");
 
   switch (handle_stdc_pragma ("STDC FLOAT_CONST_DECIMAL64"))
@@ -1147,48 +1251,82 @@
     }
 }
 
-/* A vector of registered pragma callbacks.  */
+/* A vector of registered pragma callbacks, which is never freed.   */
 
-DEF_VEC_O (pragma_handler);
-DEF_VEC_ALLOC_O (pragma_handler, heap);
+static vec<internal_pragma_handler> registered_pragmas;
 
-static VEC(pragma_handler, heap) *registered_pragmas;
-
-typedef struct
+struct pragma_ns_name
 {
   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;
+static vec<pragma_ns_name> registered_pp_pragmas;
 
 struct omp_pragma_def { const char *name; unsigned int id; };
+static const struct omp_pragma_def oacc_pragmas[] = {
+  { "atomic", PRAGMA_OACC_ATOMIC },
+  { "cache", PRAGMA_OACC_CACHE },
+  { "data", PRAGMA_OACC_DATA },
+  { "declare", PRAGMA_OACC_DECLARE },
+  { "enter", PRAGMA_OACC_ENTER_DATA },
+  { "exit", PRAGMA_OACC_EXIT_DATA },
+  { "host_data", PRAGMA_OACC_HOST_DATA },
+  { "kernels", PRAGMA_OACC_KERNELS },
+  { "loop", PRAGMA_OACC_LOOP },
+  { "parallel", PRAGMA_OACC_PARALLEL },
+  { "routine", PRAGMA_OACC_ROUTINE },
+  { "update", PRAGMA_OACC_UPDATE },
+  { "wait", PRAGMA_OACC_WAIT }
+};
 static const struct omp_pragma_def omp_pragmas[] = {
   { "atomic", PRAGMA_OMP_ATOMIC },
   { "barrier", PRAGMA_OMP_BARRIER },
+  { "cancel", PRAGMA_OMP_CANCEL },
+  { "cancellation", PRAGMA_OMP_CANCELLATION_POINT },
   { "critical", PRAGMA_OMP_CRITICAL },
+  { "end", PRAGMA_OMP_END_DECLARE_TARGET },
   { "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 },
+  { "taskgroup", PRAGMA_OMP_TASKGROUP },
   { "taskwait", PRAGMA_OMP_TASKWAIT },
+  { "taskyield", PRAGMA_OMP_TASKYIELD },
   { "threadprivate", PRAGMA_OMP_THREADPRIVATE }
 };
+static const struct omp_pragma_def omp_pragmas_simd[] = {
+  { "declare", PRAGMA_OMP_DECLARE },
+  { "distribute", PRAGMA_OMP_DISTRIBUTE },
+  { "for", PRAGMA_OMP_FOR },
+  { "ordered", PRAGMA_OMP_ORDERED },
+  { "parallel", PRAGMA_OMP_PARALLEL },
+  { "simd", PRAGMA_OMP_SIMD },
+  { "target", PRAGMA_OMP_TARGET },
+  { "taskloop", PRAGMA_OMP_TASKLOOP },
+  { "teams", PRAGMA_OMP_TEAMS },
+};
 
 void
 c_pp_lookup_pragma (unsigned int id, const char **space, const char **name)
 {
+  const int n_oacc_pragmas = sizeof (oacc_pragmas) / sizeof (*oacc_pragmas);
   const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas);
+  const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd)
+				 / sizeof (*omp_pragmas);
   int i;
 
+  for (i = 0; i < n_oacc_pragmas; ++i)
+    if (oacc_pragmas[i].id == id)
+      {
+	*space = "acc";
+	*name = oacc_pragmas[i].name;
+	return;
+      }
+
   for (i = 0; i < n_omp_pragmas; ++i)
     if (omp_pragmas[i].id == id)
       {
@@ -1197,14 +1335,33 @@
 	return;
       }
 
-  if (id >= PRAGMA_FIRST_EXTERNAL
-      && (id < PRAGMA_FIRST_EXTERNAL
-	  + VEC_length (pragma_ns_name, registered_pp_pragmas)))
+  for (i = 0; i < n_omp_pragmas_simd; ++i)
+    if (omp_pragmas_simd[i].id == id)
+      {
+	*space = "omp";
+	*name = omp_pragmas_simd[i].name;
+	return;
+      }
+
+  if (id == PRAGMA_CILK_SIMD)
     {
-      *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;
+      *space = NULL;
+      *name = "simd";
+      return;
+    }
+
+  if (id == PRAGMA_CILK_GRAINSIZE)
+    {
+      *space = "cilk";
+      *name = "grainsize";
+      return;
+    }
+
+  if (id >= PRAGMA_FIRST_EXTERNAL
+      && (id < PRAGMA_FIRST_EXTERNAL + registered_pp_pragmas.length ()))
+    {
+      *space = registered_pp_pragmas[id - PRAGMA_FIRST_EXTERNAL].space;
+      *name = registered_pp_pragmas[id - PRAGMA_FIRST_EXTERNAL].name;
       return;
     }
 
@@ -1216,7 +1373,7 @@
 
 static void
 c_register_pragma_1 (const char *space, const char *name,
-		     pragma_handler handler, bool allow_expansion)
+                     internal_pragma_handler ihandler, bool allow_expansion)
 {
   unsigned id;
 
@@ -1229,53 +1386,132 @@
 
       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);
+      registered_pp_pragmas.safe_push (ns_name);
+      id = registered_pp_pragmas.length ();
       id += PRAGMA_FIRST_EXTERNAL - 1;
     }
   else
     {
-      VEC_safe_push (pragma_handler, heap, registered_pragmas, &handler);
-      id = VEC_length (pragma_handler, registered_pragmas);
+      registered_pragmas.safe_push (ihandler);
+      id = registered_pragmas.length ();
       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 8 bits in c_token.  The C++ front end
+	 keeps the pragma kind in the form of INTEGER_CST, so no small
+	 limit applies.  At present this is sufficient.  */
+      gcc_assert (id < 256);
     }
 
   cpp_register_deferred_pragma (parse_in, space, name, id,
 				allow_expansion, false);
 }
 
+/* Register a C pragma handler, using a space and a name.  It disallows pragma
+   expansion (if you want it, use c_register_pragma_with_expansion instead).  */
 void
-c_register_pragma (const char *space, const char *name, pragma_handler handler)
+c_register_pragma (const char *space, const char *name,
+                   pragma_handler_1arg handler)
 {
-  c_register_pragma_1 (space, name, handler, false);
+  internal_pragma_handler ihandler;
+
+  ihandler.handler.handler_1arg = handler;
+  ihandler.extra_data = false;
+  ihandler.data = NULL;
+  c_register_pragma_1 (space, name, ihandler, false);
+}
+
+/* Register a C pragma handler, using a space and a name, it also carries an
+   extra data field which can be used by the handler.  It disallows pragma
+   expansion (if you want it, use c_register_pragma_with_expansion_and_data
+   instead).  */
+void
+c_register_pragma_with_data (const char *space, const char *name,
+                             pragma_handler_2arg handler, void * data)
+{
+  internal_pragma_handler ihandler;
+
+  ihandler.handler.handler_2arg = handler;
+  ihandler.extra_data = true;
+  ihandler.data = data;
+  c_register_pragma_1 (space, name, ihandler, false);
 }
 
+/* Register a C pragma handler, using a space and a name.  It allows pragma
+   expansion as in the following example:
+
+   #define NUMBER 10
+   #pragma count (NUMBER)
+
+   Name expansion is still disallowed.  */
 void
 c_register_pragma_with_expansion (const char *space, const char *name,
-				  pragma_handler handler)
+				  pragma_handler_1arg handler)
 {
-  c_register_pragma_1 (space, name, handler, true);
+  internal_pragma_handler ihandler;
+
+  ihandler.handler.handler_1arg = handler;
+  ihandler.extra_data = false;
+  ihandler.data = NULL;
+  c_register_pragma_1 (space, name, ihandler, true);
+}
+
+/* Register a C pragma handler, using a space and a name, it also carries an
+   extra data field which can be used by the handler.  It allows pragma
+   expansion as in the following example:
+
+   #define NUMBER 10
+   #pragma count (NUMBER)
+
+   Name expansion is still disallowed.  */
+void
+c_register_pragma_with_expansion_and_data (const char *space, const char *name,
+                                           pragma_handler_2arg handler,
+                                           void *data)
+{
+  internal_pragma_handler ihandler;
+
+  ihandler.handler.handler_2arg = handler;
+  ihandler.extra_data = true;
+  ihandler.data = data;
+  c_register_pragma_1 (space, name, ihandler, true);
 }
 
 void
 c_invoke_pragma_handler (unsigned int id)
 {
-  pragma_handler handler;
+  internal_pragma_handler *ihandler;
+  pragma_handler_1arg handler_1arg;
+  pragma_handler_2arg handler_2arg;
 
   id -= PRAGMA_FIRST_EXTERNAL;
-  handler = *VEC_index (pragma_handler, registered_pragmas, id);
-
-  handler (parse_in);
+  ihandler = &registered_pragmas[id];
+  if (ihandler->extra_data)
+    {
+      handler_2arg = ihandler->handler.handler_2arg;
+      handler_2arg (parse_in, ihandler->data);
+    }
+  else
+    {
+      handler_1arg = ihandler->handler.handler_1arg;
+      handler_1arg (parse_in);
+    }
 }
 
 /* Set up front-end pragmas.  */
 void
 init_pragma (void)
 {
+  if (flag_openacc)
+    {
+      const int n_oacc_pragmas
+	= sizeof (oacc_pragmas) / sizeof (*oacc_pragmas);
+      int i;
+
+      for (i = 0; i < n_oacc_pragmas; ++i)
+	cpp_register_deferred_pragma (parse_in, "acc", oacc_pragmas[i].name,
+				      oacc_pragmas[i].id, true, true);
+    }
+
   if (flag_openmp)
     {
       const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas);
@@ -1285,17 +1521,40 @@
 	cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas[i].name,
 				      omp_pragmas[i].id, true, true);
     }
+  if (flag_openmp || flag_openmp_simd)
+    {
+      const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd)
+				     / sizeof (*omp_pragmas);
+      int i;
+
+      for (i = 0; i < n_omp_pragmas_simd; ++i)
+	cpp_register_deferred_pragma (parse_in, "omp", omp_pragmas_simd[i].name,
+				      omp_pragmas_simd[i].id, true, true);
+    }
+
+  if (flag_cilkplus)
+    cpp_register_deferred_pragma (parse_in, NULL, "simd", PRAGMA_CILK_SIMD,
+				  true, false);
 
   if (!flag_preprocess_only)
     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", "ivdep", PRAGMA_IVDEP, false,
+				  false);
+
+  if (flag_cilkplus)
+    cpp_register_deferred_pragma (parse_in, "cilk", "grainsize",
+				  PRAGMA_CILK_GRAINSIZE, true, false);
+
 #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
   c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
 #else
   c_register_pragma (0, "pack", handle_pragma_pack);
 #endif
   c_register_pragma (0, "weak", handle_pragma_weak);
+
   c_register_pragma ("GCC", "visibility", handle_pragma_visibility);
 
   c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic);
@@ -1308,8 +1567,8 @@
   c_register_pragma ("STDC", "FLOAT_CONST_DECIMAL64",
 		     handle_pragma_float_const_decimal64);
 
-  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, "redefine_extname",
+				    handle_pragma_redefine_extname);
 
   c_register_pragma_with_expansion (0, "message", handle_pragma_message);
 
@@ -1317,6 +1576,10 @@
   REGISTER_TARGET_PRAGMAS ();
 #endif
 
+  global_sso = default_sso;
+  c_register_pragma (0, "scalar_storage_order", 
+		     handle_pragma_scalar_storage_order);
+
   /* Allow plugins to register their own pragmas. */
   invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULL);
 }