Change C++ to C comments.
[gcc.git] / gcc / cp / parser.c
index b5196f6184bc83f84395837ff06b47de34d7c962..165039ef07c00768a2fc4ac3f05b1ea42ceaaa0c 100644 (file)
@@ -247,8 +247,6 @@ static void cp_lexer_stop_debugging
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
-static tree cp_parser_noexcept_specification_opt
-  (cp_parser *, bool, bool *, bool, bool);
 static tree cp_parser_late_noexcept_specifier
   (cp_parser *, tree);
 static void noexcept_override_late_checks
@@ -834,14 +832,28 @@ cp_lexer_get_preprocessor_token (cp_lexer *lexer, cp_token *token)
             {
               /* Warn about the C++0x keyword (but still treat it as
                  an identifier).  */
-              warning (OPT_Wc__11_compat,
-                       "identifier %qE is a keyword in C++11",
-                       token->u.value);
+             warning_at (token->location, OPT_Wc__11_compat,
+                         "identifier %qE is a keyword in C++11",
+                         token->u.value);
 
               /* Clear out the C_RID_CODE so we don't warn about this
                  particular identifier-turned-keyword again.  */
               C_SET_RID_CODE (token->u.value, RID_MAX);
             }
+         if (warn_cxx20_compat
+             && C_RID_CODE (token->u.value) >= RID_FIRST_CXX20
+             && C_RID_CODE (token->u.value) <= RID_LAST_CXX20)
+           {
+             /* Warn about the C++20 keyword (but still treat it as
+                an identifier).  */
+             warning_at (token->location, OPT_Wc__20_compat,
+                         "identifier %qE is a keyword in C++20",
+                         token->u.value);
+
+             /* Clear out the C_RID_CODE so we don't warn about this
+                particular identifier-turned-keyword again.  */
+             C_SET_RID_CODE (token->u.value, RID_MAX);
+           }
 
          token->keyword = RID_MAX;
        }
@@ -986,6 +998,7 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_DECLTYPE:
     case RID_UNDERLYING_TYPE:
     case RID_CONSTEXPR:
+    case RID_CONSTINIT:
       return true;
 
     default:
@@ -1815,7 +1828,9 @@ enum
   /* When parsing a decl-specifier-seq, only allow mutable or constexpr.  */
   CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10,
   /* When parsing a decl-specifier-seq, allow missing typename.  */
-  CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20
+  CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20,
+  /* When parsing of the noexcept-specifier should be delayed.  */
+  CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40
 };
 
 /* This type is used for parameters and variables which hold
@@ -2102,7 +2117,7 @@ static cp_expr cp_parser_assignment_expression
 static enum tree_code cp_parser_assignment_operator_opt
   (cp_parser *);
 static cp_expr cp_parser_expression
-  (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false);
+  (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false);
 static cp_expr cp_parser_constant_expression
   (cp_parser *, bool = false, bool * = NULL, bool = false);
 static cp_expr cp_parser_builtin_offsetof
@@ -2365,7 +2380,7 @@ static void cp_parser_explicit_instantiation
 static void cp_parser_explicit_specialization
   (cp_parser *);
 
-/* Exception handling [gram.exception] */
+/* Exception handling [gram.except] */
 
 static tree cp_parser_try_block
   (cp_parser *);
@@ -2380,9 +2395,11 @@ static tree cp_parser_exception_declaration
 static tree cp_parser_throw_expression
   (cp_parser *);
 static tree cp_parser_exception_specification_opt
-  (cp_parser *, bool = false);
+  (cp_parser *, cp_parser_flags);
 static tree cp_parser_type_id_list
   (cp_parser *);
+static tree cp_parser_noexcept_specification_opt
+  (cp_parser *, cp_parser_flags, bool, bool *, bool);
 
 /* GNU Extensions */
 
@@ -2669,8 +2686,6 @@ static bool cp_parser_init_statement_p
   (cp_parser *);
 static bool cp_parser_skip_to_closing_square_bracket
   (cp_parser *);
-static int cp_parser_skip_to_closing_square_bracket_1
-  (cp_parser *, enum cpp_ttype);
 
 /* Concept-related syntactic transformations */
 
