/// \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(); }
/// 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(); }
/// ParseMatchedBinaryArgs - Parse a pair of arguments who are /// expected to be of the same type. Upon return, if both LHS and RHS /// are valid then they are guaranteed to have the same type. /// /// Name - The name token of the expression, for diagnostics. /// ExpectType - The expected type of the arguments, if known. void ParserImpl::ParseMatchedBinaryArgs(const Token &Name, TypeResult ExpectType, ExprResult &LHS, ExprResult &RHS) { if (Tok.kind == Token::RParen) { Error("unexpected end of arguments.", Name); ConsumeRParen(); return; } // Avoid NumberOrExprResult overhead and give more precise // diagnostics when we know the type. if (ExpectType.isValid()) { LHS = ParseExpr(ExpectType); if (Tok.kind == Token::RParen) { Error("unexpected end of arguments.", Name); ConsumeRParen(); return; } RHS = ParseExpr(ExpectType); } else { NumberOrExprResult LHS_NOE = ParseNumberOrExpr(); if (Tok.kind == Token::RParen) { Error("unexpected end of arguments.", Name); ConsumeRParen(); return; } if (LHS_NOE.isNumber()) { NumberOrExprResult RHS_NOE = ParseNumberOrExpr(); if (RHS_NOE.isNumber()) { Error("ambiguous arguments to expression.", Name); } else { RHS = RHS_NOE.getExpr(); if (RHS.isValid()) LHS = ParseNumberToken(RHS.get()->getWidth(), LHS_NOE.getNumber()); } } else { LHS = LHS_NOE.getExpr(); if (!LHS.isValid()) { // FIXME: Should suppress ambiguity warnings here. RHS = ParseExpr(TypeResult()); } else { RHS = ParseExpr(LHS.get()->getWidth()); } } } ExpectRParen("unexpected argument to expression."); }
/// 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; }
/// 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(); }
/// \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; }
/// 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(); } }
/// 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; }
/// 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; }
/// 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; }
/// 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; }