Studying note of GCC-3.4.6 source (92)

来源:互联网 发布:js删除对象中的元素 编辑:程序博客网 时间:2024/04/28 01:24

5.12.1.2.              Parse decl-specifier-seq part of template declaration

During parsing, we may encounter error statement, to continue parsing as possible, it is prefer to advance to the nearest “>” (of course, if the statement is correct, the next token should be “>”). Next for parsing member template like:

 

template<class T> class string {

public:

template<class T2> int compare(const T2&);

template<class T2> string(const string<T2>& s) { /* ... */ }

// ...

};

template<class T> template<class T2> int string<T>::compare(const T2& s) {}

 

At line 14458 checks for the part “template<class T2>” of the method and processes it in recursion at line 14460.

 

cp_parser_template_declaration_after_export (continue)

 

14452   /* Look for the `>'.  */

14453   cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");

14454   /* We just processed one more parameter list.  */

14455   ++parser->num_template_parameter_lists;

14456   /* If the next token is `template', there are more template

14457     parameters.  */

14458   if (cp_lexer_next_token_is_keyword (parser->lexer,

14459                                  RID_TEMPLATE))

14460     cp_parser_template_declaration_after_export (parser, member_p);

14461   else

14462   {

14463     decl = cp_parser_single_declaration (parser,

14464                                   member_p,

14465                                   &friend_p);

14466

14467     /* If this is a member template declaration, let the front

14468       end know.  */

14469     if (member_p && !friend_p && decl)

14470     {

14471       if (TREE_CODE (decl) == TYPE_DECL)

14472         cp_parser_check_access_in_redeclaration (decl);

14473

14474       decl = finish_member_template_decl (decl);

14475     }

14476     else if (friend_p && decl && TREE_CODE (decl) == TYPE_DECL)

14477       make_friend_class (current_class_type, TREE_TYPE (decl),

14478                       /*complain=*/true);

14479   }

 