@@ -3355,6 +3370,9 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
               && id_equal (id, "thread_local"))
        inform (location, "C++11 %<thread_local%> only available with "
                "%<-std=c++11%> or %<-std=gnu++11%>");
+      else if (cxx_dialect < cxx2a && id == ridpointers[(int)RID_CONSTINIT])
+       inform (location, "C++20 %<constinit%> only available with "
+               "%<-std=c++2a%> or %<-std=gnu++2a%>");
       else if (!flag_concepts && id == ridpointers[(int)RID_CONCEPT])
        inform (location, "%<concept%> only available with %<-fconcepts%>");
       else if (processing_template_decl && current_class_type
@@ -6422,9 +6440,11 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
                  == CPP_SCOPE))
            {
              token = cp_lexer_consume_token (parser->lexer);
-             error_at (token->location, "%<decltype%> evaluates to %qT, "
-                       "which is not a class or enumeration type",
-                       token->u.tree_check_value->value);
+             tree dtype = token->u.tree_check_value->value;
+             if (dtype != error_mark_node)
+               error_at (token->location, "%<decltype%> evaluates to %qT, "
+                         "which is not a class or enumeration type",
+                         dtype);
              parser->scope = error_mark_node;
              error_p = true;
              /* As below.  */
@@ -7524,33 +7544,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
          index = cp_parser_braced_list (parser, &expr_nonconst_p);
        }
       else
-       {
-         /* [depr.comma.subscript]: A comma expression appearing as
-            the expr-or-braced-init-list of a subscripting expression
-            is deprecated.  A parenthesized comma expression is not
-            deprecated.  */
-         if (warn_comma_subscript)
-           {
-             /* Save tokens so that we can put them back.  */
-             cp_lexer_save_tokens (parser->lexer);
-
-             /* Look for ',' that is not nested in () or {}.  */
-             if (cp_parser_skip_to_closing_square_bracket_1 (parser,
-                                                             CPP_COMMA) == -1)
-               {
-                 auto_diagnostic_group d;
-                 warning_at (cp_lexer_peek_token (parser->lexer)->location,
-                             OPT_Wcomma_subscript,
-                             "top-level comma expression in array subscript "
-                             "is deprecated");
-               }
-
-             /* Roll back the tokens we skipped.  */
-             cp_lexer_rollback_tokens (parser->lexer);
-           }
-
-         index = cp_parser_expression (parser);
-       }
+       index = cp_parser_expression (parser, NULL, /*cast_p=*/false,
+                                     /*decltype_p=*/false,
+                                     /*warn_comma_p=*/warn_comma_subscript);
     }
 
   parser->greater_than_is_operator_p = saved_greater_than_is_operator_p;
@@ -9932,12 +9928,13 @@ cp_parser_assignment_operator_opt (cp_parser* parser)
    CAST_P is true if this expression is the target of a cast.
    DECLTYPE_P is true if this expression is the immediate operand of decltype,
      except possibly parenthesized or on the RHS of a comma (N3276).
+   WARN_COMMA_P is true if a comma should be diagnosed.
 
    Returns a representation of the expression.  */
 
 static cp_expr
 cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
-                     bool cast_p, bool decltype_p)
+                     bool cast_p, bool decltype_p, bool warn_comma_p)
 {
   cp_expr expression = NULL_TREE;
   location_t loc = UNKNOWN_LOCATION;
@@ -9984,6 +9981,17 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
        break;
       /* Consume the `,'.  */
       loc = cp_lexer_peek_token (parser->lexer)->location;
+      if (warn_comma_p)
+       {
+         /* [depr.comma.subscript]: A comma expression appearing as
+            the expr-or-braced-init-list of a subscripting expression
+            is deprecated.  A parenthesized comma expression is not
+            deprecated.  */
+         warning_at (loc, OPT_Wcomma_subscript,
+                     "top-level comma expression in array subscript "
+                     "is deprecated");
+         warn_comma_p = false;
+       }
       cp_lexer_consume_token (parser->lexer);
       /* A comma operator cannot appear in a constant-expression.  */
       if (cp_parser_non_integral_constant_expression (parser, NIC_COMMA))
@@ -10390,7 +10398,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
     case CPTK_DIRECT_BASES:
       return cp_expr (finish_bases (type1, true), trait_loc);
     default:
-      return cp_expr (finish_trait_expr (kind, type1, type2), trait_loc);
+      return finish_trait_expr (trait_loc, kind, type1, type2);
     }
 }
 
