FreeBSD/contrib/gcc/cp/parser.c
/* Parse a class-head.

   class-head:
     class-key identifier [opt] base-clause [opt]
     class-key nested-name-specifier identifier base-clause [opt]
     class-key nested-name-specifier [opt] template-id
       base-clause [opt]

   GNU Extensions:
     class-key attributes identifier [opt] base-clause [opt]
     class-key attributes nested-name-specifier identifier base-clause [opt]
     class-key attributes nested-name-specifier [opt] template-id
       base-clause [opt]

   Returns the TYPE of the indicated class.  Sets
   *NESTED_NAME_SPECIFIER_P to TRUE iff one of the productions
   involving a nested-name-specifier was used, and FALSE otherwise.

   Returns error_mark_node if this is not a class-head.

   Returns NULL_TREE if the class-head is syntactically valid, but
   semantically invalid in a way that means we should skip the entire
   body of the class.  */
Parse a class-head.



Returns the TYPE of the indicated class.  Sets
NESTED_NAME_SPECIFIER_P to TRUE iff one of the productions
involving a nested-name-specifier was used, and FALSE otherwise.

Returns error_mark_node if this is not a class-head.

Returns NULL_TREE if the class-head is syntactically valid, but
semantically invalid in a way that means we should skip the entire
body of the class.
Parse a class - head . Returns the TYPE of the indicated class . Sets NESTED_NAME_SPECIFIER_P to TRUE iff one of the productions involving a nested - name - specifier was used and FALSE otherwise . Returns error_mark_node if this is not a class - head . Returns NULL_TREE if the class - head is syntactically valid but semantically invalid in a way that means we should skip the entire body of the class .
static tree
cp_parser_class_head (cp_parser* parser,
		      bool* nested_name_specifier_p,
		      tree *attributes_p,
		      tree *bases)
{
  tree nested_name_specifier;
  enum tag_types class_key;
  tree id = NULL_TREE;
  tree type = NULL_TREE;
  tree attributes;
  bool template_id_p = false;
  bool qualified_p = false;
  bool invalid_nested_name_p = false;
  bool invalid_explicit_specialization_p = false;
  tree pushed_scope = NULL_TREE;
  unsigned num_templates;
  *nested_name_specifier_p = false;
  num_templates = 0;
  class_key = cp_parser_class_key (parser);
  if (class_key == none_type)
    return error_mark_node;
  attributes = cp_parser_attributes_opt (parser);
  if (cp_parser_global_scope_opt (parser, false))
    qualified_p = true;
  push_deferring_access_checks (dk_no_check);
  nested_name_specifier
    = cp_parser_nested_name_specifier_opt (parser,
					   false,
					   false,
					   false,
					   false);
  if (nested_name_specifier)
    {
      cp_parser_parse_tentatively (parser);
      type = cp_parser_class_name (parser,
				   false,
				   false,
				   class_type,
				   false,
				   true,
				   false);
      if (!cp_parser_parse_definitely (parser))
	{
	  invalid_nested_name_p = true;
	  id = cp_parser_identifier (parser);
	  if (id == error_mark_node)
	    id = NULL_TREE;
	}
      if (type == error_mark_node)
	nested_name_specifier = NULL_TREE;
      else
	{
	  tree scope;
	  for (scope = TREE_TYPE (type);
	       scope && TREE_CODE (scope) != NAMESPACE_DECL;
	       scope = (TYPE_P (scope)
			? TYPE_CONTEXT (scope)
			: DECL_CONTEXT (scope)))
	    if (TYPE_P (scope)
		&& CLASS_TYPE_P (scope)
		&& CLASSTYPE_TEMPLATE_INFO (scope)
		&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope))
		&& !CLASSTYPE_TEMPLATE_SPECIALIZATION (scope))
	      ++num_templates;
	}
    }
  else
    {
      cp_parser_parse_tentatively (parser);
      id = cp_parser_template_id (parser,
				  false,
				  true,
				  true);
      if (!cp_parser_parse_definitely (parser))
	{
	  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
	    id = cp_parser_identifier (parser);
	  else
	    id = NULL_TREE;
	}
      else
	{
	  template_id_p = true;
	  ++num_templates;
	}
    }
  pop_deferring_access_checks ();
  if (id)
    cp_parser_check_for_invalid_template_id (parser, id);
  if (!cp_parser_next_token_starts_class_definition_p (parser))
    {
      cp_parser_error (parser, "expected %<{%> or %<:%>");
      return error_mark_node;
    }
  cp_parser_commit_to_tentative_parse (parser);
  if (qualified_p)
    cp_parser_error (parser,
		     "global qualification of class name is invalid");
  else if (invalid_nested_name_p)
    cp_parser_error (parser,
		     "qualified name does not name a class");
  else if (nested_name_specifier)
    {
      tree scope;
      if (!DECL_IMPLICIT_TYPEDEF_P (type))
	{
	  error ("invalid class name in declaration of %qD", type);
	  type = NULL_TREE;
	  goto done;
	}
      scope = current_scope ();
      if (scope && !is_ancestor (scope, nested_name_specifier))
	{
	  error ("declaration of %qD in %qD which does not enclose %qD",
		 type, scope, nested_name_specifier);
	  type = NULL_TREE;
	  goto done;
	}
      if (scope == nested_name_specifier)
	{
	  pedwarn ("extra qualification ignored");
	  nested_name_specifier = NULL_TREE;
	  num_templates = 0;
	}
    }
  if (at_namespace_scope_p ()
      && parser->num_template_parameter_lists == 0
      && template_id_p)
    {
      error ("an explicit specialization must be preceded by %<template <>%>");
      invalid_explicit_specialization_p = true;
      ++parser->num_template_parameter_lists;
      begin_specialization ();
    }
  if (!cp_parser_check_template_parameters (parser, num_templates))
    {
      type = NULL_TREE;
      goto done;
    }
  if (template_id_p)
    {
      type = TREE_TYPE (id);
      type = maybe_process_partial_specialization (type);
      if (nested_name_specifier)
	pushed_scope = push_scope (nested_name_specifier);
    }
  else if (nested_name_specifier)
    {
      tree class_type;
      if (TREE_CODE (TREE_TYPE (type)) == TYPENAME_TYPE)
	{
	  class_type = resolve_typename_type (TREE_TYPE (type),
					      false);
	  if (class_type != error_mark_node)
	    type = TYPE_NAME (class_type);
	  else
	    {
	      cp_parser_error (parser, "could not resolve typename type");
	      type = error_mark_node;
	    }
	}
      maybe_process_partial_specialization (TREE_TYPE (type));
      class_type = current_class_type;
      pushed_scope = push_scope (nested_name_specifier);
      type = TYPE_MAIN_DECL (TREE_TYPE (type));
      if (PROCESSING_REAL_TEMPLATE_DECL_P ()
	  && !CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (type)))
	{
	  type = push_template_decl (type);
	  if (type == error_mark_node)
	    {
	      type = NULL_TREE;
	      goto done;
	    }
	}
      type = TREE_TYPE (type);
      *nested_name_specifier_p = true;
    }
  else      
    {
      if (!id)
	id = make_anon_name ();
      type = xref_tag (class_key, id, ts_current,
		       parser->num_template_parameter_lists);
    }
  if (TREE_CODE (type) == RECORD_TYPE)
    CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type);
  cp_parser_check_class_key (class_key, type);
  if (type != error_mark_node && COMPLETE_TYPE_P (type))
    {
      error ("redefinition of %q#T", type);
      error ("previous definition of %q+#T", type);
      type = NULL_TREE;
      goto done;
    }
  else if (type == error_mark_node)
    type = NULL_TREE;
  *bases = NULL_TREE;
  if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
    *bases = cp_parser_base_clause (parser);
 done:
  if (pushed_scope)
    pop_scope (pushed_scope);
  if (invalid_explicit_specialization_p)
    {
      end_specialization ();
      --parser->num_template_parameter_lists;
    }
  *attributes_p = attributes;
  return type;
}
static tree cp_parser_class_head ( cp_parser * parser , bool * nested_name_specifier_p , tree * attributes_p , tree * bases ) { tree nested_name_specifier ; enum tag_types class_key ; tree id = NULL_TREE ; tree type = NULL_TREE ; tree attributes ; bool template_id_p = false ; bool qualified_p = false ; bool invalid_nested_name_p = false ; bool invalid_explicit_specialization_p = false ; tree pushed_scope = NULL_TREE ; unsigned num_templates ; * nested_name_specifier_p = false ; num_templates = 0 ; class_key = cp_parser_class_key ( parser ) ; if ( class_key == none_type ) return error_mark_node ; attributes = cp_parser_attributes_opt ( parser ) ; if ( cp_parser_global_scope_opt ( parser , false ) ) qualified_p = true ; push_deferring_access_checks ( dk_no_check ) ; nested_name_specifier = cp_parser_nested_name_specifier_opt ( parser , false , false , false , false ) ; if ( nested_name_specifier ) { cp_parser_parse_tentatively ( parser ) ; type = cp_parser_class_name ( parser , false , false , class_type , false , true , false ) ; if ( ! cp_parser_parse_definitely ( parser ) ) { invalid_nested_name_p = true ; id = cp_parser_identifier ( parser ) ; if ( id == error_mark_node ) id = NULL_TREE ; } if ( type == error_mark_node ) nested_name_specifier = NULL_TREE ; else { tree scope ; for ( scope = TREE_TYPE ( type ) ; scope && TREE_CODE ( scope ) != NAMESPACE_DECL ; scope = ( TYPE_P ( scope ) ? TYPE_CONTEXT ( scope ) : DECL_CONTEXT ( scope ) ) ) if ( TYPE_P ( scope ) && CLASS_TYPE_P ( scope ) && CLASSTYPE_TEMPLATE_INFO ( scope ) && PRIMARY_TEMPLATE_P ( CLASSTYPE_TI_TEMPLATE ( scope ) ) && ! CLASSTYPE_TEMPLATE_SPECIALIZATION ( scope ) ) ++ num_templates ; } } else { cp_parser_parse_tentatively ( parser ) ; id = cp_parser_template_id ( parser , false , true , true ) ; if ( ! cp_parser_parse_definitely ( parser ) ) { if ( cp_lexer_next_token_is ( parser -> lexer , CPP_NAME ) ) id = cp_parser_identifier ( parser ) ; else id = NULL_TREE ; } else { template_id_p = true ; ++ num_templates ; } } pop_deferring_access_checks ( ) ; if ( id ) cp_parser_check_for_invalid_template_id ( parser , id ) ; if ( ! cp_parser_next_token_starts_class_definition_p ( parser ) ) { cp_parser_error ( parser , " " ) ; return error_mark_node ; } cp_parser_commit_to_tentative_parse ( parser ) ; if ( qualified_p ) cp_parser_error ( parser , " " ) ; else if ( invalid_nested_name_p ) cp_parser_error ( parser , " " ) ; else if ( nested_name_specifier ) { tree scope ; if ( ! DECL_IMPLICIT_TYPEDEF_P ( type ) ) { error ( " " , type ) ; type = NULL_TREE ; goto done ; } scope = current_scope ( ) ; if ( scope && ! is_ancestor ( scope , nested_name_specifier ) ) { error ( " " , type , scope , nested_name_specifier ) ; type = NULL_TREE ; goto done ; } if ( scope == nested_name_specifier ) { pedwarn ( " " ) ; nested_name_specifier = NULL_TREE ; num_templates = 0 ; } } if ( at_namespace_scope_p ( ) && parser -> num_template_parameter_lists == 0 && template_id_p ) { error ( " " ) ; invalid_explicit_specialization_p = true ; ++ parser -> num_template_parameter_lists ; begin_specialization ( ) ; } if ( ! cp_parser_check_template_parameters ( parser , num_templates ) ) { type = NULL_TREE ; goto done ; } if ( template_id_p ) { type = TREE_TYPE ( id ) ; type = maybe_process_partial_specialization ( type ) ; if ( nested_name_specifier ) pushed_scope = push_scope ( nested_name_specifier ) ; } else if ( nested_name_specifier ) { tree class_type ; if ( TREE_CODE ( TREE_TYPE ( type ) ) == TYPENAME_TYPE ) { class_type = resolve_typename_type ( TREE_TYPE ( type ) , false ) ; if ( class_type != error_mark_node ) type = TYPE_NAME ( class_type ) ; else { cp_parser_error ( parser , " " ) ; type = error_mark_node ; } } maybe_process_partial_specialization ( TREE_TYPE ( type ) ) ; class_type = current_class_type ; pushed_scope = push_scope ( nested_name_specifier ) ; type = TYPE_MAIN_DECL ( TREE_TYPE ( type ) ) ; if ( PROCESSING_REAL_TEMPLATE_DECL_P ( ) && ! CLASSTYPE_TEMPLATE_SPECIALIZATION ( TREE_TYPE ( type ) ) ) { type = push_template_decl ( type ) ; if ( type == error_mark_node ) { type = NULL_TREE ; goto done ; } } type = TREE_TYPE ( type ) ; * nested_name_specifier_p = true ; } else { if ( ! id ) id = make_anon_name ( ) ; type = xref_tag ( class_key , id , ts_current , parser -> num_template_parameter_lists ) ; } if ( TREE_CODE ( type ) == RECORD_TYPE ) CLASSTYPE_DECLARED_CLASS ( type ) = ( class_key == class_type ) ; cp_parser_check_class_key ( class_key , type ) ; if ( type != error_mark_node && COMPLETE_TYPE_P ( type ) ) { error ( " " , type ) ; error ( " " , type ) ; type = NULL_TREE ; goto done ; } else if ( type == error_mark_node ) type = NULL_TREE ; * bases = NULL_TREE ; if ( cp_lexer_next_token_is ( parser -> lexer , CPP_COLON ) ) * bases = cp_parser_base_clause ( parser ) ; done : if ( pushed_scope ) pop_scope ( pushed_scope ) ; if ( invalid_explicit_specialization_p ) { end_specialization ( ) ; -- parser -> num_template_parameter_lists ; } * attributes_p = attributes ; return type ; }
Parse a class-head.
Parse a class - head .
/* Assume no nested-name-specifier will be present.  */ /* Assume no template parameter lists will be used in defining the
     type.  */ /* Look for the class-key.  */ /* Parse the attributes.  */ /* If the next token is `::', that is invalid -- but sometimes
     people do try to write:

       struct ::S {};

     Handle this gracefully by accepting the extra qualifier, and then
     issuing an error about it later if this really is a
     class-head.  If it turns out just to be an elaborated type
     specifier, remain silent.  */ /*current_scope_valid_p=*/ /* Determine the name of the class.  Begin by looking for an
     optional nested-name-specifier.  */ /*typename_keyword_p=*/ /*check_dependency_p=*/ /*type_p=*/ /*is_declaration=*/ /* If there was a nested-name-specifier, then there *must* be an
     identifier.  */ /* Although the grammar says `identifier', it really means
	 `class-name' or `template-name'.  You are only allowed to
	 define a class that has already been declared with this
	 syntax.

	 The proposed resolution for Core Issue 180 says that wherever
	 you see `class T::X' you should treat `X' as a type-name.

	 It is OK to define an inaccessible class; for example:

	   class A { class B; };
	   class A::B {};

	 We do not know if we will see a class-name, or a
	 template-name.  We look for a class-name first, in case the
	 class-name is a template-id; if we looked for the
	 template-name first we would stop after the template-name.  */ /*typename_keyword_p=*/ /*template_keyword_p=*/ /*check_dependency_p=*/ /*class_head_p=*/ /*is_declaration=*/ /* If that didn't work, ignore the nested-name-specifier.  */ /* If we could not find a corresponding TYPE, treat this
	 declaration like an unqualified declaration.  */ /* Otherwise, count the number of templates used in TYPE and its
	 containing scopes.  */ /* Otherwise, the identifier is optional.  */ /* We don't know whether what comes next is a template-id,
	 an identifier, or nothing at all.  */ /* Check for a template-id.  */ /*template_keyword_p=*/ /*check_dependency_p=*/ /*is_declaration=*/ /* If that didn't work, it could still be an identifier.  */ /* If it's not a `:' or a `{' then we can't really be looking at a
     class-head, since a class-head only appears as part of a
     class-specifier.  We have to detect this situation before calling
     xref_tag, since that has irreversible side-effects.  */ /* At this point, we're going ahead with the class-specifier, even
     if some other problem occurs.  */ /* Issue the error about the overly-qualified name now.  */ /* Reject typedef-names in class heads.  */ /* Figure out in what scope the declaration is being placed.  */ /* If that scope does not contain the scope in which the
	 class was originally declared, the program is invalid.  */ /* [dcl.meaning]

	 A declarator-id shall not be qualified exception of the
	 definition of a ... nested class outside of its class
	 ... [or] a the definition or explicit instantiation of a
	 class member of a namespace outside of its namespace.  */ /* An explicit-specialization must be preceded by "template <>".  If
     it is not, try to recover gracefully.  */ /* Take the same action that would have been taken by
	 cp_parser_explicit_specialization.  */ /* There must be no "return" statements between this point and the
     end of this function; set "type "to the correct return value and
     use "goto done;" to return.  */ /* Make sure that the right number of template parameters were
     present.  */ /* If something went wrong, there is no point in even trying to
	 process the class-definition.  */ /* Look up the type.  */ /* Given:

	    template <typename T> struct S { struct T };
	    template <typename T> struct S<T>::T { };

	 we will get a TYPENAME_TYPE when processing the definition of
	 `S::T'.  We need to resolve it to the actual type before we
	 try to define it.  */ /*only_current_p=*/ /* Enter the scope indicated by the nested-name-specifier.  */ /* Get the canonical version of this type.  */ /* The name is not a nested name.  */ /* If the class was unnamed, create a dummy name.  */ /*tag_scope=*/ /* Indicate whether this class was declared as a `class' or as a
     `struct'.  */ /* If this type was already complete, and we see another definition,
     that's an error.  */ /* We will have entered the scope containing the class; the names of
     base classes should be looked up in that context.  For example:

       struct A { struct B {}; struct C; };
       struct A::C : B {};

     is valid.  */ /* Get the list of base-classes, if there is one.  */ /* Leave the scope given by the nested-name-specifier.  We will
     enter the class scope itself while processing the members.  */