Patchwork [gomp4] Fix up #pragma omp declare simd parsing

login
register
mail settings
Submitter Jakub Jelinek
Date July 1, 2013, 12:18 p.m.
Message ID <20130701121852.GX2336@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/256102/
State New
Headers show

Comments

Jakub Jelinek - July 1, 2013, 12:18 p.m.
Hi!

The latest OpenMP 4.0 wording says:
"The expressions appearing in the clauses of this directive are evaluated in the scope of
the arguments of the function declaration or definition."
so the current implementation of parsing all the clauses
at the place where they appear and just don't lookup the decls of the
clauses doesn't work properly.  This patch adjusts it so that we just
remember the tokens of #pragma omp declare simd directive, and parse it
during cp_parser_direct_declarator when the arguments are in scope (and also
any template arguments etc.).

Jason, does this look ok?

2013-07-01  Jakub Jelinek  <jakub@redhat.com>

	* tree.h (omp_declare_simd_clauses_equal): Remove prototype.
	(omp_remove_redundant_declare_simd_attrs): New prototype.
	* tree.c (omp_declare_simd_clauses_equal): Make static.
	(omp_remove_redundant_declare_simd_attrs): New function.
c/
	* c-typeck.c (c_finish_omp_declare_simd): Don't remove
	redundant "omp declare simd" clauses here.  Adjust
	c_omp_declare_simd_clauses_to_numbers caller.
cp/
	* decl.c (declare_simd_adjust_this): New function.
	(grokfndecl): Remove omp_declare_simd_clauses argument.
	Don't call finish_omp_declare_simd, instead just call
	c_omp_declare_simd_clauses_to_numbers.
	(grokdeclarator): Don't pass omp_declare_simd_clauses to
	grokfndecl.
	* parser.c (cp_ensure_no_omp_declare_simd): Adjust for
	change from omp_declare_simd_clauses vector to omp_declare_simd
	pointer.
	(cp_finish_omp_declare_simd): Renamed to...
	(cp_finalize_omp_declare_simd): ... this.  Adjust for
	change from omp_declare_simd_clauses vector to omp_declare_simd
	pointer, remove declspecs argument.
	(cp_parser_init_declarator, cp_parser_member_declaration,
	cp_parser_function_definition_from_specifiers_and_declarator,
	cp_parser_save_member_function_body): Don't copy
	omp_declare_simd_clauses vector to declspecs.  Call
	cp_finalize_omp_declare_simd instead of cp_finish_omp_declare_simd.
	(cp_parser_direct_declarator): Before calling make_call_declarator
	on cdk_id declarator, call cp_finish_omp_declare_simd.
	(cp_parser_omp_var_list_no_open): Don't special-case lookup in
	omp declare simd clauses.
	(OMP_DECLARE_SIMD_CLAUSE_MASK): Remove OMP_CLAUSE_REDUCTION.
	(cp_parser_omp_declare_simd): Don't set up omp_declare_simd_clauses
	vector, don't parse omp clauses here.  Instead remember tokens
	from #pragma omp declare simd till end of pragma line and populate
	omp_declare_simd_data structure.
	(cp_finish_omp_declare_simd): New function.
	* pt.c (apply_late_template_attributes): Adjust
	c_omp_declare_simd_clauses_to_numbers caller.
	* cp-tree.h (struct cp_decl_specifier_seq): Remove
	omp_declare_simd_clauses field.
	(finish_omp_declare_simd): Remove.
	* parser.h (cp_omp_declare_simd_data): New structure.
	(struct cp_parser): Remove omp_declare_simd_clauses field,
	add omp_declare_simd field instead.
	* semantics.c (finish_omp_declare_simd): Remove.
c-family/
	* c-omp.c (c_omp_declare_simd_clauses_to_numbers): Change first
	argument from a fndecl to its parms.
testsuite/
	* g++.dg/gomp/declare-simd-1.C: Add some new tests.
	* g++.dg/gomp/declare-simd-2.C: Remove a test that should no longer
	fail, adjust fn11 error locus, add new tests.



	Jakub
Jason Merrill - July 14, 2013, 12:33 a.m.
On 07/01/2013 05:18 AM, Jakub Jelinek wrote:
> 	(cp_finish_omp_declare_simd): Renamed to...
> 	(cp_finalize_omp_declare_simd): ... this.  Adjust for
...
> 	(cp_finish_omp_declare_simd): New function.