@@ -10932,7 +10940,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
       tx_qual = cp_parser_tx_qualifier_opt (parser);
 
       /* Parse optional exception specification.  */
-      exception_spec = cp_parser_exception_specification_opt (parser);
+      exception_spec
+       = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
 
       std_attrs = cp_parser_std_attribute_spec_seq (parser);
 
@@ -12080,6 +12089,10 @@ cp_parser_condition (cp_parser* parser)
   /* Restore the saved message.  */
   parser->type_definition_forbidden_message = saved_message;
 
+  /* Gather the attributes that were provided with the
+     decl-specifiers.  */
+  tree prefix_attributes = type_specifiers.attributes;
+
   cp_parser_maybe_commit_to_declaration (parser,
                                         type_specifiers.any_specifiers_p);
 
@@ -12130,7 +12143,7 @@ cp_parser_condition (cp_parser* parser)
          /* Create the declaration.  */
          decl = start_decl (declarator, &type_specifiers,
                             /*initialized_p=*/true,
-                            attributes, /*prefix_attributes=*/NULL_TREE,
+                            attributes, prefix_attributes,
                             &pushed_scope);
 
          /* Parse the initializer.  */
@@ -13847,9 +13860,12 @@ cp_parser_decomposition_declaration (cp_parser *parser,
 
       if (decl != error_mark_node)
        {
+         int flags = (decl_spec_seq_has_spec_p (decl_specifiers, ds_constinit)
+                      ? LOOKUP_CONSTINIT : 0);
          cp_maybe_mangle_decomp (decl, prev, v.length ());
          cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE,
-                         is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT);
+                         (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT)
+                         | flags);
          cp_finish_decomp (decl, prev, v.length ());
        }
     }
