zcov: / lib/Parse/ParseInit.cpp


Files: 1 Branches Taken: 84.5% 82 / 97
Generated: 2010-02-10 01:31 Branches Executed: 95.9% 93 / 97
Line Coverage: 94.6% 87 / 92


Programs: 2 Runs 3018


       1                 : //===--- ParseInit.cpp - Initializer Parsing ------------------------------===//
       2                 : //
       3                 : //                     The LLVM Compiler Infrastructure
       4                 : //
       5                 : // This file is distributed under the University of Illinois Open Source
       6                 : // License. See LICENSE.TXT for details.
       7                 : //
       8                 : //===----------------------------------------------------------------------===//
       9                 : //
      10                 : // This file implements initializer parsing as specified by C99 6.7.8.
      11                 : //
      12                 : //===----------------------------------------------------------------------===//
      13                 : 
      14                 : #include "clang/Parse/Designator.h"
      15                 : #include "clang/Parse/Parser.h"
      16                 : #include "clang/Parse/ParseDiagnostic.h"
      17                 : #include "llvm/ADT/SmallString.h"
      18                 : #include "llvm/Support/raw_ostream.h"
      19                 : using namespace clang;
      20                 : 
      21                 : 
      22                 : /// MayBeDesignationStart - Return true if this token might be the start of a
      23                 : /// designator.  If we can tell it is impossible that it is a designator, return
      24                 : /// false.
      25             2489: static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
                     1622: branch 0 taken
                      183: branch 1 taken
                      684: branch 2 taken
      26             2489:   switch (K) {
      27             1622:   default: return false;
      28                 :   case tok::period:      // designator: '.' identifier
      29                 :   case tok::l_square:    // designator: array-designator
      30              183:       return true;
      31                 :   case tok::identifier:  // designation: identifier ':'
      32              684:     return PP.LookAhead(0).is(tok::colon);
      33                 :   }
      34                 : }
      35                 : 
      36                 : /// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
      37                 : /// checking to see if the token stream starts with a designator.
      38                 : ///
      39                 : ///       designation:
      40                 : ///         designator-list '='
      41                 : /// [GNU]   array-designator
      42                 : /// [GNU]   identifier ':'
      43                 : ///
      44                 : ///       designator-list:
      45                 : ///         designator
      46                 : ///         designator-list designator
      47                 : ///
      48                 : ///       designator:
      49                 : ///         array-designator
      50                 : ///         '.' identifier
      51                 : ///
      52                 : ///       array-designator:
      53                 : ///         '[' constant-expression ']'
      54                 : /// [GNU]   '[' constant-expression '...' constant-expression ']'
      55                 : ///
      56                 : /// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
      57                 : /// initializer (because it is an expression).  We need to consider this case
      58                 : /// when parsing array designators.
      59                 : ///
      60              186: Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
      61                 : 
      62                 :   // If this is the old-style GNU extension:
      63                 :   //   designation ::= identifier ':'
      64                 :   // Handle it as a field designator.  Otherwise, this must be the start of a
      65                 :   // normal expression.
                        3: branch 1 taken
                      183: branch 2 taken
      66              186:   if (Tok.is(tok::identifier)) {
      67                3:     const IdentifierInfo *FieldName = Tok.getIdentifierInfo();
      68                 : 
      69                3:     llvm::SmallString<256> NewSyntax;
      70                 :     llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName()
      71                3:                                          << " = ";
      72                 : 
      73                3:     SourceLocation NameLoc = ConsumeToken(); // Eat the identifier.
      74                 : 
                        3: branch 1 taken
                        0: branch 2 not taken
      75                3:     assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!");
      76                3:     SourceLocation ColonLoc = ConsumeToken();
      77                 : 
      78                 :     Diag(Tok, diag::ext_gnu_old_style_field_designator)
      79                 :       << CodeModificationHint::CreateReplacement(SourceRange(NameLoc,
      80                 :                                                              ColonLoc),
      81                3:                                                  NewSyntax.str());
      82                 : 
      83                3:     Designation D;
      84                3:     D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
      85                 :     return Actions.ActOnDesignatedInitializer(D, ColonLoc, true,
      86                3:                                               ParseInitializer());
      87                 :   }
      88                 : 
      89                 :   // Desig - This is initialized when we see our first designator.  We may have
      90                 :   // an objc message send with no designator, so we don't want to create this
      91                 :   // eagerly.
      92              183:   Designation Desig;
      93                 : 
      94                 :   // Parse each designator in the designator list until we find an initializer.
                       73: branch 1 taken
                       24: branch 2 taken
                      256: branch 4 taken
                      141: branch 5 taken
                      100: branch 7 taken
                      156: branch 8 taken
                      241: branch 9 taken
                      156: branch 10 taken
      95               97:   while (Tok.is(tok::period) || Tok.is(tok::l_square)) {
                      141: branch 1 taken
                      100: branch 2 taken
      96              241:     if (Tok.is(tok::period)) {
      97                 :       // designator: '.' identifier
      98              141:       SourceLocation DotLoc = ConsumeToken();
      99                 : 
                        0: branch 1 not taken
                      141: branch 2 taken
     100              141:       if (Tok.isNot(tok::identifier)) {
     101                0:         Diag(Tok.getLocation(), diag::err_expected_field_designator);
     102                0:         return ExprError();
     103                 :       }
     104                 : 
     105                 :       Desig.AddDesignator(Designator::getField(Tok.getIdentifierInfo(), DotLoc,
     106              141:                                                Tok.getLocation()));
     107              141:       ConsumeToken(); // Eat the identifier.
     108              141:       continue;
     109                 :     }
     110                 : 
     111                 :     // We must have either an array designator now or an objc message send.
                      100: branch 1 taken
                        0: branch 2 not taken
     112              100:     assert(Tok.is(tok::l_square) && "Unexpected token!");
     113                 : 
     114                 :     // Handle the two forms of array designator:
     115                 :     //   array-designator: '[' constant-expression ']'
     116                 :     //   array-designator: '[' constant-expression '...' constant-expression ']'
     117                 :     //
     118                 :     // Also, we have to handle the case where the expression after the
     119                 :     // designator an an objc message send: '[' objc-message-expr ']'.
     120                 :     // Interesting cases are:
     121                 :     //   [foo bar]         -> objc message send
     122                 :     //   [foo]             -> array designator
     123                 :     //   [foo ... bar]     -> array designator
     124                 :     //   [4][foo bar]      -> obsolete GNU designation with objc message send.
     125                 :     //
     126              100:     SourceLocation StartLoc = ConsumeBracket();
     127                 : 
     128                 :     // If Objective-C is enabled and this is a typename or other identifier
     129                 :     // receiver, parse this as a message send expression.
                       29: branch 1 taken
                       71: branch 2 taken
                        3: branch 4 taken
                       26: branch 5 taken
                        3: branch 6 taken
                       97: branch 7 taken
     130              129:     if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) {
     131                 :       // If we have exactly one array designator, this used the GNU
     132                 :       // 'designation: array-designator' extension, otherwise there should be no
     133                 :       // designators at all!
                        1: branch 1 taken
                        2: branch 2 taken
                        0: branch 5 not taken
                        1: branch 6 taken
                        0: branch 9 not taken
                        0: branch 10 not taken
                        1: branch 11 taken
                        2: branch 12 taken
     134                3:       if (Desig.getNumDesignators() == 1 &&
     135                 :           (Desig.getDesignator(0).isArrayDesignator() ||
     136                 :            Desig.getDesignator(0).isArrayRangeDesignator()))
     137                1:         Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
                        0: branch 1 not taken
                        2: branch 2 taken
     138                2:       else if (Desig.getNumDesignators() > 0)
     139                0:         Diag(Tok, diag::err_expected_equal_designator);
     140                 : 
     141                3:       IdentifierInfo *Name = Tok.getIdentifierInfo();
     142                3:       SourceLocation NameLoc = ConsumeToken();
     143                 :       return ParseAssignmentExprWithObjCMessageExprStart(
     144                3:                        StartLoc, NameLoc, Name, ExprArg(Actions));
     145                 :     }
     146                 : 
     147                 :     // Note that we parse this as an assignment expression, not a constant
     148                 :     // expression (allowing *=, =, etc) to handle the objc case.  Sema needs
     149                 :     // to validate that the expression is a constant.
     150               97:     OwningExprResult Idx(ParseAssignmentExpression());
                        1: branch 1 taken
                       96: branch 2 taken
     151               97:     if (Idx.isInvalid()) {
     152                1:       SkipUntil(tok::r_square);
     153                1:       return move(Idx);
     154                 :     }
     155                 : 
     156                 :     // Given an expression, we could either have a designator (if the next
     157                 :     // tokens are '...' or ']' or an objc message send.  If this is an objc
     158                 :     // message send, handle it now.  An objc-message send is the start of
     159                 :     // an assignment-expression production.
                       25: branch 1 taken
                       71: branch 2 taken
                       25: branch 4 taken
                        0: branch 5 not taken
                       23: branch 7 taken
                        2: branch 8 taken
                       23: branch 9 taken
                       73: branch 10 taken
     160               96:     if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
     161                 :         Tok.isNot(tok::r_square)) {
     162                 : 
     163                 :       // If we have exactly one array designator, this used the GNU
     164                 :       // 'designation: array-designator' extension, otherwise there should be no
     165                 :       // designators at all!
                        2: branch 1 taken
                       21: branch 2 taken
                        1: branch 5 taken
                        1: branch 6 taken
                        0: branch 9 not taken
                        1: branch 10 taken
                        1: branch 11 taken
                       22: branch 12 taken
     166               23:       if (Desig.getNumDesignators() == 1 &&
     167                 :           (Desig.getDesignator(0).isArrayDesignator() ||
     168                 :            Desig.getDesignator(0).isArrayRangeDesignator()))
     169                1:         Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
                        1: branch 1 taken
                       21: branch 2 taken
     170               22:       else if (Desig.getNumDesignators() > 0)
     171                1:         Diag(Tok, diag::err_expected_equal_designator);
     172                 : 
     173                 :       return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
     174                 :                                                          SourceLocation(),
     175               23:                                                          0, move(Idx));
     176                 :     }
     177                 : 
     178                 :     // If this is a normal array designator, remember it.
                       65: branch 1 taken
                        8: branch 2 taken
     179               73:     if (Tok.isNot(tok::ellipsis)) {
     180               65:       Desig.AddDesignator(Designator::getArray(Idx.release(), StartLoc));
     181                 :     } else {
     182                 :       // Handle the gnu array range extension.
     183                8:       Diag(Tok, diag::ext_gnu_array_range);
     184                8:       SourceLocation EllipsisLoc = ConsumeToken();
     185                 : 
     186                8:       OwningExprResult RHS(ParseConstantExpression());
                        0: branch 1 not taken
                        8: branch 2 taken
     187                8:       if (RHS.isInvalid()) {
     188                0:         SkipUntil(tok::r_square);
     189                0:         return move(RHS);
     190                 :       }
     191                 :       Desig.AddDesignator(Designator::getArrayRange(Idx.release(),
     192                 :                                                     RHS.release(),
                        8: branch 5 taken
                        0: branch 6 not taken
     193                8:                                                     StartLoc, EllipsisLoc));
     194                 :     }
     195                 : 
     196               73:     SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
     197               73:     Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc(EndLoc);
     198                 :   }
     199                 : 
     200                 :   // Okay, we're done with the designator sequence.  We know that there must be
     201                 :   // at least one designator, because the only case we can get into this method
     202                 :   // without a designator is when we have an objc message send.  That case is
     203                 :   // handled and returned from above.
                      156: branch 1 taken
                        0: branch 2 not taken
     204              156:   assert(!Desig.empty() && "Designator is empty?");
     205                 : 
     206                 :   // Handle a normal designator sequence end, which is an equal.
                      149: branch 1 taken
                        7: branch 2 taken
     207              156:   if (Tok.is(tok::equal)) {
     208              149:     SourceLocation EqualLoc = ConsumeToken();
     209                 :     return Actions.ActOnDesignatedInitializer(Desig, EqualLoc, false,
     210              149:                                               ParseInitializer());
     211                 :   }
     212                 : 
     213                 :   // We read some number of designators and found something that isn't an = or
     214                 :   // an initializer.  If we have exactly one array designator, this
     215                 :   // is the GNU 'designation: array-designator' extension.  Otherwise, it is a
     216                 :   // parse error.
                        6: branch 1 taken
                        1: branch 2 taken
                        0: branch 5 not taken
                        6: branch 6 taken
                        0: branch 9 not taken
                        0: branch 10 not taken
                        6: branch 11 taken
                        1: branch 12 taken
     217                7:   if (Desig.getNumDesignators() == 1 &&
     218                 :       (Desig.getDesignator(0).isArrayDesignator() ||
     219                 :        Desig.getDesignator(0).isArrayRangeDesignator())) {
     220                 :     Diag(Tok, diag::ext_gnu_missing_equal_designator)
     221                6:       << CodeModificationHint::CreateInsertion(Tok.getLocation(), "= ");
     222                 :     return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(),
     223                6:                                               true, ParseInitializer());
     224                 :   }
     225                 : 
     226                1:   Diag(Tok, diag::err_expected_equal_designator);
     227                1:   return ExprError();
     228                 : }
     229                 : 
     230                 : 
     231                 : /// ParseBraceInitializer - Called when parsing an initializer that has a
     232                 : /// leading open brace.
     233                 : ///
     234                 : ///       initializer: [C99 6.7.8]
     235                 : ///         '{' initializer-list '}'
     236                 : ///         '{' initializer-list ',' '}'
     237                 : /// [GNU]   '{' '}'
     238                 : ///
     239                 : ///       initializer-list:
     240                 : ///         designation[opt] initializer
     241                 : ///         initializer-list ',' designation[opt] initializer
     242                 : ///
     243              915: Parser::OwningExprResult Parser::ParseBraceInitializer() {
     244              915:   SourceLocation LBraceLoc = ConsumeBrace();
     245                 : 
     246                 :   /// InitExprs - This is the actual list of expressions contained in the
     247                 :   /// initializer.
     248              915:   ExprVector InitExprs(Actions);
     249                 : 
                       32: branch 1 taken
                      883: branch 2 taken
     250              915:   if (Tok.is(tok::r_brace)) {
     251                 :     // Empty initializers are a C++ feature and a GNU extension to C.
                       23: branch 1 taken
                        9: branch 2 taken
     252               32:     if (!getLang().CPlusPlus)
     253               23:       Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
     254                 :     // Match the '}'.
     255                 :     return Actions.ActOnInitList(LBraceLoc, Action::MultiExprArg(Actions),
     256               32:                                  ConsumeBrace());
     257                 :   }
     258                 : 
     259              883:   bool InitExprsOk = true;
     260                 : 
                     1606: branch 1 taken
                      883: branch 2 taken
     261             2489:   while (1) {
     262                 :     // Parse: designation[opt] initializer
     263                 : 
     264                 :     // If we know that this cannot be a designation, just parse the nested
     265                 :     // initializer directly.
     266             2489:     OwningExprResult SubElt(Actions);
                      186: branch 2 taken
                     2303: branch 3 taken
     267             2489:     if (MayBeDesignationStart(Tok.getKind(), PP))
     268              186:       SubElt = ParseInitializerWithPotentialDesignator();
     269                 :     else
     270             2303:       SubElt = ParseInitializer();
     271                 : 
     272                 :     // If we couldn't parse the subelement, bail out.
                     2480: branch 1 taken
                        9: branch 2 taken
     273             2489:     if (!SubElt.isInvalid()) {
     274             2480:       InitExprs.push_back(SubElt.release());
     275                 :     } else {
     276                9:       InitExprsOk = false;
     277                 : 
     278                 :       // We have two ways to try to recover from this error: if the code looks
     279                 :       // gramatically ok (i.e. we have a comma coming up) try to continue
     280                 :       // parsing the rest of the initializer.  This allows us to emit
     281                 :       // diagnostics for later elements that we find.  If we don't see a comma,
     282                 :       // assume there is a parse error, and just skip to recover.
     283                 :       // FIXME: This comment doesn't sound right. If there is a r_brace
     284                 :       // immediately, it can't be an error, since there is no other way of
     285                 :       // leaving this loop except through this if.
                        5: branch 1 taken
                        4: branch 2 taken
     286                9:       if (Tok.isNot(tok::comma)) {
     287                5:         SkipUntil(tok::r_brace, false, true);
     288                 :         break;
     289                 :       }
     290                 :     }
     291                 : 
     292                 :     // If we don't have a comma continued list, we're done.
                      856: branch 1 taken
                     1628: branch 2 taken
     293             2484:     if (Tok.isNot(tok::comma)) break;
     294                 : 
     295                 :     // TODO: save comma locations if some client cares.
     296             1628:     ConsumeToken();
     297                 : 
     298                 :     // Handle trailing comma.
                       22: branch 1 taken
                     1606: branch 2 taken
     299             1628:     if (Tok.is(tok::r_brace)) break;
     300                 :   }
                      877: branch 0 taken
                        6: branch 1 taken
                      876: branch 3 taken
                        1: branch 4 taken
                      876: branch 5 taken
                        7: branch 6 taken
     301              883:   if (InitExprsOk && Tok.is(tok::r_brace))
     302                 :     return Actions.ActOnInitList(LBraceLoc, move_arg(InitExprs),
     303              876:                                  ConsumeBrace());
     304                 : 
     305                 :   // Match the '}'.
     306                7:   MatchRHSPunctuation(tok::r_brace, LBraceLoc);
     307                7:   return ExprError(); // an error occurred.
     308                 : }
     309                 : 

Generated: 2010-02-10 01:31 by zcov