So now we have "finish" and "finalize"; please choose more distinct 
names.  Instead of "finish", perhaps 
cp_parser_late_parsing_omp_declare_simd to match other deferred parsing 
functions.

> +  tree save_ccp = current_class_ptr;
> +  tree save_ccr = current_class_ref;
> +  if (quals >= 0)
> +    inject_this_parameter (current_class_type, quals);

Let's share this code with the trailing-return-type rather than 
duplicate it.  Perhaps by changing cp_parser_late_return_opt to handle 
both the trailing return type and omp declare simd.

>         (omp_remove_redundant_declare_simd_attrs): New function.

This doesn't seem to be used anywhere.

Jason

Patch

--- gcc/c/c-typeck.c.jj	2013-06-26 12:13:51.000000000 +0200
+++ gcc/c/c-typeck.c	2013-07-01 12:19:58.399171019 +0200
@@ -11150,16 +11150,7 @@  c_finish_omp_declare_simd (tree fndecl,
 	    pc = &OMP_CLAUSE_CHAIN (c);
 	}
       cl = c_finish_omp_clauses (cl);
-      tree saved_arguments = DECL_ARGUMENTS (fndecl);
-      DECL_ARGUMENTS (fndecl) = parms;
-      cl = c_omp_declare_simd_clauses_to_numbers (fndecl, cl);
-      DECL_ARGUMENTS (fndecl) = saved_arguments;
-      for (c = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (fndecl));
-	   c; c = lookup_attribute ("omp declare simd", TREE_CHAIN (c)))
-	if (omp_declare_simd_clauses_equal (TREE_VALUE (c), cl))
-	  break;
-      if (c)
-	continue;
+      cl = c_omp_declare_simd_clauses_to_numbers (parms, cl);
       c = build_tree_list (get_identifier ("omp declare simd"), cl);
       TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
       DECL_ATTRIBUTES (fndecl) = c;
--- gcc/tree.h.jj	2013-06-28 17:56:45.000000000 +0200
+++ gcc/tree.h	2013-07-01 12:19:42.369439517 +0200
@@ -5100,9 +5100,8 @@  extern tree build_type_attribute_variant
 extern tree build_decl_attribute_variant (tree, tree);
 extern tree build_type_attribute_qual_variant (tree, tree, int);
 
-/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
-   the same.  */
-extern bool omp_declare_simd_clauses_equal (tree, tree);
+/* Remove redundant "omp declare simd" attributes from fndecl.  */
+extern void omp_remove_redundant_declare_simd_attrs (tree);
 
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
--- gcc/cp/decl.c.jj	2013-06-28 17:53:49.692430032 +0200
+++ gcc/cp/decl.c	2013-07-01 12:24:59.897094138 +0200
@@ -7299,6 +7299,22 @@  check_static_quals (tree decl, cp_cv_qua
 	   decl);
 }
 
+/* Helper function.  Replace the temporary this parameter injected
+   during cp_finish_omp_declare_simd with the real this parameter.  */
+
+static tree
+declare_simd_adjust_this (tree *tp, int *walk_subtrees, void *data)
+{
+  tree this_parm = (tree) data;
+  if (TREE_CODE (*tp) == PARM_DECL
+      && DECL_NAME (*tp) == this_identifier
+      && *tp != this_parm)
+    *tp = this_parm;
+  else if (TYPE_P (*tp))
+    *walk_subtrees = 0;
+  return NULL_TREE;
+}
+
 /* CTYPE is class type, or null if non-class.
    TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE
    or METHOD_TYPE.
@@ -7337,8 +7353,7 @@  grokfndecl (tree ctype,
 	    int template_count,
 	    tree in_namespace,
 	    tree* attrlist,
-	    location_t location,
-	    vec<tree, va_gc> *omp_declare_simd_clauses)
+	    location_t location)
 {
   tree decl;
   int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
@@ -7627,8 +7642,25 @@  grokfndecl (tree ctype,
   if (TYPE_NOTHROW_P (type) || nothrow_libfn_p (decl))
     TREE_NOTHROW (decl) = 1;
 
-  if (omp_declare_simd_clauses)
-    finish_omp_declare_simd (decl, omp_declare_simd_clauses);
+  if (flag_openmp)
+    {
+      /* Adjust "omp declare simd" attributes.  */
+      tree ods = lookup_attribute ("omp declare simd", *attrlist);
+      if (ods)
+	{
+	  tree attr;
+	  for (attr = ods; attr;
+	       attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr)))
+	    {
+	      if (TREE_CODE (type) == METHOD_TYPE)
+		walk_tree (&TREE_VALUE (attr), declare_simd_adjust_this,
+			   DECL_ARGUMENTS (decl), NULL);
+	      TREE_VALUE (attr)
+		= c_omp_declare_simd_clauses_to_numbers (DECL_ARGUMENTS (decl),
+							 TREE_VALUE (attr));
+	    }
+	}
+    }
 
   /* Caller will do the rest of this.  */
   if (check < 0)
