--- 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);