In the statement of our run-through example, the unparsed part is: “class SingleThreaded {…”; according to the syntax rule, it should be decl-specifier-seq. Structure decl-specifier-seq contains sequence of decl-specifier, which is a complex structure shown in below.

t

 

14508 static tree

14509 cp_parser_single_declaration (cp_parser* parser,                                        in parser.c

14510                          bool member_p,

14511                          bool* friend_p)

14512 {

14513   int declares_class_or_enum;

14514   tree decl = NULL_TREE;

14515   tree decl_specifiers;

14516   tree attributes;

14517   bool function_definition_p = false;

14518

14519   /* This function is only used when processing a template

14520     declaration.  */

14521   if (innermost_scope_kind () != sk_template_parms

14522       && innermost_scope_kind () != sk_template_spec)

14523     abort ();

14524

14525   /* Defer access checks until we know what is being declared.  */

14526   push_deferring_access_checks (dk_deferred);

14527

14528   /* Try the `decl-specifier-seq [opt] init-declarator [opt]'

14529     alternative.  */

14530   decl_specifiers

14531     = cp_parser_decl_specifier_seq (parser,

14532                               CP_PARSER_FLAGS_OPTIONAL,

14533                               &attributes,

14534                               &declares_class_or_enum);

14535   if (friend_p)

14536     *friend_p = cp_parser_friend_p (decl_specifiers);

14537

14538   /* There are no template typedefs.  */

14539   if (cp_parser_typedef_p (decl_specifiers))

14540   {

14541     error ("template declaration of `typedef'");

14542     decl = error_mark_node;

14543   }

14544

14545   /* Gather up the access checks that occurred the

14546     decl-specifier-seq.  */

14547   stop_deferring_access_checks ();

 

In below function, if declares_class_or_enum is non-null, *declares_class_or_enum is set to the bitwise or of the following flags:

1: one of the decl-specifiers is an elaborated-type-specifier (i.e., a type declaration)

2: one of the decl-specifiers is an enum-specifier or a class-specifier (i.e., a type definition)

 

6642 static tree

6643 cp_parser_decl_specifier_seq (cp_parser* parser,                                          in parser.c

6644                          cp_parser_flags flags,

6645                          tree* attributes,

6646                          int* declares_class_or_enum)

6647 {

6648   tree decl_specs = NULL_TREE;

6649   bool friend_p = false;

6650   bool constructor_possible_p = !parser->in_declarator_p;

6651  

6652   /* Assume no class or enumeration type is declared.  */

6653   *declares_class_or_enum = 0;

6654

6655   /* Assume there are no attributes.  */

6656   *attributes = NULL_TREE;

6657

6658  /* Keep reading specifiers until there are no more to read.  */

6659   while (true)

6660   {

6661     tree decl_spec = NULL_TREE;

6662     bool constructor_p;

6663     cp_token *token;

6664

6665     /* Peek at the next token.  */

6666     token = cp_lexer_peek_token (parser->lexer);

6667     /* Handle attributes.  */

6668     if (token->keyword == RID_ATTRIBUTE)

6669     {

6670       /* Parse the attributes.  */

6671       decl_spec = cp_parser_attributes_opt (parser);

6672       /* Add them to the list.  */

6673       *attributes = chainon (*attributes, decl_spec);

6674       continue;

6675     }

 

We skip GCC entension attribution above and go on for the handling of decl-specifier excluding type-specifier. See that among these items, friend, function-specifier, typedef, storage-class-specifier must be followed by type-specifier (see the break statement). Local variable decl_spec records the information about these items.

 

cp_parser_decl_specifier_seq (continue)

 

6676     /* If the next token is an appropriate keyword, we can simply

6677       add it to the list.  */

6678     switch (token->keyword)

6679     {

6680       case RID_FRIEND:

6681         /* decl-specifier:

6682           friend  */

6683         if (friend_p)

6684           error ("duplicate `friend'");

6685         else

6686           friend_p = true;

6687         /* The representation of the specifier is simply the

6688           appropriate TREE_IDENTIFIER node.  */

6689         decl_spec = token->value;

6690         /* Consume the token.  */

6691         cp_lexer_consume_token (parser->lexer);

6692         break;

6693

6694       /* function-specifier:

6695         inline

6696         virtual

6697         explicit  */

6698       case RID_INLINE:

6699       case RID_VIRTUAL:

6700       case RID_EXPLICIT:

6701         decl_spec = cp_parser_function_specifier_opt (parser);

6702         break;

6703    

6704       /* decl-specifier:

6705         typedef  */

6706       case RID_TYPEDEF:

6707         /* The representation of the specifier is simply the

6708           appropriate TREE_IDENTIFIER node.  */

6709         decl_spec = token->value;

6710         /* Consume the token.  */

6711         cp_lexer_consume_token (parser->lexer);

6712         /* A constructor declarator cannot appear in a typedef.  */

6713         constructor_possible_p = false;

6714         /* The "typedef" keyword can only occur in a declaration; we

6715           may as well commit at this point.  */

6716         cp_parser_commit_to_tentative_parse (parser);

6717         break;

6718

6719       /* storage-class-specifier:

6720         auto

6721         register

6722         static

6723         extern

6724         mutable 

6725

6726         GNU Extension:

6727         thread  */

6728       case RID_AUTO:

6729       case RID_REGISTER:

6730       case RID_STATIC:

6731       case RID_EXTERN:

6732       case RID_MUTABLE:

6733       case RID_THREAD:

6734         decl_spec = cp_parser_storage_class_specifier_opt (parser);

6735         break;

6736    

6737       default:

6738         break;

6739     }

 

Routine cp_parser_function_specifier_opt and cp_parser_storage_class_specifier_opt just double check expected token fetched.

In the language, decl-specifier-seq specify how names are to be interpreted, while a declarator delcares a single object, function, or type, within a declaration. Considering constructor, for example:

class A {

public:

   A();

};

In A(); A should not be parsed as decl-specifier, it is not declaration, instead it is declarator. Notice that A() aligns with the format of simple-declaration, it hasn’t decl-specifier part. As it is a such special case, it needs be handled specially. Of course, it will not be a problem during parsing declarator, note that at line 6713, constructor_possible_p is the reverse of in_declarator_p slot in parser which is true during parsing declarator.

 

cp_parser_decl_specifier_seq (continue)

 

6741     /* Constructors are a special case. The `S' in `S()' is not a

6742       decl-specifier; it is the beginning of the declarator.  */

6743     constructor_p = (!decl_spec

6744                   && constructor_possible_p

6745                   && cp_parser_constructor_declarator_p (parser,

6746                                                     friend_p));

 

Also notice that parsing of constructor here never consumes tokens no matter it successes or not as it is not decl-specifier but declarator. And finding it just means error. To avoid deviating to far away from our focus, we just skip the parsing of constructor here temperarily.

5.12.3.2.1.        Parse type-specifier

If above cases can’t be found, now we can try type-specifier as below. Type-specifier is the key part of decl-specifier-seq, which is the major part of the declaration.

 

cp_parser_decl_specifier_seq (continue)

 

6748     /* If we don't have a DECL_SPEC yet, then we must be looking at

6749       a type-specifier.  */

6750     if (!decl_spec && !constructor_p)

6751     {

6752       int decl_spec_declares_class_or_enum;

6753       bool is_cv_qualifier;

6754

6755       decl_spec

6756          = cp_parser_type_specifier (parser, flags,

6757                                 friend_p,

6758                                 /*is_declaration=*/true,

6759                                 &decl_spec_declares_class_or_enum,

6760                                 &is_cv_qualifier);

6761

6762       *declares_class_or_enum |= decl_spec_declares_class_or_enum;

6763

6764        /* If this type-specifier referenced a user-defined type

6765          (a typedef, class-name, etc.), then we can't allow any

6766          more such type-specifiers henceforth.

6767

6768          [dcl.spec]

6769

6770          The longest sequence of decl-specifiers that could

6771          possibly be a type name is taken as the

6772          decl-specifier-seq of a declaration. The sequence shall

6773          be self-consistent as described below.

6774

6775          [dcl.type]

6776

6777          As a general rule, at most one type-specifier is allowed

6778          in the complete decl-specifier-seq of a declaration. The

6779          only exceptions are the following:

6780

6781          -- const or volatile can be combined with any other

6782            type-specifier.

6783

6784          -- signed or unsigned can be combined with char, long,

6785            short, or int.

6786

6787          -- ..

6788

6789          Example:

6790

6791            typedef char* Pc;

6792            void g (const int Pc);

6793

6794          Here, Pc is *not* part of the decl-specifier seq; it's

6795         the declarator. Therefore, once we see a type-specifier

6796          (other than a cv-qualifier), we forbid any additional

6797          user-defined types. We *do* still allow things like `int

6798          int' to be considered a decl-specifier-seq, and issue the

6799          error message later.  */

6800        if (decl_spec && !is_cv_qualifier)

6801          flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;

6802        /* A constructor declarator cannot follow a type-specifier.  */

6803        if (decl_spec)

6804          constructor_possible_p = false;

6805     }

 

The abbreviate syntax tree of type-specifier is shown in below.

type-specifier

simple-type-specifier

├ class-specifier

├ enum-specifier

├ elaborated-type-specifier

├ cv-qualifier

GUN ext __complex__

In below function, parameter declares_class_or_enum if non-null, and the type-specifier is a class-specifier, enum-specifier, or elaborated-type-specifier, then *declares_class_or_enum is set to a nonzero value. The value is 1 if a type is declared, 2 if it is defined; otherwise, it is set to zero. And if is_cv_qualifier is non-null, and the type-specifier is a cv-qualifier, then *is_cv_qualifier is set to true; otherwise, it is set to false.

 

8713 static tree

8714 cp_parser_type_specifier (cp_parser* parser,                                                in parser.c

8715                      cp_parser_flags flags,

8716                      bool is_friend,

8717                      bool is_declaration,

8718                      int* declares_class_or_enum,

8719                      bool* is_cv_qualifier)

8720 {

8721   tree type_spec = NULL_TREE;

8722   cp_token *token;

8723   enum rid keyword;

8724

8725  /* Assume this type-specifier does not declare a new type.  */

8726   if (declares_class_or_enum)

8727     *declares_class_or_enum = 0;

8728   /* And that it does not specify a cv-qualifier.  */

8729   if (is_cv_qualifier)

8730     *is_cv_qualifier = false;

8731  /* Peek at the next token.  */

8732   token = cp_lexer_peek_token (parser->lexer);

8733

8734  /* If we're looking at a keyword, we can use that to guide the

8735     production we choose.  */

8736   keyword = token->keyword;

8737   switch (keyword)

8738   {

8739     case RID_ENUM:

            ...

8763     /* Any of these indicate either a class-specifier, or an

8764       elaborated-type-specifier.  */

8765     case RID_CLASS:

8766     case RID_STRUCT:

8767     case RID_UNION:

8768       /* Parse tentatively so that we can back up if we don't find a

8769         class-specifier or enum-specifier.  */

8770       cp_parser_parse_tentatively (parser);

8771       /* Look for the class-specifier.  */

8772       type_spec = cp_parser_class_specifier (parser);

8773       /* If that worked, we're done.  */

8774       if (cp_parser_parse_definitely (parser))

8775       {

8776         if (declares_class_or_enum)

8777           *declares_class_or_enum = 2;

8778         return type_spec;

8779       }

 

The coming tokens of the second statement of our example form the class-specifier. They are further handled by cp_parser_class_specifier.