@@ -10494,8 +10526,7 @@  grokdeclarator (const cp_declarator *dec
                                inlinep | (2 * constexpr_p),
 			       sfk,
 			       funcdef_flag, template_count, in_namespace,
-			       attrlist, declarator->id_loc,
-			       declspecs->omp_declare_simd_clauses);
+			       attrlist, declarator->id_loc);
             decl = set_virt_specifiers (decl, virt_specifiers);
 	    if (decl == NULL_TREE)
 	      return error_mark_node;
@@ -10708,8 +10739,7 @@  grokdeclarator (const cp_declarator *dec
 			   publicp, inlinep | (2 * constexpr_p), sfk,
                            funcdef_flag,
 			   template_count, in_namespace, attrlist,
-			   declarator->id_loc,
-			   declspecs->omp_declare_simd_clauses);
+			   declarator->id_loc);
 	if (decl == NULL_TREE)
 	  return error_mark_node;
 
--- gcc/cp/parser.c.jj	2013-06-28 17:53:57.120344205 +0200
+++ gcc/cp/parser.c	2013-07-01 12:47:19.052508557 +0200
@@ -1227,12 +1227,11 @@  cp_token_cache_new (cp_token *first, cp_
 static inline void
 cp_ensure_no_omp_declare_simd (cp_parser *parser)
 {
-  if (parser->omp_declare_simd_clauses
-      && (*parser->omp_declare_simd_clauses)[0] != error_mark_node)
+  if (parser->omp_declare_simd && !parser->omp_declare_simd->error_seen)
     {
       error ("%<#pragma omp declare simd%> not immediately followed by "
 	     "function declaration or definition");
-      parser->omp_declare_simd_clauses = NULL;
+      parser->omp_declare_simd = NULL;
     }
 }
 
@@ -1240,14 +1239,13 @@  cp_ensure_no_omp_declare_simd (cp_parser
    and put that into "omp declare simd" attribute.  */
 
 static inline void
-cp_finish_omp_declare_simd (cp_parser *parser,
-			    cp_decl_specifier_seq *declspecs, tree fndecl)
+cp_finalize_omp_declare_simd (cp_parser *parser, tree fndecl)
 {
-  if (__builtin_expect (parser->omp_declare_simd_clauses != NULL, 0))
+  if (__builtin_expect (parser->omp_declare_simd != NULL, 0))
     {
       if (fndecl == error_mark_node)
 	{
-	  parser->omp_declare_simd_clauses = NULL;
+	  parser->omp_declare_simd = NULL;
 	  return;
 	}
       if (TREE_CODE (fndecl) != FUNCTION_DECL)
@@ -1256,7 +1254,6 @@  cp_finish_omp_declare_simd (cp_parser *p
 	  return;
 	}
     }
-  declspecs->omp_declare_simd_clauses = NULL;
 }
 
 /* Decl-specifiers.  */
@@ -2100,6 +2097,9 @@  static vec<constructor_elt, va_gc> *cp_p
 static bool cp_parser_ctor_initializer_opt_and_function_body
   (cp_parser *, bool);
 
+static tree cp_finish_omp_declare_simd
+  (cp_parser *, tree, cp_cv_quals);
+
 /* Classes [gram.class] */
 
 static tree cp_parser_class_name
@@ -16504,12 +16504,10 @@  cp_parser_init_declarator (cp_parser* pa
     {
       if (parser->in_unbraced_linkage_specification_p)
 	decl_specifiers->storage_class = sc_extern;
-      decl_specifiers->omp_declare_simd_clauses
-	= parser->omp_declare_simd_clauses;
       decl = start_decl (declarator, decl_specifiers,
 			 range_for_decl_p? SD_INITIALIZED : is_initialized,
 			 attributes, prefix_attributes, &pushed_scope);
-      cp_finish_omp_declare_simd (parser, decl_specifiers, decl);
+      cp_finalize_omp_declare_simd (parser, decl);
       /* Adjust location of decl if declarator->id_loc is more appropriate:
 	 set, and decl wasn't merged with another decl, in which case its
 	 location would be different from input_location, and more accurate.  */
@@ -16613,14 +16611,12 @@  cp_parser_init_declarator (cp_parser* pa
 	  pop_scope (pushed_scope);
 	  pushed_scope = NULL_TREE;
 	}
-      decl_specifiers->omp_declare_simd_clauses
-	= parser->omp_declare_simd_clauses;
       decl = grokfield (declarator, decl_specifiers,
 			initializer, !is_non_constant_init,
 			/*asmspec=*/NULL_TREE, prefix_attributes);
       if (decl && TREE_CODE (decl) == FUNCTION_DECL)
 	cp_parser_save_default_args (parser, decl);
-      cp_finish_omp_declare_simd (parser, decl_specifiers, decl);
+      cp_finalize_omp_declare_simd (parser, decl);
     }
 
   /* Finish processing the declaration.  But, skip member
@@ -16924,6 +16920,14 @@  cp_parser_direct_declarator (cp_parser*
 		  late_return = (cp_parser_late_return_type_opt
 				 (parser, memfn ? cv_quals : -1));
 
+		  if (parser->omp_declare_simd
+		      && declarator
+		      && declarator->kind == cdk_id)
+		    declarator->std_attributes
+		      = cp_finish_omp_declare_simd (parser,
+						    declarator->std_attributes,
+						    memfn ? cv_quals : -1);
+
 		  /* Parse the virt-specifier-seq.  */
 		  virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
 
@@ -20151,14 +20155,12 @@  cp_parser_member_declaration (cp_parser*
 		if (declarator->kind == cdk_function)
 		  declarator->id_loc = token->location;
 	      /* Create the declaration.  */
-	      decl_specifiers.omp_declare_simd_clauses
-		= parser->omp_declare_simd_clauses;
 	      decl = grokfield (declarator, &decl_specifiers,
 				initializer, /*init_const_expr_p=*/true,
 				asm_specification, attributes);
 	    }
 
-	  cp_finish_omp_declare_simd (parser, &decl_specifiers, decl);
+	  cp_finalize_omp_declare_simd (parser, decl);
 
 	  /* Reset PREFIX_ATTRIBUTES.  */
 	  while (attributes && TREE_CHAIN (attributes) != first_attribute)
@@ -22293,8 +22295,6 @@  cp_parser_function_definition_from_speci
   bool success_p;
 
   /* Begin the function-definition.  */
-  decl_specifiers->omp_declare_simd_clauses
-    = parser->omp_declare_simd_clauses;
   success_p = start_function (decl_specifiers, declarator, attributes);
 
   /* The things we're about to see are not directly qualified by any
@@ -22309,15 +22309,13 @@  cp_parser_function_definition_from_speci
 
   if (success_p)
     {
-      cp_finish_omp_declare_simd (parser, decl_specifiers,
-				  current_function_decl);
-      parser->omp_declare_simd_clauses = NULL;
+      cp_finalize_omp_declare_simd (parser, current_function_decl);
+      parser->omp_declare_simd = NULL;
     }
 
   if (!success_p)
     {
       /* Skip the entire function.  */
-      decl_specifiers->omp_declare_simd_clauses = NULL;
       cp_parser_skip_to_end_of_block_or_statement (parser);
       fn = error_mark_node;
     }
@@ -22848,10 +22846,8 @@  cp_parser_save_member_function_body (cp_
   tree fn;
 
   /* Create the FUNCTION_DECL.  */
-  decl_specifiers->omp_declare_simd_clauses
-    = parser->omp_declare_simd_clauses;
   fn = grokmethod (decl_specifiers, declarator, attributes);
-  cp_finish_omp_declare_simd (parser, decl_specifiers, fn);
+  cp_finalize_omp_declare_simd (parser, fn);
   /* If something went badly wrong, bail out now.  */
   if (fn == error_mark_node)
     {
@@ -26592,20 +26588,15 @@  cp_parser_omp_var_list_no_open (cp_parse
       tree name, decl;
 
       token = cp_lexer_peek_token (parser->lexer);
-      if (parser->omp_declare_simd_clauses)
-	decl = name = cp_parser_identifier (parser);
-      else
-	{
-	  name = cp_parser_id_expression (parser, /*template_p=*/false,
-					  /*check_dependency_p=*/true,
-					  /*template_p=*/NULL,
-					  /*declarator_p=*/false,
-					  /*optional_p=*/false);
-	  if (name == error_mark_node)
-	    goto skip_comma;
+      name = cp_parser_id_expression (parser, /*template_p=*/false,
+				      /*check_dependency_p=*/true,
+				      /*template_p=*/NULL,
+				      /*declarator_p=*/false,
+				      /*optional_p=*/false);
+      if (name == error_mark_node)
+	goto skip_comma;
 
-	  decl = cp_parser_lookup_name_simple (parser, name, token->location);
-	}
+      decl = cp_parser_lookup_name_simple (parser, name, token->location);
       if (decl == error_mark_node)
 	cp_parser_name_lookup_error (parser, name, decl, NLE_NULL,
 				     token->location);
@@ -29725,7 +29716,6 @@  cp_parser_omp_target (cp_parser *parser,
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH))
 
@@ -29733,13 +29723,24 @@  static void
 cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok,
 			    enum pragma_context context)
 {
-  bool first_p = parser->omp_declare_simd_clauses == NULL;
-  vec_safe_push (parser->omp_declare_simd_clauses, NULL_TREE);
-  tree clauses
-    = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
-				 "#pragma omp declare simd", pragma_tok,
-				 false);
-  parser->omp_declare_simd_clauses->last () = clauses;
+  bool first_p = parser->omp_declare_simd == NULL;
+  cp_omp_declare_simd_data data;
+  if (first_p)
+    {
+      data.error_seen = false;
+      data.fndecl_seen = false;
+      data.tokens = vNULL;
+      parser->omp_declare_simd = &data;
+    }
+  while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)
+	 && cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
+    cp_lexer_consume_token (parser->lexer);
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
+    parser->omp_declare_simd->error_seen = true;
+  cp_parser_require_pragma_eol (parser, pragma_tok);
+  struct cp_token_cache *cp
+    = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer));
+  parser->omp_declare_simd->tokens.safe_push (cp);
   if (first_p)
     {
       while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA))