@@ -14001,7 +14017,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
        {
          /* decl-specifier:
               friend
-               constexpr */
+              constexpr
+              constinit */
        case RID_FRIEND:
          if (!at_class_scope_p ())
            {
@@ -14023,6 +14040,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
           cp_lexer_consume_token (parser->lexer);
           break;
 
+       case RID_CONSTINIT:
+         ds = ds_constinit;
+         cp_lexer_consume_token (parser->lexer);
+         break;
+
         case RID_CONCEPT:
           ds = ds_concept;
           cp_lexer_consume_token (parser->lexer);
@@ -19388,6 +19410,7 @@ cp_parser_namespace_alias_definition (cp_parser* parser)
   /* Look for the qualified-namespace-specifier.  */
   namespace_specifier
     = cp_parser_qualified_namespace_specifier (parser);
+  cp_warn_deprecated_use_scopes (namespace_specifier);
   /* Look for the `;' token.  */
   cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
 
@@ -19502,6 +19525,8 @@ cp_parser_using_declaration (cp_parser* parser,
           && !TYPE_FUNCTION_SCOPE_P (qscope))
     qscope = CP_TYPE_CONTEXT (qscope);
 
+  cp_warn_deprecated_use_scopes (qscope);
+
   if (access_declaration_p && cp_parser_error_occurred (parser))
     /* Something has already gone wrong; there's no need to parse
        further.  Since an error has occurred, the return value of
@@ -19709,7 +19734,7 @@ cp_parser_alias_declaration (cp_parser* parser)
   if (decl == error_mark_node)
     return decl;
 
-  // Attach constraints to the alias declaration.
+  /* Attach constraints to the alias declaration.  */
   if (flag_concepts && current_template_parms)
     {
       tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
@@ -19762,6 +19787,7 @@ cp_parser_using_directive (cp_parser* parser)
                                       /*is_declaration=*/true);
   /* Get the namespace being used.  */
   namespace_decl = cp_parser_namespace_name (parser);
+  cp_warn_deprecated_use_scopes (namespace_decl);
   /* And any specified attributes.  */
   attribs = cp_parser_attributes_opt (parser);
 
@@ -20536,6 +20562,8 @@ cp_parser_init_declarator (cp_parser* parser,
      declarations.  */
   if (!member_p && decl && decl != error_mark_node && !range_for_decl_p)
     {
+      int cf = (decl_spec_seq_has_spec_p (decl_specifiers, ds_constinit)
+               ? LOOKUP_CONSTINIT : 0);
       cp_finish_decl (decl,
                      initializer, !is_non_constant_init,
                      asm_specification,
@@ -20544,7 +20572,7 @@ cp_parser_init_declarator (cp_parser* parser,
                         `explicit' constructor is OK.  Otherwise, an
                         `explicit' constructor cannot be used.  */
                      ((is_direct_init || !is_initialized)
-                      ? LOOKUP_NORMAL : LOOKUP_IMPLICIT));
+                      ? LOOKUP_NORMAL : LOOKUP_IMPLICIT) | cf);
     }
   else if ((cxx_dialect != cxx98) && friend_p
           && decl && TREE_CODE (decl) == FUNCTION_DECL)
@@ -20852,7 +20880,7 @@ cp_parser_direct_declarator (cp_parser* parser,
                  tree tx_qual = cp_parser_tx_qualifier_opt (parser);
                  /* And the exception-specification.  */
                  exception_specification
-                   = cp_parser_exception_specification_opt (parser, friend_p);
+                   = cp_parser_exception_specification_opt (parser, flags);
 
                  attrs = cp_parser_std_attribute_spec_seq (parser);
 
@@ -22523,12 +22551,14 @@ cp_parser_parameter_declaration (cp_parser *parser,
          && !LAMBDA_TYPE_P (current_class_type))
        default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
 
-      // A constrained-type-specifier may declare a type template-parameter.
+      /* A constrained-type-specifier may declare a type
+        template-parameter.  */
       else if (declares_constrained_type_template_parameter (type))
         default_argument
           = cp_parser_default_type_template_argument (parser);
 
-      // A constrained-type-specifier may declare a template-template-parameter.
+      /* A constrained-type-specifier may declare a
+        template-template-parameter.  */
       else if (declares_constrained_template_template_parameter (type))
         default_argument
           = cp_parser_default_template_template_argument (parser);
@@ -22888,25 +22918,16 @@ cp_parser_braced_list (cp_parser* parser, bool* non_constant_p)
 }
 
 /* Consume tokens up to, and including, the next non-nested closing `]'.
-   Returns 1 iff we found a closing `]'.  Returns -1 if OR_TTYPE is not
-   CPP_EOF and we found an unnested token of that type.  */
+   Returns true iff we found a closing `]'.  */
 
-static int
-cp_parser_skip_to_closing_square_bracket_1 (cp_parser *parser,
-                                           enum cpp_ttype or_ttype)
+static bool
+cp_parser_skip_to_closing_square_bracket (cp_parser *parser)
 {
   unsigned square_depth = 0;
-  unsigned paren_depth = 0;
-  unsigned brace_depth = 0;
 
   while (true)
     {
-      cp_token *token = cp_lexer_peek_token (parser->lexer);
-
-      /* Have we found what we're looking for before the closing square?  */
-      if (token->type == or_ttype && or_ttype != CPP_EOF
-         && brace_depth == 0 && paren_depth == 0 && square_depth == 0)
-       return -1;
+      cp_token * token = cp_lexer_peek_token (parser->lexer);
 
       switch (token->type)
        {
@@ -22916,38 +22937,20 @@ cp_parser_skip_to_closing_square_bracket_1 (cp_parser *parser,
          /* FALLTHRU */
        case CPP_EOF:
          /* If we've run out of tokens, then there is no closing `]'.  */
-         return 0;
+         return false;
 
         case CPP_OPEN_SQUARE:
           ++square_depth;
           break;
 
         case CPP_CLOSE_SQUARE:
-         if (square_depth-- == 0)
+         if (!square_depth--)
            {
              cp_lexer_consume_token (parser->lexer);
-             return 1;
+             return true;
            }
          break;
 
-       case CPP_OPEN_BRACE:
-         ++brace_depth;
-         break;
-
-       case CPP_CLOSE_BRACE:
-         if (brace_depth-- == 0)
-           return 0;
-         break;
-
-       case CPP_OPEN_PAREN:
-         ++paren_depth;
-         break;
-
-       case CPP_CLOSE_PAREN:
-         if (paren_depth-- == 0)
-           return 0;
-         break;
-
        default:
          break;
        }
