Пример #1
0
/// \brief Replaces a template-id annotation token with a type
/// annotation token.
///
/// If there was a failure when forming the type from the template-id,
/// a type annotation token will still be created, but will have a
/// NULL type pointer to signify an error.
void Parser::AnnotateTemplateIdTokenAsType() {
  assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");

  TemplateIdAnnotation *TemplateId
    = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
  assert((TemplateId->Kind == TNK_Type_template ||
          TemplateId->Kind == TNK_Dependent_template_name) &&
         "Only works for type and dependent templates");

  ASTTemplateArgsPtr TemplateArgsPtr(Actions,
                                     TemplateId->getTemplateArgs(),
                                     TemplateId->NumArgs);

  TypeResult Type
    = Actions.ActOnTemplateIdType(TemplateId->SS,
                                  TemplateId->Template,
                                  TemplateId->TemplateNameLoc,
                                  TemplateId->LAngleLoc,
                                  TemplateArgsPtr,
                                  TemplateId->RAngleLoc);
  // Create the new "type" annotation token.
  Tok.setKind(tok::annot_typename);
  setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get());
  if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name.
    Tok.setLocation(TemplateId->SS.getBeginLoc());
  // End location stays the same

  // Replace the template-id annotation token, and possible the scope-specifier
  // that precedes it, with the typename annotation token.
  PP.AnnotateCachedTokens(Tok);
  TemplateId->Destroy();
}
Пример #2
0
/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
///
///       template-argument: [C++ 14.2]
///         constant-expression
///         type-id
///         id-expression
ParsedTemplateArgument Parser::ParseTemplateArgument() {
  // C++ [temp.arg]p2:
  //   In a template-argument, an ambiguity between a type-id and an
  //   expression is resolved to a type-id, regardless of the form of
  //   the corresponding template-parameter.
  //
  // Therefore, we initially try to parse a type-id.  
  if (isCXXTypeId(TypeIdAsTemplateArgument)) {
    SourceLocation Loc = Tok.getLocation();
    TypeResult TypeArg = ParseTypeName(/*Range=*/0, 
                                       Declarator::TemplateTypeArgContext);
    if (TypeArg.isInvalid())
      return ParsedTemplateArgument();
    
    return ParsedTemplateArgument(ParsedTemplateArgument::Type,
                                  TypeArg.get().getAsOpaquePtr(), 
                                  Loc);
  }
  
  // Try to parse a template template argument.
  {
    TentativeParsingAction TPA(*this);

    ParsedTemplateArgument TemplateTemplateArgument
      = ParseTemplateTemplateArgument();
    if (!TemplateTemplateArgument.isInvalid()) {
      TPA.Commit();
      return TemplateTemplateArgument;
    }
    
    // Revert this tentative parse to parse a non-type template argument.
    TPA.Revert();
  }
  
  // Parse a non-type template argument. 
  SourceLocation Loc = Tok.getLocation();
  ExprResult ExprArg = ParseConstantExpression();
  if (ExprArg.isInvalid() || !ExprArg.get())
    return ParsedTemplateArgument();

  return ParsedTemplateArgument(ParsedTemplateArgument::NonType, 
                                ExprArg.release(), Loc);
}
ParsedTemplateArgument 
Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
                         SourceLocation EllipsisLoc) {
  if (Arg.isInvalid())
    return Arg;

  switch (Arg.getKind()) {
  case ParsedTemplateArgument::Type: {
    TypeResult Result = ActOnPackExpansion(Arg.getAsType(), EllipsisLoc);
    if (Result.isInvalid())
      return ParsedTemplateArgument();

    return ParsedTemplateArgument(Arg.getKind(), Result.get().getAsOpaquePtr(), 
                                  Arg.getLocation());
  }

  case ParsedTemplateArgument::NonType: {
    ExprResult Result = ActOnPackExpansion(Arg.getAsExpr(), EllipsisLoc);
    if (Result.isInvalid())
      return ParsedTemplateArgument();
    
    return ParsedTemplateArgument(Arg.getKind(), Result.get(), 
                                  Arg.getLocation());
  }
    
  case ParsedTemplateArgument::Template:
    if (!Arg.getAsTemplate().get().containsUnexpandedParameterPack()) {
      SourceRange R(Arg.getLocation());
      if (Arg.getScopeSpec().isValid())
        R.setBegin(Arg.getScopeSpec().getBeginLoc());
      Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
        << R;
      return ParsedTemplateArgument();
    }
      
    return Arg.getTemplatePackExpansion(EllipsisLoc);
  }
  llvm_unreachable("Unhandled template argument kind?");
  return ParsedTemplateArgument();
}
Пример #4
0
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
                                             bool isAmbiguous,
                                             SourceLocation LParenLoc,
                                             ParamInfo *Params,
                                             unsigned NumParams,
                                             SourceLocation EllipsisLoc,
                                             SourceLocation RParenLoc,
                                             unsigned TypeQuals,
                                             bool RefQualifierIsLvalueRef,
                                             SourceLocation RefQualifierLoc,
                                             SourceLocation ConstQualifierLoc,
                                             SourceLocation
                                                 VolatileQualifierLoc,
                                             SourceLocation
                                                 RestrictQualifierLoc,
                                             SourceLocation MutableLoc,
                                             ExceptionSpecificationType
                                                 ESpecType,
                                             SourceLocation ESpecLoc,
                                             ParsedType *Exceptions,
                                             SourceRange *ExceptionRanges,
                                             unsigned NumExceptions,
                                             Expr *NoexceptExpr,
                                             CachedTokens *ExceptionSpecTokens,
                                             SourceLocation LocalRangeBegin,
                                             SourceLocation LocalRangeEnd,
                                             Declarator &TheDeclarator,
                                             TypeResult TrailingReturnType) {
  assert(!(TypeQuals & DeclSpec::TQ_atomic) &&
         "function cannot have _Atomic qualifier");

  DeclaratorChunk I;
  I.Kind                        = Function;
  I.Loc                         = LocalRangeBegin;
  I.EndLoc                      = LocalRangeEnd;
  I.Fun.AttrList                = nullptr;
  I.Fun.hasPrototype            = hasProto;
  I.Fun.isVariadic              = EllipsisLoc.isValid();
  I.Fun.isAmbiguous             = isAmbiguous;
  I.Fun.LParenLoc               = LParenLoc.getRawEncoding();
  I.Fun.EllipsisLoc             = EllipsisLoc.getRawEncoding();
  I.Fun.RParenLoc               = RParenLoc.getRawEncoding();
  I.Fun.DeleteParams            = false;
  I.Fun.TypeQuals               = TypeQuals;
  I.Fun.NumParams               = NumParams;
  I.Fun.Params                  = nullptr;
  I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef;
  I.Fun.RefQualifierLoc         = RefQualifierLoc.getRawEncoding();
  I.Fun.ConstQualifierLoc       = ConstQualifierLoc.getRawEncoding();
  I.Fun.VolatileQualifierLoc    = VolatileQualifierLoc.getRawEncoding();
  I.Fun.RestrictQualifierLoc    = RestrictQualifierLoc.getRawEncoding();
  I.Fun.MutableLoc              = MutableLoc.getRawEncoding();
  I.Fun.ExceptionSpecType       = ESpecType;
  I.Fun.ExceptionSpecLoc        = ESpecLoc.getRawEncoding();
  I.Fun.NumExceptions           = 0;
  I.Fun.Exceptions              = nullptr;
  I.Fun.NoexceptExpr            = nullptr;
  I.Fun.HasTrailingReturnType   = TrailingReturnType.isUsable() ||
                                  TrailingReturnType.isInvalid();
  I.Fun.TrailingReturnType      = TrailingReturnType.get();

  assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow");
  assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow");

  // new[] a parameter array if needed.
  if (NumParams) {
    // If the 'InlineParams' in Declarator is unused and big enough, put our
    // parameter list there (in an effort to avoid new/delete traffic).  If it
    // is already used (consider a function returning a function pointer) or too
    // small (function with too many parameters), go to the heap.
    if (!TheDeclarator.InlineParamsUsed &&
        NumParams <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
      I.Fun.Params = TheDeclarator.InlineParams;
      I.Fun.DeleteParams = false;
      TheDeclarator.InlineParamsUsed = true;
    } else {
      I.Fun.Params = new DeclaratorChunk::ParamInfo[NumParams];
      I.Fun.DeleteParams = true;
    }
    memcpy(I.Fun.Params, Params, sizeof(Params[0]) * NumParams);
  }

  // Check what exception specification information we should actually store.
  switch (ESpecType) {
  default: break; // By default, save nothing.
  case EST_Dynamic:
    // new[] an exception array if needed
    if (NumExceptions) {
      I.Fun.NumExceptions = NumExceptions;
      I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
      for (unsigned i = 0; i != NumExceptions; ++i) {
        I.Fun.Exceptions[i].Ty = Exceptions[i];
        I.Fun.Exceptions[i].Range = ExceptionRanges[i];
      }
    }
    break;

  case EST_ComputedNoexcept:
    I.Fun.NoexceptExpr = NoexceptExpr;
    break;

  case EST_Unparsed:
    I.Fun.ExceptionSpecTokens = ExceptionSpecTokens;
    break;
  }
  return I;
}
Пример #5
0
/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
/// checking to see if the token stream starts with a designator.
///
///       designation:
///         designator-list '='
/// [GNU]   array-designator
/// [GNU]   identifier ':'
///
///       designator-list:
///         designator
///         designator-list designator
///
///       designator:
///         array-designator
///         '.' identifier
///
///       array-designator:
///         '[' constant-expression ']'
/// [GNU]   '[' constant-expression '...' constant-expression ']'
///
/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
/// initializer (because it is an expression).  We need to consider this case
/// when parsing array designators.
///
ExprResult Parser::ParseInitializerWithPotentialDesignator() {

  // If this is the old-style GNU extension:
  //   designation ::= identifier ':'
  // Handle it as a field designator.  Otherwise, this must be the start of a
  // normal expression.
  if (Tok.is(tok::identifier)) {
    const IdentifierInfo *FieldName = Tok.getIdentifierInfo();

    SmallString<256> NewSyntax;
    llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName()
                                         << " = ";

    SourceLocation NameLoc = ConsumeToken(); // Eat the identifier.

    assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!");
    SourceLocation ColonLoc = ConsumeToken();

    Diag(NameLoc, diag::ext_gnu_old_style_field_designator)
      << FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc),
                                      NewSyntax);

    Designation D;
    D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
    return Actions.ActOnDesignatedInitializer(D, ColonLoc, true,
                                              ParseInitializer());
  }

  // Desig - This is initialized when we see our first designator.  We may have
  // an objc message send with no designator, so we don't want to create this
  // eagerly.
  Designation Desig;

  // Parse each designator in the designator list until we find an initializer.
  while (Tok.is(tok::period) || Tok.is(tok::l_square)) {
    if (Tok.is(tok::period)) {
      // designator: '.' identifier
      SourceLocation DotLoc = ConsumeToken();

      if (Tok.isNot(tok::identifier)) {
        Diag(Tok.getLocation(), diag::err_expected_field_designator);
        return ExprError();
      }

      Desig.AddDesignator(Designator::getField(Tok.getIdentifierInfo(), DotLoc,
                                               Tok.getLocation()));
      ConsumeToken(); // Eat the identifier.
      continue;
    }

    // We must have either an array designator now or an objc message send.
    assert(Tok.is(tok::l_square) && "Unexpected token!");

    // Handle the two forms of array designator:
    //   array-designator: '[' constant-expression ']'
    //   array-designator: '[' constant-expression '...' constant-expression ']'
    //
    // Also, we have to handle the case where the expression after the
    // designator an an objc message send: '[' objc-message-expr ']'.
    // Interesting cases are:
    //   [foo bar]         -> objc message send
    //   [foo]             -> array designator
    //   [foo ... bar]     -> array designator
    //   [4][foo bar]      -> obsolete GNU designation with objc message send.
    //
    // We do not need to check for an expression starting with [[ here. If it
    // contains an Objective-C message send, then it is not an ill-formed
    // attribute. If it is a lambda-expression within an array-designator, then
    // it will be rejected because a constant-expression cannot begin with a
    // lambda-expression.
    InMessageExpressionRAIIObject InMessage(*this, true);

    BalancedDelimiterTracker T(*this, tok::l_square);
    T.consumeOpen();
    SourceLocation StartLoc = T.getOpenLocation();

    ExprResult Idx;

    // If Objective-C is enabled and this is a typename (class message
    // send) or send to 'super', parse this as a message send
    // expression.  We handle C++ and C separately, since C++ requires
    // much more complicated parsing.
    if  (getLangOpts().ObjC && getLangOpts().CPlusPlus) {
      // Send to 'super'.
      if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
          NextToken().isNot(tok::period) &&
          getCurScope()->isInObjcMethodScope()) {
        CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
        return ParseAssignmentExprWithObjCMessageExprStart(
            StartLoc, ConsumeToken(), nullptr, nullptr);
      }

      // Parse the receiver, which is either a type or an expression.
      bool IsExpr;
      void *TypeOrExpr;
      if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
        SkipUntil(tok::r_square, StopAtSemi);
        return ExprError();
      }

      // If the receiver was a type, we have a class message; parse
      // the rest of it.
      if (!IsExpr) {
        CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
        return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
                                                           SourceLocation(),
                                   ParsedType::getFromOpaquePtr(TypeOrExpr),
                                                           nullptr);
      }

      // If the receiver was an expression, we still don't know
      // whether we have a message send or an array designator; just
      // adopt the expression for further analysis below.
      // FIXME: potentially-potentially evaluated expression above?
      Idx = ExprResult(static_cast<Expr*>(TypeOrExpr));
    } else if (getLangOpts().ObjC && Tok.is(tok::identifier)) {
      IdentifierInfo *II = Tok.getIdentifierInfo();
      SourceLocation IILoc = Tok.getLocation();
      ParsedType ReceiverType;
      // Three cases. This is a message send to a type: [type foo]
      // This is a message send to super:  [super foo]
      // This is a message sent to an expr:  [super.bar foo]
      switch (Actions.getObjCMessageKind(
          getCurScope(), II, IILoc, II == Ident_super,
          NextToken().is(tok::period), ReceiverType)) {
      case Sema::ObjCSuperMessage:
        CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
        return ParseAssignmentExprWithObjCMessageExprStart(
            StartLoc, ConsumeToken(), nullptr, nullptr);

      case Sema::ObjCClassMessage:
        CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
        ConsumeToken(); // the identifier
        if (!ReceiverType) {
          SkipUntil(tok::r_square, StopAtSemi);
          return ExprError();
        }

        // Parse type arguments and protocol qualifiers.
        if (Tok.is(tok::less)) {
          SourceLocation NewEndLoc;
          TypeResult NewReceiverType
            = parseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType,
                                                     /*consumeLastToken=*/true,
                                                     NewEndLoc);
          if (!NewReceiverType.isUsable()) {
            SkipUntil(tok::r_square, StopAtSemi);
            return ExprError();
          }

          ReceiverType = NewReceiverType.get();
        }

        return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
                                                           SourceLocation(),
                                                           ReceiverType,
                                                           nullptr);

      case Sema::ObjCInstanceMessage:
        // Fall through; we'll just parse the expression and
        // (possibly) treat this like an Objective-C message send
        // later.
        break;
      }
    }

    // Parse the index expression, if we haven't already gotten one
    // above (which can only happen in Objective-C++).
    // Note that we parse this as an assignment expression, not a constant
    // expression (allowing *=, =, etc) to handle the objc case.  Sema needs
    // to validate that the expression is a constant.
    // FIXME: We also need to tell Sema that we're in a
    // potentially-potentially evaluated context.
    if (!Idx.get()) {
      Idx = ParseAssignmentExpression();
      if (Idx.isInvalid()) {
        SkipUntil(tok::r_square, StopAtSemi);
        return Idx;
      }
    }

    // Given an expression, we could either have a designator (if the next
    // tokens are '...' or ']' or an objc message send.  If this is an objc
    // message send, handle it now.  An objc-message send is the start of
    // an assignment-expression production.
    if (getLangOpts().ObjC && Tok.isNot(tok::ellipsis) &&
        Tok.isNot(tok::r_square)) {
      CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);
      return ParseAssignmentExprWithObjCMessageExprStart(
          StartLoc, SourceLocation(), nullptr, Idx.get());
    }

    // If this is a normal array designator, remember it.
    if (Tok.isNot(tok::ellipsis)) {
      Desig.AddDesignator(Designator::getArray(Idx.get(), StartLoc));
    } else {
      // Handle the gnu array range extension.
      Diag(Tok, diag::ext_gnu_array_range);
      SourceLocation EllipsisLoc = ConsumeToken();

      ExprResult RHS(ParseConstantExpression());
      if (RHS.isInvalid()) {
        SkipUntil(tok::r_square, StopAtSemi);
        return RHS;
      }
      Desig.AddDesignator(Designator::getArrayRange(Idx.get(),
                                                    RHS.get(),
                                                    StartLoc, EllipsisLoc));
    }

    T.consumeClose();
    Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc(
                                                        T.getCloseLocation());
  }

  // Okay, we're done with the designator sequence.  We know that there must be
  // at least one designator, because the only case we can get into this method
  // without a designator is when we have an objc message send.  That case is
  // handled and returned from above.
  assert(!Desig.empty() && "Designator is empty?");

  // Handle a normal designator sequence end, which is an equal.
  if (Tok.is(tok::equal)) {
    SourceLocation EqualLoc = ConsumeToken();
    return Actions.ActOnDesignatedInitializer(Desig, EqualLoc, false,
                                              ParseInitializer());
  }

  // We read some number of designators and found something that isn't an = or
  // an initializer.  If we have exactly one array designator, this
  // is the GNU 'designation: array-designator' extension.  Otherwise, it is a
  // parse error.
  if (Desig.getNumDesignators() == 1 &&
      (Desig.getDesignator(0).isArrayDesignator() ||
       Desig.getDesignator(0).isArrayRangeDesignator())) {
    Diag(Tok, diag::ext_gnu_missing_equal_designator)
      << FixItHint::CreateInsertion(Tok.getLocation(), "= ");
    return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(),
                                              true, ParseInitializer());
  }

  Diag(Tok, diag::err_expected_equal_designator);
  return ExprError();
}
Пример #6
0
/// \brief Replace the tokens that form a simple-template-id with an
/// annotation token containing the complete template-id.
///
/// The first token in the stream must be the name of a template that
/// is followed by a '<'. This routine will parse the complete
/// simple-template-id and replace the tokens with a single annotation
/// token with one of two different kinds: if the template-id names a
/// type (and \p AllowTypeAnnotation is true), the annotation token is
/// a type annotation that includes the optional nested-name-specifier
/// (\p SS). Otherwise, the annotation token is a template-id
/// annotation that does not include the optional
/// nested-name-specifier.
///
/// \param Template  the declaration of the template named by the first
/// token (an identifier), as returned from \c Action::isTemplateName().
///
/// \param TemplateNameKind the kind of template that \p Template
/// refers to, as returned from \c Action::isTemplateName().
///
/// \param SS if non-NULL, the nested-name-specifier that precedes
/// this template name.
///
/// \param TemplateKWLoc if valid, specifies that this template-id
/// annotation was preceded by the 'template' keyword and gives the
/// location of that keyword. If invalid (the default), then this
/// template-id was not preceded by a 'template' keyword.
///
/// \param AllowTypeAnnotation if true (the default), then a
/// simple-template-id that refers to a class template, template
/// template parameter, or other template that produces a type will be
/// replaced with a type annotation token. Otherwise, the
/// simple-template-id is always replaced with a template-id
/// annotation token.
///
/// If an unrecoverable parse error occurs and no annotation token can be
/// formed, this function returns true.
///
bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
                                     CXXScopeSpec &SS,
                                     UnqualifiedId &TemplateName,
                                     SourceLocation TemplateKWLoc,
                                     bool AllowTypeAnnotation) {
  assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
  assert(Template && Tok.is(tok::less) &&
         "Parser isn't at the beginning of a template-id");

  // Consume the template-name.
  SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin();

  // Parse the enclosed template argument list.
  SourceLocation LAngleLoc, RAngleLoc;
  TemplateArgList TemplateArgs;
  bool Invalid = ParseTemplateIdAfterTemplateName(Template, 
                                                  TemplateNameLoc,
                                                  SS, false, LAngleLoc,
                                                  TemplateArgs,
                                                  RAngleLoc);

  if (Invalid) {
    // If we failed to parse the template ID but skipped ahead to a >, we're not
    // going to be able to form a token annotation.  Eat the '>' if present.
    if (Tok.is(tok::greater))
      ConsumeToken();
    return true;
  }

  ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
                                     TemplateArgs.size());

  // Build the annotation token.
  if (TNK == TNK_Type_template && AllowTypeAnnotation) {
    TypeResult Type
      = Actions.ActOnTemplateIdType(SS, 
                                    Template, TemplateNameLoc,
                                    LAngleLoc, TemplateArgsPtr,
                                    RAngleLoc);
    if (Type.isInvalid()) {
      // If we failed to parse the template ID but skipped ahead to a >, we're not
      // going to be able to form a token annotation.  Eat the '>' if present.
      if (Tok.is(tok::greater))
        ConsumeToken();
      return true;
    }

    Tok.setKind(tok::annot_typename);
    setTypeAnnotation(Tok, Type.get());
    if (SS.isNotEmpty())
      Tok.setLocation(SS.getBeginLoc());
    else if (TemplateKWLoc.isValid())
      Tok.setLocation(TemplateKWLoc);
    else
      Tok.setLocation(TemplateNameLoc);
  } else {
    // Build a template-id annotation token that can be processed
    // later.
    Tok.setKind(tok::annot_template_id);
    TemplateIdAnnotation *TemplateId
      = TemplateIdAnnotation::Allocate(TemplateArgs.size());
    TemplateId->TemplateNameLoc = TemplateNameLoc;
    if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) {
      TemplateId->Name = TemplateName.Identifier;
      TemplateId->Operator = OO_None;
    } else {
      TemplateId->Name = 0;
      TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
    }
    TemplateId->SS = SS;
    TemplateId->Template = Template;
    TemplateId->Kind = TNK;
    TemplateId->LAngleLoc = LAngleLoc;
    TemplateId->RAngleLoc = RAngleLoc;
    ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
    for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
      Args[Arg] = ParsedTemplateArgument(TemplateArgs[Arg]);
    Tok.setAnnotationValue(TemplateId);
    if (TemplateKWLoc.isValid())
      Tok.setLocation(TemplateKWLoc);
    else
      Tok.setLocation(TemplateNameLoc);

    TemplateArgsPtr.release();
  }

  // Common fields for the annotation token
  Tok.setAnnotationEndLoc(RAngleLoc);

  // In case the tokens were cached, have Preprocessor replace them with the
  // annotation token.
  PP.AnnotateCachedTokens(Tok);
  return false;
}
Пример #7
0
/// ParseParenExpr - Parse a parenthesized expression with the given
/// \arg ExpectedType. \arg ExpectedType can be invalid if the type
/// cannot be inferred from the context.
///
/// paren-expr = '(' type number ')'
/// paren-expr = '(' identifier [type] expr+ ')
/// paren-expr = '(' ('Read' | 'ReadMSB' | 'ReadLSB') type expr update-list ')'
ExprResult ParserImpl::ParseParenExpr(TypeResult FIXME_UNUSED) {
  if (Tok.kind != Token::LParen) {
    Error("unexpected token.");
    ConsumeAnyToken();
    return ExprResult();
  }

  ConsumeLParen();
  
  // Check for coercion case (w32 11).
  if (Tok.kind == Token::KWWidth) {
    TypeResult ExpectedType = ParseTypeSpecifier();

    if (Tok.kind != Token::Number) {
      Error("coercion can only apply to a number.");
      SkipUntilRParen();
      return ExprResult();
    }
    
    // Make sure this was a type specifier we support.
    ExprResult Res;
    if (ExpectedType.isValid()) 
      Res = ParseNumber(ExpectedType.get());
    else
      ConsumeToken();

    ExpectRParen("unexpected argument in coercion.");  
    return Res;
  }
  
  if (Tok.kind != Token::Identifier) {
    Error("unexpected token, expected expression.");
    SkipUntilRParen();
    return ExprResult();
  }

  Token Name = Tok;
  ConsumeToken();

  // FIXME: Use invalid type (i.e. width==0)?
  Token TypeTok = Tok;
  bool HasType = TypeTok.kind == Token::KWWidth;
  TypeResult Type = HasType ? ParseTypeSpecifier() : Expr::Bool;

  // FIXME: For now just skip to rparen on error. It might be nice
  // to try and actually parse the child nodes though for error
  // messages & better recovery?
  if (!Type.isValid()) {
    SkipUntilRParen();
    return ExprResult();
  }
  Expr::Width ResTy = Type.get();

  unsigned ExprKind;
  bool IsFixed;
  int NumArgs;
  if (!LookupExprInfo(Name, ExprKind, IsFixed, NumArgs)) {
    // FIXME: For now just skip to rparen on error. It might be nice
    // to try and actually parse the child nodes though for error
    // messages & better recovery?
    Error("unknown expression kind.", Name);
    SkipUntilRParen();
    return ExprResult();
  }

  // See if we have to parse this form specially.
  if (NumArgs == -1) {
    switch (ExprKind) {
    case eMacroKind_Concat:
      return ParseConcatParenExpr(Name, ResTy);

    case Expr::Extract:
      return ParseExtractParenExpr(Name, ResTy);

    case eMacroKind_ReadLSB:
    case eMacroKind_ReadMSB:
    case Expr::Read:
      return ParseAnyReadParenExpr(Name, ExprKind, ResTy);

    default:
      Error("internal error, unimplemented special form.", Name);
      SkipUntilRParen();
      return ExprResult(Builder->Constant(0, ResTy));
    }
  }

  switch (NumArgs) {
  case 1:
    return ParseUnaryParenExpr(Name, ExprKind, IsFixed, ResTy);
  case 2:
    return ParseBinaryParenExpr(Name, ExprKind, IsFixed, ResTy);
  case 3:
    if (ExprKind == Expr::Select)
      return ParseSelectParenExpr(Name, ResTy);
  default:
    assert(0 && "Invalid argument kind (number of args).");
    return ExprResult();
  }
}
Пример #8
0
/// ParseExpr - Parse an expression with the given \arg
/// ExpectedType. \arg ExpectedType can be invalid if the type cannot
/// be inferred from the context.
///
/// expr = false | true
/// expr = <constant>
/// expr = <identifier>
/// expr = [<identifier>:] paren-expr
ExprResult ParserImpl::ParseExpr(TypeResult ExpectedType) {
  // FIXME: Is it right to need to do this here?
  if (Tok.kind == Token::EndOfFile) {
    Error("unexpected end of file.");
    return ExprResult();
  }

  if (Tok.kind == Token::KWFalse || Tok.kind == Token::KWTrue) {
    bool Value = Tok.kind == Token::KWTrue;
    ConsumeToken();
    return ExprResult(Builder->Constant(Value, Expr::Bool));
  }
  
  if (Tok.kind == Token::Number) {
    if (!ExpectedType.isValid()) {
      Error("cannot infer type of number.");
      ConsumeToken();
      return ExprResult();
    }
    
    return ParseNumber(ExpectedType.get());
  }

  const Identifier *Label = 0;
  if (Tok.kind == Token::Identifier) {
    Token LTok = Tok;
    Label = GetOrCreateIdentifier(Tok);
    ConsumeToken();

    if (Tok.kind != Token::Colon) {
      ExprSymTabTy::iterator it = ExprSymTab.find(Label);

      if (it == ExprSymTab.end()) {
        Error("invalid expression label reference.", LTok);
        return ExprResult();
      }

      return it->second;
    }

    ConsumeToken();
    if (ExprSymTab.count(Label)) {
      Error("duplicate expression label definition.", LTok);
      Label = 0;
    }
  }

  Token Start = Tok;
  ExprResult Res = ParseParenExpr(ExpectedType);
  if (!Res.isValid()) {
    // If we know the type, define the identifier just so we don't get
    // use-of-undef errors. 
    // FIXME: Maybe we should let the symbol table map to invalid
    // entries?
    if (Label && ExpectedType.isValid()) {
      ref<Expr> Value = Builder->Constant(0, ExpectedType.get());
      ExprSymTab.insert(std::make_pair(Label, Value));
    }
    return Res;
  } else if (ExpectedType.isValid()) {
    // Type check result.    
    if (Res.get()->getWidth() != ExpectedType.get()) {
      // FIXME: Need more info, and range
      Error("expression has incorrect type.", Start);
      return ExprResult();
    }
  }

  if (Label)
    ExprSymTab.insert(std::make_pair(Label, Res.get()));
  return Res;
}
Пример #9
0
/// ParseArrayDecl - Parse an array declaration. The lexer should be positioned
/// at the opening 'array'.
///
/// array-declaration = "array" name "[" [ size ] "]" ":" domain "->" range 
///                       "=" array-initializer
/// array-initializer = "symbolic" | "{" { numeric-literal } "}"
DeclResult ParserImpl::ParseArrayDecl() {
  // FIXME: Recovery here is horrible, we need to scan to next decl start or
  // something.
  ConsumeExpectedToken(Token::KWArray);
  
  if (Tok.kind != Token::Identifier) {
    Error("expected identifier token.");
    return DeclResult();
  }

  Token Name = Tok;
  IntegerResult Size;
  TypeResult DomainType;
  TypeResult RangeType;
  std::vector< ref<ConstantExpr> > Values;

  ConsumeToken();
  
  if (Tok.kind != Token::LSquare) {
    Error("expected '['.");
    goto exit;
  }
  ConsumeLSquare();

  if (Tok.kind != Token::RSquare) {
    Size = ParseIntegerConstant(64);
  }
  if (Tok.kind != Token::RSquare) {
    Error("expected ']'.");
    goto exit;
  }
  ConsumeRSquare();
  
  if (Tok.kind != Token::Colon) {
    Error("expected ':'.");
    goto exit;
  }
  ConsumeExpectedToken(Token::Colon);

  DomainType = ParseTypeSpecifier();
  if (Tok.kind != Token::Arrow) {
    Error("expected '->'.");
    goto exit;
  }
  ConsumeExpectedToken(Token::Arrow);

  RangeType = ParseTypeSpecifier();
  if (Tok.kind != Token::Equals) {
    Error("expected '='.");
    goto exit;
  }
  ConsumeExpectedToken(Token::Equals);

  if (Tok.kind == Token::KWSymbolic) {
    ConsumeExpectedToken(Token::KWSymbolic);    
  } else if (Tok.kind == Token::LSquare) {
    ConsumeLSquare();
    while (Tok.kind != Token::RSquare) {
      if (Tok.kind == Token::EndOfFile) {
        Error("unexpected end of file.");
        goto exit;
      }

      ExprResult Res = ParseNumber(RangeType.get());
      if (Res.isValid())
        Values.push_back(cast<ConstantExpr>(Res.get()));
    }
    ConsumeRSquare();
  } else {
    Error("expected 'symbolic' or '['.");
    goto exit;
  }

  // Type check size.
  if (!Size.isValid()) {
    if (Values.empty()) {
      Error("unsized arrays are not yet supported.");
      Size = 1;
    } else {
      Size = Values.size();
    }
  }

  if (!Values.empty()) {
    if (Size.get() != Values.size()) {
      // FIXME: Lame message.
      Error("constant arrays must be completely specified.");
      Values.clear();
    }

    // for (unsigned i = 0; i != Size.get(); ++i) {
    // TODO: Check: Must be constant expression.
    //}
  }

  // FIXME: Validate that size makes sense for domain type.

  if (DomainType.get() != Expr::Int32) {
    Error("array domain must currently be w32.");
    DomainType = Expr::Int32;
    Values.clear();
  }

  if (RangeType.get() != Expr::Int8) {
    Error("array domain must currently be w8.");
    RangeType = Expr::Int8;
    Values.clear();
  }

  // FIXME: Validate that this array is undeclared.

 exit:
  if (!Size.isValid())
    Size = 1;
  if (!DomainType.isValid())
    DomainType = 32;
  if (!RangeType.isValid())
    RangeType = 8;

  // FIXME: Array should take domain and range.
  const Identifier *Label = GetOrCreateIdentifier(Name);
  const Array *Root;
  if (!Values.empty())
    Root = TheArrayCache.CreateArray(Label->Name, Size.get(), &Values[0],
                                     &Values[0] + Values.size());
  else
    Root = TheArrayCache.CreateArray(Label->Name, Size.get());
  ArrayDecl *AD = new ArrayDecl(Label, Size.get(), 
                                DomainType.get(), RangeType.get(), Root);

  ArraySymTab[Label] = AD;

  // Create the initial version reference.
  VersionSymTab.insert(std::make_pair(Label,
                                      UpdateList(Root, NULL)));

  return AD;
}
Пример #10
0
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
                                             SourceLocation EllipsisLoc,
                                             ParamInfo *ArgInfo,
                                             unsigned NumArgs,
                                             unsigned TypeQuals,
                                             bool RefQualifierIsLvalueRef,
                                             SourceLocation RefQualifierLoc,
                                             SourceLocation ConstQualifierLoc,
                                             SourceLocation
                                                 VolatileQualifierLoc,
                                             SourceLocation MutableLoc,
                                             ExceptionSpecificationType
                                                 ESpecType,
                                             SourceLocation ESpecLoc,
                                             ParsedType *Exceptions,
                                             SourceRange *ExceptionRanges,
                                             unsigned NumExceptions,
                                             Expr *NoexceptExpr,
                                             SourceLocation LocalRangeBegin,
                                             SourceLocation LocalRangeEnd,
                                             Declarator &TheDeclarator,
                                             TypeResult TrailingReturnType) {
  DeclaratorChunk I;
  I.Kind                        = Function;
  I.Loc                         = LocalRangeBegin;
  I.EndLoc                      = LocalRangeEnd;
  I.Fun.AttrList                = 0;
  I.Fun.hasPrototype            = hasProto;
  I.Fun.isVariadic              = isVariadic;
  I.Fun.EllipsisLoc             = EllipsisLoc.getRawEncoding();
  I.Fun.DeleteArgInfo           = false;
  I.Fun.TypeQuals               = TypeQuals;
  I.Fun.NumArgs                 = NumArgs;
  I.Fun.ArgInfo                 = 0;
  I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef;
  I.Fun.RefQualifierLoc         = RefQualifierLoc.getRawEncoding();
  I.Fun.ConstQualifierLoc       = ConstQualifierLoc.getRawEncoding();
  I.Fun.VolatileQualifierLoc    = VolatileQualifierLoc.getRawEncoding();
  I.Fun.MutableLoc              = MutableLoc.getRawEncoding();
  I.Fun.ExceptionSpecType       = ESpecType;
  I.Fun.ExceptionSpecLoc        = ESpecLoc.getRawEncoding();
  I.Fun.NumExceptions           = 0;
  I.Fun.Exceptions              = 0;
  I.Fun.NoexceptExpr            = 0;
  I.Fun.HasTrailingReturnType   = TrailingReturnType.isUsable() ||
                                  TrailingReturnType.isInvalid();
  I.Fun.TrailingReturnType      = TrailingReturnType.get();

  // new[] an argument array if needed.
  if (NumArgs) {
    // If the 'InlineParams' in Declarator is unused and big enough, put our
    // parameter list there (in an effort to avoid new/delete traffic).  If it
    // is already used (consider a function returning a function pointer) or too
    // small (function taking too many arguments), go to the heap.
    if (!TheDeclarator.InlineParamsUsed &&
        NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
      I.Fun.ArgInfo = TheDeclarator.InlineParams;
      I.Fun.DeleteArgInfo = false;
      TheDeclarator.InlineParamsUsed = true;
    } else {
      I.Fun.ArgInfo = new DeclaratorChunk::ParamInfo[NumArgs];
      I.Fun.DeleteArgInfo = true;
    }
    memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs);
  }

  // Check what exception specification information we should actually store.
  switch (ESpecType) {
  default: break; // By default, save nothing.
  case EST_Dynamic:
    // new[] an exception array if needed
    if (NumExceptions) {
      I.Fun.NumExceptions = NumExceptions;
      I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions];
      for (unsigned i = 0; i != NumExceptions; ++i) {
        I.Fun.Exceptions[i].Ty = Exceptions[i];
        I.Fun.Exceptions[i].Range = ExceptionRanges[i];
      }
    }
    break;

  case EST_ComputedNoexcept:
    I.Fun.NoexceptExpr = NoexceptExpr;
    break;
  }
  return I;
}
Пример #11
0
/// TryAnnotateTypeOrScopeToken - If the current token position is on a
/// typename (possibly qualified in C++) or a C++ scope specifier not followed
/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
/// with a single annotation token representing the typename or C++ scope
/// respectively.
/// This simplifies handling of C++ scope specifiers and allows efficient
/// backtracking without the need to re-parse and resolve nested-names and
/// typenames.
/// It will mainly be called when we expect to treat identifiers as typenames
/// (if they are typenames). For example, in C we do not expect identifiers
/// inside expressions to be treated as typenames so it will not be called
/// for expressions in C.
/// The benefit for C/ObjC is that a typename will be annotated and
/// Actions.getTypeName will not be needed to be called again (e.g. getTypeName
/// will not be called twice, once to check whether we have a declaration
/// specifier, and another one to get the actual type inside
/// ParseDeclarationSpecifiers).
///
/// This returns true if the token was annotated or an unrecoverable error
/// occurs.
/// 
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
bool Parser::TryAnnotateTypeOrScopeToken() {
  assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) 
          || Tok.is(tok::kw_typename)) &&
         "Cannot be a type or scope token!");
  
  if (Tok.is(tok::kw_typename)) {
    // Parse a C++ typename-specifier, e.g., "typename T::type".
    //
    //   typename-specifier:
    //     'typename' '::' [opt] nested-name-specifier identifier
    //     'typename' '::' [opt] nested-name-specifier template [opt] 
    //            simple-template-id
    SourceLocation TypenameLoc = ConsumeToken();
    CXXScopeSpec SS;
    bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS);
    if (!HadNestedNameSpecifier) {
      Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
      return false;
    }

    TypeResult Ty;
    if (Tok.is(tok::identifier)) {
      // FIXME: check whether the next token is '<', first!
      Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(), 
                                     Tok.getLocation());
    } else if (Tok.is(tok::annot_template_id)) {
      TemplateIdAnnotation *TemplateId 
        = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
      if (TemplateId->Kind == TNK_Function_template) {
        Diag(Tok, diag::err_typename_refers_to_non_type_template)
          << Tok.getAnnotationRange();
        return false;
      }

      AnnotateTemplateIdTokenAsType(0);
      assert(Tok.is(tok::annot_typename) && 
             "AnnotateTemplateIdTokenAsType isn't working properly");
      if (Tok.getAnnotationValue())
        Ty = Actions.ActOnTypenameType(TypenameLoc, SS, SourceLocation(),
                                       Tok.getAnnotationValue());
      else
        Ty = true;
    } else {
      Diag(Tok, diag::err_expected_type_name_after_typename)
        << SS.getRange();
      return false;
    }

    Tok.setKind(tok::annot_typename);
    Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get());
    Tok.setAnnotationEndLoc(Tok.getLocation());
    Tok.setLocation(TypenameLoc);
    PP.AnnotateCachedTokens(Tok);
    return true;
  }

  CXXScopeSpec SS;
  if (getLang().CPlusPlus)
    ParseOptionalCXXScopeSpecifier(SS);

  if (Tok.is(tok::identifier)) {
    // Determine whether the identifier is a type name.
    if (TypeTy *Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), 
                                         Tok.getLocation(), CurScope, &SS)) {
      // This is a typename. Replace the current token in-place with an
      // annotation type token.
      Tok.setKind(tok::annot_typename);
      Tok.setAnnotationValue(Ty);
      Tok.setAnnotationEndLoc(Tok.getLocation());
      if (SS.isNotEmpty()) // it was a C++ qualified type name.
        Tok.setLocation(SS.getBeginLoc());
      
      // In case the tokens were cached, have Preprocessor replace
      // them with the annotation token.
      PP.AnnotateCachedTokens(Tok);
      return true;
    } 

    if (!getLang().CPlusPlus) {
      // If we're in C, we can't have :: tokens at all (the lexer won't return
      // them).  If the identifier is not a type, then it can't be scope either,
      // just early exit. 
      return false;
    }
    
    // If this is a template-id, annotate with a template-id or type token.
    if (NextToken().is(tok::less)) {
      TemplateTy Template;
      if (TemplateNameKind TNK 
            = Actions.isTemplateName(*Tok.getIdentifierInfo(),
                                     CurScope, Template, &SS))
        if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
          // If an unrecoverable error occurred, we need to return true here,
          // because the token stream is in a damaged state.  We may not return
          // a valid identifier.
          return Tok.isNot(tok::identifier);
        }
    }

    // The current token, which is either an identifier or a
    // template-id, is not part of the annotation. Fall through to
    // push that token back into the stream and complete the C++ scope
    // specifier annotation.
  } 

  if (Tok.is(tok::annot_template_id)) {
    TemplateIdAnnotation *TemplateId 
      = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
    if (TemplateId->Kind == TNK_Type_template) {
      // A template-id that refers to a type was parsed into a
      // template-id annotation in a context where we weren't allowed
      // to produce a type annotation token. Update the template-id
      // annotation token to a type annotation token now.
      AnnotateTemplateIdTokenAsType(&SS);
      return true;
    }
  }

  if (SS.isEmpty())
    return Tok.isNot(tok::identifier) && Tok.isNot(tok::coloncolon);
  
  // A C++ scope specifier that isn't followed by a typename.
  // Push the current token back into the token stream (or revert it if it is
  // cached) and use an annotation scope token for current token.
  if (PP.isBacktrackEnabled())
    PP.RevertCachedTokens(1);
  else
    PP.EnterToken(Tok);
  Tok.setKind(tok::annot_cxxscope);
  Tok.setAnnotationValue(SS.getScopeRep());
  Tok.setAnnotationRange(SS.getRange());

  // In case the tokens were cached, have Preprocessor replace them with the
  // annotation token.
  PP.AnnotateCachedTokens(Tok);
  return true;
}