@@ -29759,16 +29760,72 @@  cp_parser_omp_declare_simd (cp_parser *p
 	  cp_parser_declaration_statement (parser);
 	  break;
 	}
-      if (parser->omp_declare_simd_clauses
-	  && (*parser->omp_declare_simd_clauses)[0] != error_mark_node
-	  && (*parser->omp_declare_simd_clauses)[0] != integer_zero_node)
+      if (parser->omp_declare_simd
+	  && !parser->omp_declare_simd->error_seen
+	  && !parser->omp_declare_simd->fndecl_seen)      
 	error_at (pragma_tok->location,
 		  "%<#pragma omp declare simd%> not immediately followed by "
 		  "function declaration or definition");
-      parser->omp_declare_simd_clauses = NULL;
+      data.tokens.release ();
+      parser->omp_declare_simd = NULL;
+    }
+}
+
+/* Finalize #pragma omp declare simd clauses after direct declarator has
+   been parsed, and put that into "omp declare simd" attribute.  */
+
+static tree
+cp_finish_omp_declare_simd (cp_parser *parser, tree attrs, cp_cv_quals quals)
+{
+  struct cp_token_cache *ce;
+  cp_omp_declare_simd_data *data = parser->omp_declare_simd;
+  int i;
+
+  if (!data->error_seen && data->fndecl_seen)
+    {
+      error ("%<#pragma omp declare simd%> not immediately followed by "
+	     "a single function declaration or definition");
+      data->error_seen = true;
+      return attrs;
     }
+  if (data->error_seen)
+    return attrs;
+
+  tree save_ccp = current_class_ptr;
+  tree save_ccr = current_class_ref;
+  if (quals >= 0)
+    inject_this_parameter (current_class_type, quals);
+
+  FOR_EACH_VEC_ELT (data->tokens, i, ce)
+    {
+      tree c, cl;
+
+      cp_parser_push_lexer_for_tokens (parser, ce);
+      parser->lexer->in_pragma = true;
+      gcc_assert (cp_lexer_peek_token (parser->lexer)->type == CPP_PRAGMA);
+      cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer);
+      cp_lexer_consume_token (parser->lexer);
+      cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+				      "#pragma omp declare simd", pragma_tok);
+      cp_parser_pop_lexer (parser);
+      c = build_tree_list (get_identifier ("omp declare simd"), cl);
+      TREE_CHAIN (c) = attrs;
+      if (processing_template_decl)
+	ATTR_IS_DEPENDENT (c) = 1;
+      attrs = c;
+    }
+
+  if (quals >= 0)
+    {
+      current_class_ptr = save_ccp;
+      current_class_ref = save_ccr;
+    }
+
+  data->fndecl_seen = true;
+  return attrs;
 }
 