@@ -22957,15 +22960,6 @@ cp_parser_skip_to_closing_square_bracket_1 (cp_parser *parser,
     }
 }
 
-/* Consume tokens up to, and including, the next non-nested closing `]'.
-   Returns true iff we found a closing `]'.  */
-
-static bool
-cp_parser_skip_to_closing_square_bracket (cp_parser *parser)
-{
-  return cp_parser_skip_to_closing_square_bracket_1 (parser, CPP_EOF) == 1;
-}
-
 /* Return true if we are looking at an array-designator, false otherwise.  */
 
 static bool
@@ -24791,11 +24785,15 @@ cp_parser_member_declaration (cp_parser* parser)
              tree asm_specification;
              int ctor_dtor_or_conv_p;
              bool static_p = (decl_specifiers.storage_class == sc_static);
+             cp_parser_flags flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
+             if (!friend_p
+                 && !decl_spec_seq_has_spec_p (&decl_specifiers, ds_typedef))
+               flags |= CP_PARSER_FLAGS_DELAY_NOEXCEPT;
 
              /* Parse the declarator.  */
              declarator
                = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
-                                       CP_PARSER_FLAGS_TYPENAME_OPTIONAL,
+                                       flags,
                                        &ctor_dtor_or_conv_p,
                                        /*parenthesized_p=*/NULL,
                                        /*member_p=*/true,
@@ -25370,10 +25368,10 @@ cp_parser_late_noexcept_specifier (cp_parser *parser, tree default_arg)
   /* Parse the cached noexcept-specifier.  */
   tree parsed_arg
     = cp_parser_noexcept_specification_opt (parser,
+                                           CP_PARSER_FLAGS_NONE,
                                            /*require_constexpr=*/true,
                                            /*consumed_expr=*/NULL,
-                                           /*return_cond=*/false,
-                                           /*friend_p=*/false);
+                                           /*return_cond=*/false);
 
   /* Revert to the main lexer.  */
   cp_parser_pop_lexer (parser);
@@ -25422,15 +25420,15 @@ noexcept_override_late_checks (tree type, tree fndecl)
    expression if parentheses follow noexcept, or return BOOLEAN_TRUE_NODE if
    there are no parentheses.  CONSUMED_EXPR will be set accordingly.
    Otherwise, returns a noexcept specification unless RETURN_COND is true,
-   in which case a boolean condition is returned instead.  If FRIEND_P is true,
-   the function with this noexcept-specification had the `friend' specifier.  */
+   in which case a boolean condition is returned instead.  The parser flags
+   FLAGS is used to control parsing.  */
 
 static tree
 cp_parser_noexcept_specification_opt (cp_parser* parser,
+                                     cp_parser_flags flags,
                                      bool require_constexpr,
                                      bool* consumed_expr,
-                                     bool return_cond,
-                                     bool friend_p)
+                                     bool return_cond)
 {
   cp_token *token;
   const char *saved_message;
@@ -25457,8 +25455,10 @@ cp_parser_noexcept_specification_opt (cp_parser* parser,
          /* No need to delay parsing for a number literal or true/false.  */
          && !literal_p
          && at_class_scope_p ()
-         /* Don't delay parsing for friend member functions.  */
-         && !friend_p
+         /* We don't delay parsing for friend member functions,
+            alias-declarations, and typedefs, even though the standard seems
+            to require it.  */
+         && (flags & CP_PARSER_FLAGS_DELAY_NOEXCEPT)
          && TYPE_BEING_DEFINED (current_class_type)
          && !LAMBDA_TYPE_P (current_class_type))
        return cp_parser_save_noexcept (parser);
@@ -25533,11 +25533,11 @@ cp_parser_noexcept_specification_opt (cp_parser* parser,
      throw ( type-id-list [opt] )
 
    Returns a TREE_LIST representing the exception-specification.  The
-   TREE_VALUE of each node is a type.  If FRIEND_P is true, the function
-   with this noexcept-specification had the `friend' specifier.  */
+   TREE_VALUE of each node is a type.  The parser flags FLAGS is used to
+   control parsing.  */
 
 static tree