+
 /* OpenMP 4.0:
    # pragma omp declare target new-line
    declarations and definitions
--- gcc/cp/pt.c.jj	2013-06-28 17:53:52.000000000 +0200
+++ gcc/cp/pt.c	2013-07-01 12:31:45.998252881 +0200
@@ -8494,8 +8494,9 @@  apply_late_template_attributes (tree *de
 						complain, in_decl);
 		  c_omp_declare_simd_clauses_to_decls (*decl_p, clauses);
 		  clauses = finish_omp_clauses (clauses);
+		  tree parms = DECL_ARGUMENTS (*decl_p);
 		  TREE_VALUE (t)
-		    = c_omp_declare_simd_clauses_to_numbers (*decl_p, clauses);
+		    = c_omp_declare_simd_clauses_to_numbers (parms, clauses);
 		}
 	      /* If the first attribute argument is an identifier, don't
 		 pass it through tsubst.  Attributes like mode, format,
--- gcc/cp/cp-tree.h.jj	2013-06-28 17:53:58.624326262 +0200
+++ gcc/cp/cp-tree.h	2013-07-01 11:44:29.522186412 +0200
@@ -4799,10 +4799,6 @@  typedef struct cp_decl_specifier_seq {
   /* If non-NULL, a built-in type that the user attempted to redefine
      to some other type.  */
   tree redefined_builtin_type;