-cp_parser_exception_specification_opt (cp_parser* parser, bool friend_p)
+cp_parser_exception_specification_opt (cp_parser* parser, cp_parser_flags flags)
 {
   cp_token *token;
   tree type_id_list;
@@ -25548,11 +25548,10 @@ cp_parser_exception_specification_opt (cp_parser* parser, bool friend_p)
 
   /* Is it a noexcept-specification?  */
   type_id_list
-    = cp_parser_noexcept_specification_opt (parser,
+    = cp_parser_noexcept_specification_opt (parser, flags,
                                            /*require_constexpr=*/true,
                                            /*consumed_expr=*/NULL,
-                                           /*return_cond=*/false,
-                                           friend_p);
+                                           /*return_cond=*/false);
   if (type_id_list != NULL_TREE)
     return type_id_list;
 
@@ -28478,9 +28477,9 @@ cp_parser_single_declaration (cp_parser* parser,
       if (cp_parser_declares_only_class_p (parser)
          || (declares_class_or_enum & 2))
        {
-         // If this is a declaration, but not a definition, associate
-         // any constraints with the type declaration. Constraints
-         // are associated with definitions in cp_parser_class_specifier.
+         /* If this is a declaration, but not a definition, associate
+            any constraints with the type declaration. Constraints
+            are associated with definitions in cp_parser_class_specifier.  */
          if (declares_class_or_enum == 1)
            associate_classtype_constraints (decl_specifiers.type);
 
@@ -29510,7 +29509,8 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
            "typedef",
            "using",
             "constexpr",
-           "__complex"
+           "__complex",
+           "constinit"
          };
          gcc_rich_location richloc (location);
          richloc.add_fixit_remove ();
@@ -32510,6 +32510,8 @@ cp_parser_omp_clause_name (cp_parser *parser)
            result = PRAGMA_OACC_CLAUSE_DEVICEPTR;
          else if (!strcmp ("device_resident", p))
            result = PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT;
+         else if (!strcmp ("device_type", p))
+           result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE;
          else if (!strcmp ("dist_schedule", p))
            result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
          break;
@@ -35321,6 +35323,56 @@ cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list,
   return list;
 }
 
+/* OpenMP 5.0:
+   device_type ( host | nohost | any )  */
+
+static tree
+cp_parser_omp_clause_device_type (cp_parser *parser, tree list,
+                                 location_t location)
+{
+  tree c;
+  enum omp_clause_device_type_kind kind;
+
+  if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+    return list;
+
+  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    {
+      tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+      const char *p = IDENTIFIER_POINTER (id);
+
+      if (strcmp ("host", p) == 0)
+       kind = OMP_CLAUSE_DEVICE_TYPE_HOST;
+      else if (strcmp ("nohost", p) == 0)
+       kind = OMP_CLAUSE_DEVICE_TYPE_NOHOST;
+      else if (strcmp ("any", p) == 0)
+       kind = OMP_CLAUSE_DEVICE_TYPE_ANY;
+      else
+       goto invalid_kind;
+    }
+  else
+    goto invalid_kind;
+
+  cp_lexer_consume_token (parser->lexer);
+  if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_COMMA_CLOSE_PAREN))
+    goto resync_fail;
+
+  c = build_omp_clause (location, OMP_CLAUSE_DEVICE_TYPE);
+  /* check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE, "device_type",
+                               location);  */
+  OMP_CLAUSE_DEVICE_TYPE_KIND (c) = kind;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+
+ invalid_kind:
+  cp_parser_error (parser, "invalid depend kind");
+ resync_fail:
+  cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+                                        /*or_comma=*/false,
+                                        /*consume_paren=*/true);
+  return list;
+}
+
 /* OpenACC:
    async [( int-expr )] */
 
@@ -35849,6 +35901,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
                                                    token->location);
          c_name = "proc_bind";
          break;
+       case PRAGMA_OMP_CLAUSE_DEVICE_TYPE:
+         clauses = cp_parser_omp_clause_device_type (parser, clauses,
+                                                     token->location);
+         c_name = "device_type";
+         break;
        case PRAGMA_OMP_CLAUSE_SAFELEN:
          clauses = cp_parser_omp_clause_safelen (parser, clauses,
                                                  token->location);
@@ -39831,12 +39888,15 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs)
 
 #define OMP_DECLARE_TARGET_CLAUSE_MASK                         \
        ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO)           \