-  /* When parsing #pragma omp declare simd, this is a vector of
-     the clauses, each tree is either NULL_TREE, or OMP_CLAUSE
-     with optional chain of other clauses.  */
-  vec<tree, va_gc> *omp_declare_simd_clauses;
   /* The storage class specified -- or sc_none if no storage class was
      explicitly specified.  */
   cp_storage_class storage_class;
@@ -5778,7 +5774,6 @@  extern void simplify_aggr_init_expr		(tr
 extern void finalize_nrv			(tree *, tree, tree);
 extern void note_decl_for_pch			(tree);
 extern tree finish_omp_clauses			(tree);
-extern void finish_omp_declare_simd		(tree, vec<tree, va_gc> *);
 extern void finish_omp_threadprivate		(tree);
 extern tree begin_omp_structured_block		(void);
 extern tree finish_omp_structured_block		(tree);
--- gcc/cp/parser.h.jj	2013-05-13 16:46:08.000000000 +0200
+++ gcc/cp/parser.h	2013-07-01 11:44:29.525186361 +0200
@@ -196,6 +196,14 @@  typedef struct GTY (()) cp_parser_contex
 } cp_parser_context;
 
 
+/* Control structure for #pragma omp declare simd parsing.  */
+struct cp_omp_declare_simd_data {
+  bool error_seen; /* Set if error has been reported.  */
+  bool fndecl_seen; /* Set if one fn decl/definition has been seen already.  */
+  vec<cp_token_cache_ptr> tokens;
+};
+
+
 /* The cp_parser structure represents the C++ parser.  */
 
 typedef struct GTY(()) cp_parser {
@@ -342,14 +350,9 @@  typedef struct GTY(()) cp_parser {
      current declaration.  */
   unsigned num_template_parameter_lists;
 
-  /* When parsing #pragma omp declare simd, this is a vector of
-     the clauses, each tree is either NULL_TREE, or OMP_CLAUSE
-     with optional chain of other clauses.  If error regarding
-     omp declare simd has been reported already, either
-     omp_declare_simd_clauses is set to NULL, or first element set
-     to error_mark_node.  If a FUNCTION_DECL has been seen already,
-     first element is set to integer_zero_node.  */
-  vec<tree, va_gc> *omp_declare_simd_clauses;
+  /* When parsing #pragma omp declare simd, this is a pointer to a
+     data structure with everything needed for parsing the clauses.  */
+  cp_omp_declare_simd_data * GTY((skip)) omp_declare_simd;
 } cp_parser;
 
 /* In parser.c  */
--- gcc/cp/semantics.c.jj	2013-06-28 17:53:53.594385529 +0200
+++ gcc/cp/semantics.c	2013-07-01 11:44:29.531186259 +0200
@@ -5226,90 +5226,6 @@  finish_omp_clauses (tree clauses)
   return clauses;
 }
 
-/* Finalize #pragma omp declare simd clauses after FNDECL has been parsed,
-   and put that into "omp declare simd" attribute.  */
-
-void
-finish_omp_declare_simd (tree fndecl, vec<tree, va_gc> *clauses)
-{
-  tree cl;
-  int i;
-
-  if (TREE_CODE (fndecl) != FUNCTION_DECL)
-    return;
-  if ((*clauses)[0] == integer_zero_node)
-    {
-      error_at (DECL_SOURCE_LOCATION (fndecl),
-		"%<#pragma omp declare simd%> not immediately followed by "
-		"a single function declaration or definition");
-      (*clauses)[0] = error_mark_node;
-      return;
-    }
-  if ((*clauses)[0] == error_mark_node)
-    return;
-
-  FOR_EACH_VEC_SAFE_ELT (clauses, i, cl)
-    {
-      tree c, *pc, decl, name;
-      for (pc = &cl, c = cl; c; c = *pc)
-	{
-	  bool remove = false;
-	  switch (OMP_CLAUSE_CODE (c))
-	    {
-	    case OMP_CLAUSE_UNIFORM:
-	    case OMP_CLAUSE_LINEAR:
-	    case OMP_CLAUSE_ALIGNED:
-	    case OMP_CLAUSE_REDUCTION:
-	      name = OMP_CLAUSE_DECL (c);
-	      if (name == error_mark_node)
-		remove = true;
-	      else
-		{
-		  for (decl = DECL_ARGUMENTS (fndecl); decl;
-		       decl = TREE_CHAIN (decl))
-		    if (DECL_NAME (decl) == name)
-		      break;
-		  if (decl == NULL_TREE)
-		    {
-		      error_at (OMP_CLAUSE_LOCATION (c),
-				"%qE is not a function parameter", name);
-		      remove = true;
-		    }
-		  else
-		    OMP_CLAUSE_DECL (c) = decl;
-		}
-	      break;
-	    default:
-	      break;
-	    }
-	  if (remove)
-	    *pc = OMP_CLAUSE_CHAIN (c);
-	  else
-	    pc = &OMP_CLAUSE_CHAIN (c);
-	}
-      cl = finish_omp_clauses (cl);
-      cl = c_omp_declare_simd_clauses_to_numbers (fndecl, cl);
-      if (!processing_template_decl)
-	{
-	  for (c = lookup_attribute ("omp declare simd",
-				     DECL_ATTRIBUTES (fndecl));
-	       c; c = lookup_attribute ("omp declare simd",
-					TREE_CHAIN (c)))
-	    if (omp_declare_simd_clauses_equal (TREE_VALUE (c), cl))
-	      break;
-	  if (c)
-	    continue;
-	}
-      c = build_tree_list (get_identifier ("omp declare simd"), cl);
-      TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
-      if (processing_template_decl)
-	ATTR_IS_DEPENDENT (c) = 1;
-      DECL_ATTRIBUTES (fndecl) = c;
-    }
-
-  (*clauses)[0] = integer_zero_node;
-}
-
 /* For all variables in the tree_list VARS, mark them as thread local.  */
 
 void