-       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK))
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)         \
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE))
 
 static void
 cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok)
 {
   tree clauses = NULL_TREE;
+  int device_type = 0;
+  bool only_device_type = true;
   if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
     clauses
       = cp_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK,
@@ -39854,17 +39914,18 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok)
       scope_chain->omp_declare_target_attribute++;
       return;
     }
-  if (scope_chain->omp_declare_target_attribute)
-    error_at (pragma_tok->location,
-             "%<#pragma omp declare target%> with clauses in between "
-             "%<#pragma omp declare target%> without clauses and "
-             "%<#pragma omp end declare target%>");
+  for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+      device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c);
   for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
     {
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+       continue;
       tree t = OMP_CLAUSE_DECL (c), id;
       tree at1 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (t));
       tree at2 = lookup_attribute ("omp declare target link",
                                   DECL_ATTRIBUTES (t));
+      only_device_type = false;
       if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK)
        {
          id = get_identifier ("omp declare target link");
@@ -39897,7 +39958,34 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok)
                }
            }
        }
+      if (TREE_CODE (t) != FUNCTION_DECL)
+       continue;
+      if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0)
+       {
+         tree at3 = lookup_attribute ("omp declare target host",
+                                      DECL_ATTRIBUTES (t));
+         if (at3 == NULL_TREE)
+           {
+             id = get_identifier ("omp declare target host");
+             DECL_ATTRIBUTES (t)
+               = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t));
+           }
+       }
+      if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0)
+       {
+         tree at3 = lookup_attribute ("omp declare target nohost",
+                                      DECL_ATTRIBUTES (t));
+         if (at3 == NULL_TREE)
+           {
+             id = get_identifier ("omp declare target nohost");
+             DECL_ATTRIBUTES (t)
+               = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t));
+           }
+       }
     }
+  if (device_type && only_device_type)
+    warning_at (OMP_CLAUSE_LOCATION (clauses), 0,
+               "directive with only %<device_type%> clauses ignored");
 }
 
 static void
@@ -41084,10 +41172,10 @@ cp_parser_transaction (cp_parser *parser, cp_token *token)
     }
   else
     noex = cp_parser_noexcept_specification_opt (parser,
+                                                CP_PARSER_FLAGS_NONE,
                                                 /*require_constexpr=*/true,
                                                 /*consumed_expr=*/NULL,
-                                                /*return_cond=*/true,
-                                                /*friend_p=*/false);
+                                                /*return_cond=*/true);
 
   /* Keep track if we're in the lexical scope of an outer transaction.  */
   new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
@@ -41148,10 +41236,10 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword)
 
   /* Parse a noexcept specification.  */
   noex = cp_parser_noexcept_specification_opt (parser,
+                                              CP_PARSER_FLAGS_NONE,
                                               /*require_constexpr=*/false,
                                               &noex_expr,
-                                              /*return_cond=*/true,
-                                              /*friend_p=*/false);
+                                              /*return_cond=*/true);
 
   if (!noex || !noex_expr
       || cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN)
@@ -41315,7 +41403,10 @@ cp_parser_initial_pragma (cp_token *first_token)
 
   cp_lexer_get_preprocessor_token (NULL, first_token);
   if (cp_parser_pragma_kind (first_token) != PRAGMA_GCC_PCH_PREPROCESS)
-    return;
+    {
+      c_common_no_more_pch ();
+      return;
+    }
 
   cp_lexer_get_preprocessor_token (NULL, first_token);
   if (first_token->type == CPP_STRING)
@@ -41942,7 +42033,7 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
       non_type = true;
     }
 
-  // Attach the constraint to the parm before processing.
+  /* Attach the constraint to the parm before processing.  */
   tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
   TREE_TYPE (node) = constr;
   tree new_parm
@@ -41985,8 +42076,8 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
       TREE_VEC_ELT (new_parms, new_parm_idx) = parser->implicit_template_parms;
     }
 
-  // If the new parameter was constrained, we need to add that to the
-  // constraints in the template parameter list.
+  /* If the new parameter was constrained, we need to add that to the
+     constraints in the template parameter list.  */
   if (tree req = TEMPLATE_PARM_CONSTRAINTS (tree_last (new_parm)))
     {
       tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);