--- gcc/tree.c.jj	2013-06-28 17:56:45.000000000 +0200
+++ gcc/tree.c	2013-07-01 12:18:32.563612066 +0200
@@ -4617,7 +4617,7 @@  build_type_attribute_qual_variant (tree
 /* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
    the same.  */
 
-bool
+static bool
 omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
 {
   tree cl1, cl2;
@@ -4656,6 +4656,35 @@  omp_declare_simd_clauses_equal (tree cla
   return true;
 }
 
+/* Remove duplicate "omp declare simd" attributes.  */
+
+void
+omp_remove_redundant_declare_simd_attrs (tree fndecl)
+{
+  tree attr, end_attr = NULL_TREE, last_attr = NULL_TREE;
+  for (attr = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (fndecl));
+       attr;
+       attr = lookup_attribute ("omp declare simd", TREE_CHAIN (attr)))
+    {
+      tree *pc;
+      for (pc = &TREE_CHAIN (attr); *pc && *pc != end_attr; )
+	{
+	  if (is_attribute_p ("omp declare simd", TREE_PURPOSE (*pc)))
+	    {
+	      last_attr = TREE_CHAIN (*pc);
+	      if (omp_declare_simd_clauses_equal (TREE_VALUE (*pc),
+						  TREE_VALUE (attr)))
+		{
+		  *pc = TREE_CHAIN (*pc);
+		  continue;
+		}
+	    }
+	  pc = &TREE_CHAIN (*pc);
+	}
+      end_attr = last_attr;
+    }
+}
+
 /* Compare two attributes for their value identity.  Return true if the
    attribute values are known to be equal; otherwise return false.
 */
--- gcc/testsuite/g++.dg/gomp/declare-simd-1.C.jj	2013-05-09 17:06:21.000000000 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-simd-1.C	2013-07-01 12:50:11.757851173 +0200
@@ -222,3 +222,22 @@  f33 (int x)
     extern int f35 (int a, int *b, int c);
   return x;
 }
+
+#pragma omp declare simd simdlen (N)
+template <int N>
+int f36 (int);
+
+struct D
+{
+  int d;
+  #pragma omp declare simd simdlen (N) linear (a : sizeof (a) + sizeof (d) + sizeof (this) + sizeof (this->d))
+  template <int N>
+  int f37 (int a);
+  int e;
+};
+
+void
+f38 (D &d)
+{
+  d.f37 <12> (6);
+}
--- gcc/testsuite/g++.dg/gomp/declare-simd-2.C.jj	2013-05-09 17:06:21.000000000 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-simd-2.C	2013-07-01 12:52:20.420076087 +0200
@@ -52,9 +52,16 @@  int t;
 #pragma omp threadprivate(t)	// { dg-error "not immediately followed by function declaration or definition" }
 int fn10 (int a);
 
-#pragma omp declare simd inbranch notinbranch
-int fn11 (int);		// { dg-error "clause is incompatible with" }
+#pragma omp declare simd inbranch notinbranch // { dg-error "clause is incompatible with" }
+int fn11 (int);
 
-#pragma omp declare simd simdlen (N)	// { dg-error "was not declared in this scope" }
-template <int N>
-int fn12 (int);
+struct D
+{
+  int d;
+  #pragma omp declare simd simdlen (N) linear (a : sizeof (e) + sizeof (this->e)) // { dg-error "was not declared" }
+  template <int N>
+  int fn12 (int a);
+  int e;
+};
+
+// { dg-error "has no member" "" { target *-*-* } 61 }
--- gcc/c-family/c-omp.c.jj	2013-06-21 08:38:19.000000000 +0200
+++ gcc/c-family/c-omp.c	2013-07-01 12:25:57.729124328 +0200
@@ -895,7 +895,7 @@  c_omp_declare_simd_clause_cmp (const voi
    CLAUSES on FNDECL into argument indexes and sort them.  */
 
 tree
-c_omp_declare_simd_clauses_to_numbers (tree fndecl, tree clauses)
+c_omp_declare_simd_clauses_to_numbers (tree parms, tree clauses)
 {
   tree c;
   vec<tree> clvec = vNULL;
@@ -909,14 +909,14 @@  c_omp_declare_simd_clauses_to_numbers (t
 	  tree decl = OMP_CLAUSE_DECL (c);
 	  tree arg;
 	  int idx;
-	  for (arg = DECL_ARGUMENTS (fndecl), idx = 0; arg;
+	  for (arg = parms, idx = 0; arg;
 	       arg = TREE_CHAIN (arg), idx++)
 	    if (arg == decl)
 	      break;
 	  if (arg == NULL_TREE)
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
-			"%qD is not an argument of %qD", decl, fndecl);
+			"%qD is not an function argument", decl);
 	      continue;
 	    }
 	  OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, idx);