Path: blob/main/contrib/llvm-project/clang/lib/Parse/ParseInit.cpp
35234 views
//===--- ParseInit.cpp - Initializer Parsing ------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements initializer parsing as specified by C99 6.7.8.9//10//===----------------------------------------------------------------------===//1112#include "clang/Basic/TokenKinds.h"13#include "clang/Parse/ParseDiagnostic.h"14#include "clang/Parse/Parser.h"15#include "clang/Parse/RAIIObjectsForParser.h"16#include "clang/Sema/Designator.h"17#include "clang/Sema/EnterExpressionEvaluationContext.h"18#include "clang/Sema/Ownership.h"19#include "clang/Sema/Scope.h"20#include "clang/Sema/SemaCodeCompletion.h"21#include "clang/Sema/SemaObjC.h"22#include "llvm/ADT/STLExtras.h"23#include "llvm/ADT/SmallString.h"24using namespace clang;252627/// MayBeDesignationStart - Return true if the current token might be the start28/// of a designator. If we can tell it is impossible that it is a designator,29/// return false.30bool Parser::MayBeDesignationStart() {31switch (Tok.getKind()) {32default:33return false;3435case tok::period: // designator: '.' identifier36return true;3738case tok::l_square: { // designator: array-designator39if (!PP.getLangOpts().CPlusPlus)40return true;4142// C++11 lambda expressions and C99 designators can be ambiguous all the43// way through the closing ']' and to the next character. Handle the easy44// cases here, and fall back to tentative parsing if those fail.45switch (PP.LookAhead(0).getKind()) {46case tok::equal:47case tok::ellipsis:48case tok::r_square:49// Definitely starts a lambda expression.50return false;5152case tok::amp:53case tok::kw_this:54case tok::star:55case tok::identifier:56// We have to do additional analysis, because these could be the57// start of a constant expression or a lambda capture list.58break;5960default:61// Anything not mentioned above cannot occur following a '[' in a62// lambda expression.63return true;64}6566// Handle the complicated case below.67break;68}69case tok::identifier: // designation: identifier ':'70return PP.LookAhead(0).is(tok::colon);71}7273// Parse up to (at most) the token after the closing ']' to determine74// whether this is a C99 designator or a lambda.75RevertingTentativeParsingAction Tentative(*this);7677LambdaIntroducer Intro;78LambdaIntroducerTentativeParse ParseResult;79if (ParseLambdaIntroducer(Intro, &ParseResult)) {80// Hit and diagnosed an error in a lambda.81// FIXME: Tell the caller this happened so they can recover.82return true;83}8485switch (ParseResult) {86case LambdaIntroducerTentativeParse::Success:87case LambdaIntroducerTentativeParse::Incomplete:88// Might be a lambda-expression. Keep looking.89// FIXME: If our tentative parse was not incomplete, parse the lambda from90// here rather than throwing away then reparsing the LambdaIntroducer.91break;9293case LambdaIntroducerTentativeParse::MessageSend:94case LambdaIntroducerTentativeParse::Invalid:95// Can't be a lambda-expression. Treat it as a designator.96// FIXME: Should we disambiguate against a message-send?97return true;98}99100// Once we hit the closing square bracket, we look at the next101// token. If it's an '=', this is a designator. Otherwise, it's a102// lambda expression. This decision favors lambdas over the older103// GNU designator syntax, which allows one to omit the '=', but is104// consistent with GCC.105return Tok.is(tok::equal);106}107108static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,109Designation &Desig) {110// If we have exactly one array designator, this used the GNU111// 'designation: array-designator' extension, otherwise there should be no112// designators at all!113if (Desig.getNumDesignators() == 1 &&114(Desig.getDesignator(0).isArrayDesignator() ||115Desig.getDesignator(0).isArrayRangeDesignator()))116P.Diag(Loc, diag::ext_gnu_missing_equal_designator);117else if (Desig.getNumDesignators() > 0)118P.Diag(Loc, diag::err_expected_equal_designator);119}120121/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production122/// checking to see if the token stream starts with a designator.123///124/// C99:125///126/// designation:127/// designator-list '='128/// [GNU] array-designator129/// [GNU] identifier ':'130///131/// designator-list:132/// designator133/// designator-list designator134///135/// designator:136/// array-designator137/// '.' identifier138///139/// array-designator:140/// '[' constant-expression ']'141/// [GNU] '[' constant-expression '...' constant-expression ']'142///143/// C++20:144///145/// designated-initializer-list:146/// designated-initializer-clause147/// designated-initializer-list ',' designated-initializer-clause148///149/// designated-initializer-clause:150/// designator brace-or-equal-initializer151///152/// designator:153/// '.' identifier154///155/// We allow the C99 syntax extensions in C++20, but do not allow the C++20156/// extension (a braced-init-list after the designator with no '=') in C99.157///158/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an159/// initializer (because it is an expression). We need to consider this case160/// when parsing array designators.161///162/// \p CodeCompleteCB is called with Designation parsed so far.163ExprResult Parser::ParseInitializerWithPotentialDesignator(164DesignatorCompletionInfo DesignatorCompletion) {165// If this is the old-style GNU extension:166// designation ::= identifier ':'167// Handle it as a field designator. Otherwise, this must be the start of a168// normal expression.169if (Tok.is(tok::identifier)) {170const IdentifierInfo *FieldName = Tok.getIdentifierInfo();171172SmallString<256> NewSyntax;173llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName()174<< " = ";175176SourceLocation NameLoc = ConsumeToken(); // Eat the identifier.177178assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!");179SourceLocation ColonLoc = ConsumeToken();180181Diag(NameLoc, diag::ext_gnu_old_style_field_designator)182<< FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc),183NewSyntax);184185Designation D;186D.AddDesignator(Designator::CreateFieldDesignator(187FieldName, SourceLocation(), NameLoc));188PreferredType.enterDesignatedInitializer(189Tok.getLocation(), DesignatorCompletion.PreferredBaseType, D);190return Actions.ActOnDesignatedInitializer(D, ColonLoc, true,191ParseInitializer());192}193194// Desig - This is initialized when we see our first designator. We may have195// an objc message send with no designator, so we don't want to create this196// eagerly.197Designation Desig;198199// Parse each designator in the designator list until we find an initializer.200while (Tok.is(tok::period) || Tok.is(tok::l_square)) {201if (Tok.is(tok::period)) {202// designator: '.' identifier203SourceLocation DotLoc = ConsumeToken();204205if (Tok.is(tok::code_completion)) {206cutOffParsing();207Actions.CodeCompletion().CodeCompleteDesignator(208DesignatorCompletion.PreferredBaseType,209DesignatorCompletion.InitExprs, Desig);210return ExprError();211}212if (Tok.isNot(tok::identifier)) {213Diag(Tok.getLocation(), diag::err_expected_field_designator);214return ExprError();215}216217Desig.AddDesignator(Designator::CreateFieldDesignator(218Tok.getIdentifierInfo(), DotLoc, Tok.getLocation()));219ConsumeToken(); // Eat the identifier.220continue;221}222223// We must have either an array designator now or an objc message send.224assert(Tok.is(tok::l_square) && "Unexpected token!");225226// Handle the two forms of array designator:227// array-designator: '[' constant-expression ']'228// array-designator: '[' constant-expression '...' constant-expression ']'229//230// Also, we have to handle the case where the expression after the231// designator an an objc message send: '[' objc-message-expr ']'.232// Interesting cases are:233// [foo bar] -> objc message send234// [foo] -> array designator235// [foo ... bar] -> array designator236// [4][foo bar] -> obsolete GNU designation with objc message send.237//238// We do not need to check for an expression starting with [[ here. If it239// contains an Objective-C message send, then it is not an ill-formed240// attribute. If it is a lambda-expression within an array-designator, then241// it will be rejected because a constant-expression cannot begin with a242// lambda-expression.243InMessageExpressionRAIIObject InMessage(*this, true);244245BalancedDelimiterTracker T(*this, tok::l_square);246T.consumeOpen();247SourceLocation StartLoc = T.getOpenLocation();248249ExprResult Idx;250251// If Objective-C is enabled and this is a typename (class message252// send) or send to 'super', parse this as a message send253// expression. We handle C++ and C separately, since C++ requires254// much more complicated parsing.255if (getLangOpts().ObjC && getLangOpts().CPlusPlus) {256// Send to 'super'.257if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&258NextToken().isNot(tok::period) &&259getCurScope()->isInObjcMethodScope()) {260CheckArrayDesignatorSyntax(*this, StartLoc, Desig);261return ParseAssignmentExprWithObjCMessageExprStart(262StartLoc, ConsumeToken(), nullptr, nullptr);263}264265// Parse the receiver, which is either a type or an expression.266bool IsExpr;267void *TypeOrExpr;268if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {269SkipUntil(tok::r_square, StopAtSemi);270return ExprError();271}272273// If the receiver was a type, we have a class message; parse274// the rest of it.275if (!IsExpr) {276CheckArrayDesignatorSyntax(*this, StartLoc, Desig);277return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,278SourceLocation(),279ParsedType::getFromOpaquePtr(TypeOrExpr),280nullptr);281}282283// If the receiver was an expression, we still don't know284// whether we have a message send or an array designator; just285// adopt the expression for further analysis below.286// FIXME: potentially-potentially evaluated expression above?287Idx = ExprResult(static_cast<Expr*>(TypeOrExpr));288} else if (getLangOpts().ObjC && Tok.is(tok::identifier)) {289IdentifierInfo *II = Tok.getIdentifierInfo();290SourceLocation IILoc = Tok.getLocation();291ParsedType ReceiverType;292// Three cases. This is a message send to a type: [type foo]293// This is a message send to super: [super foo]294// This is a message sent to an expr: [super.bar foo]295switch (Actions.ObjC().getObjCMessageKind(296getCurScope(), II, IILoc, II == Ident_super,297NextToken().is(tok::period), ReceiverType)) {298case SemaObjC::ObjCSuperMessage:299CheckArrayDesignatorSyntax(*this, StartLoc, Desig);300return ParseAssignmentExprWithObjCMessageExprStart(301StartLoc, ConsumeToken(), nullptr, nullptr);302303case SemaObjC::ObjCClassMessage:304CheckArrayDesignatorSyntax(*this, StartLoc, Desig);305ConsumeToken(); // the identifier306if (!ReceiverType) {307SkipUntil(tok::r_square, StopAtSemi);308return ExprError();309}310311// Parse type arguments and protocol qualifiers.312if (Tok.is(tok::less)) {313SourceLocation NewEndLoc;314TypeResult NewReceiverType315= parseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType,316/*consumeLastToken=*/true,317NewEndLoc);318if (!NewReceiverType.isUsable()) {319SkipUntil(tok::r_square, StopAtSemi);320return ExprError();321}322323ReceiverType = NewReceiverType.get();324}325326return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,327SourceLocation(),328ReceiverType,329nullptr);330331case SemaObjC::ObjCInstanceMessage:332// Fall through; we'll just parse the expression and333// (possibly) treat this like an Objective-C message send334// later.335break;336}337}338339// Parse the index expression, if we haven't already gotten one340// above (which can only happen in Objective-C++).341// Note that we parse this as an assignment expression, not a constant342// expression (allowing *=, =, etc) to handle the objc case. Sema needs343// to validate that the expression is a constant.344// FIXME: We also need to tell Sema that we're in a345// potentially-potentially evaluated context.346if (!Idx.get()) {347Idx = ParseAssignmentExpression();348if (Idx.isInvalid()) {349SkipUntil(tok::r_square, StopAtSemi);350return Idx;351}352}353354// Given an expression, we could either have a designator (if the next355// tokens are '...' or ']' or an objc message send. If this is an objc356// message send, handle it now. An objc-message send is the start of357// an assignment-expression production.358if (getLangOpts().ObjC && Tok.isNot(tok::ellipsis) &&359Tok.isNot(tok::r_square)) {360CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);361return ParseAssignmentExprWithObjCMessageExprStart(362StartLoc, SourceLocation(), nullptr, Idx.get());363}364365// If this is a normal array designator, remember it.366if (Tok.isNot(tok::ellipsis)) {367Desig.AddDesignator(Designator::CreateArrayDesignator(Idx.get(),368StartLoc));369} else {370// Handle the gnu array range extension.371Diag(Tok, diag::ext_gnu_array_range);372SourceLocation EllipsisLoc = ConsumeToken();373374ExprResult RHS(ParseConstantExpression());375if (RHS.isInvalid()) {376SkipUntil(tok::r_square, StopAtSemi);377return RHS;378}379Desig.AddDesignator(Designator::CreateArrayRangeDesignator(380Idx.get(), RHS.get(), StartLoc, EllipsisLoc));381}382383T.consumeClose();384Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc(385T.getCloseLocation());386}387388// Okay, we're done with the designator sequence. We know that there must be389// at least one designator, because the only case we can get into this method390// without a designator is when we have an objc message send. That case is391// handled and returned from above.392assert(!Desig.empty() && "Designator is empty?");393394// Handle a normal designator sequence end, which is an equal.395if (Tok.is(tok::equal)) {396SourceLocation EqualLoc = ConsumeToken();397PreferredType.enterDesignatedInitializer(398Tok.getLocation(), DesignatorCompletion.PreferredBaseType, Desig);399return Actions.ActOnDesignatedInitializer(Desig, EqualLoc, false,400ParseInitializer());401}402403// Handle a C++20 braced designated initialization, which results in404// direct-list-initialization of the aggregate element. We allow this as an405// extension from C++11 onwards (when direct-list-initialization was added).406if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) {407PreferredType.enterDesignatedInitializer(408Tok.getLocation(), DesignatorCompletion.PreferredBaseType, Desig);409return Actions.ActOnDesignatedInitializer(Desig, SourceLocation(), false,410ParseBraceInitializer());411}412413// We read some number of designators and found something that isn't an = or414// an initializer. If we have exactly one array designator, this415// is the GNU 'designation: array-designator' extension. Otherwise, it is a416// parse error.417if (Desig.getNumDesignators() == 1 &&418(Desig.getDesignator(0).isArrayDesignator() ||419Desig.getDesignator(0).isArrayRangeDesignator())) {420Diag(Tok, diag::ext_gnu_missing_equal_designator)421<< FixItHint::CreateInsertion(Tok.getLocation(), "= ");422return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(),423true, ParseInitializer());424}425426Diag(Tok, diag::err_expected_equal_designator);427return ExprError();428}429430ExprResult Parser::createEmbedExpr() {431assert(Tok.getKind() == tok::annot_embed);432EmbedAnnotationData *Data =433reinterpret_cast<EmbedAnnotationData *>(Tok.getAnnotationValue());434ExprResult Res;435ASTContext &Context = Actions.getASTContext();436SourceLocation StartLoc = ConsumeAnnotationToken();437if (Data->BinaryData.size() == 1) {438Res = IntegerLiteral::Create(Context,439llvm::APInt(CHAR_BIT, Data->BinaryData.back()),440Context.UnsignedCharTy, StartLoc);441} else {442auto CreateStringLiteralFromStringRef = [&](StringRef Str, QualType Ty) {443llvm::APSInt ArraySize =444Context.MakeIntValue(Str.size(), Context.getSizeType());445QualType ArrayTy = Context.getConstantArrayType(446Ty, ArraySize, nullptr, ArraySizeModifier::Normal, 0);447return StringLiteral::Create(Context, Str, StringLiteralKind::Ordinary,448false, ArrayTy, StartLoc);449};450451StringLiteral *BinaryDataArg = CreateStringLiteralFromStringRef(452Data->BinaryData, Context.UnsignedCharTy);453Res = Actions.ActOnEmbedExpr(StartLoc, BinaryDataArg);454}455return Res;456}457458/// ParseBraceInitializer - Called when parsing an initializer that has a459/// leading open brace.460///461/// initializer: [C99 6.7.8]462/// '{' initializer-list '}'463/// '{' initializer-list ',' '}'464/// [C23] '{' '}'465///466/// initializer-list:467/// designation[opt] initializer ...[opt]468/// initializer-list ',' designation[opt] initializer ...[opt]469///470ExprResult Parser::ParseBraceInitializer() {471InMessageExpressionRAIIObject InMessage(*this, false);472473BalancedDelimiterTracker T(*this, tok::l_brace);474T.consumeOpen();475SourceLocation LBraceLoc = T.getOpenLocation();476477/// InitExprs - This is the actual list of expressions contained in the478/// initializer.479ExprVector InitExprs;480481if (Tok.is(tok::r_brace)) {482// Empty initializers are a C++ feature and a GNU extension to C before C23.483if (!getLangOpts().CPlusPlus) {484Diag(LBraceLoc, getLangOpts().C23485? diag::warn_c23_compat_empty_initializer486: diag::ext_c_empty_initializer);487}488// Match the '}'.489return Actions.ActOnInitList(LBraceLoc, std::nullopt, ConsumeBrace());490}491492// Enter an appropriate expression evaluation context for an initializer list.493EnterExpressionEvaluationContext EnterContext(494Actions, EnterExpressionEvaluationContext::InitList);495496bool InitExprsOk = true;497QualType LikelyType = PreferredType.get(T.getOpenLocation());498DesignatorCompletionInfo DesignatorCompletion{InitExprs, LikelyType};499bool CalledSignatureHelp = false;500auto RunSignatureHelp = [&] {501QualType PreferredType;502if (!LikelyType.isNull())503PreferredType = Actions.CodeCompletion().ProduceConstructorSignatureHelp(504LikelyType->getCanonicalTypeInternal(), T.getOpenLocation(),505InitExprs, T.getOpenLocation(), /*Braced=*/true);506CalledSignatureHelp = true;507return PreferredType;508};509510while (true) {511PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp);512513// Handle Microsoft __if_exists/if_not_exists if necessary.514if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||515Tok.is(tok::kw___if_not_exists))) {516if (ParseMicrosoftIfExistsBraceInitializer(InitExprs, InitExprsOk)) {517if (Tok.isNot(tok::comma)) break;518ConsumeToken();519}520if (Tok.is(tok::r_brace)) break;521continue;522}523524// Parse: designation[opt] initializer525526// If we know that this cannot be a designation, just parse the nested527// initializer directly.528ExprResult SubElt;529if (MayBeDesignationStart())530SubElt = ParseInitializerWithPotentialDesignator(DesignatorCompletion);531else if (Tok.getKind() == tok::annot_embed)532SubElt = createEmbedExpr();533else534SubElt = ParseInitializer();535536if (Tok.is(tok::ellipsis))537SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());538539SubElt = Actions.CorrectDelayedTyposInExpr(SubElt.get());540541// If we couldn't parse the subelement, bail out.542if (SubElt.isUsable()) {543InitExprs.push_back(SubElt.get());544} else {545InitExprsOk = false;546547// We have two ways to try to recover from this error: if the code looks548// grammatically ok (i.e. we have a comma coming up) try to continue549// parsing the rest of the initializer. This allows us to emit550// diagnostics for later elements that we find. If we don't see a comma,551// assume there is a parse error, and just skip to recover.552// FIXME: This comment doesn't sound right. If there is a r_brace553// immediately, it can't be an error, since there is no other way of554// leaving this loop except through this if.555if (Tok.isNot(tok::comma)) {556SkipUntil(tok::r_brace, StopBeforeMatch);557break;558}559}560561// If we don't have a comma continued list, we're done.562if (Tok.isNot(tok::comma)) break;563564// TODO: save comma locations if some client cares.565ConsumeToken();566567// Handle trailing comma.568if (Tok.is(tok::r_brace)) break;569}570571bool closed = !T.consumeClose();572573if (InitExprsOk && closed)574return Actions.ActOnInitList(LBraceLoc, InitExprs,575T.getCloseLocation());576577return ExprError(); // an error occurred.578}579580581// Return true if a comma (or closing brace) is necessary after the582// __if_exists/if_not_exists statement.583bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,584bool &InitExprsOk) {585bool trailingComma = false;586IfExistsCondition Result;587if (ParseMicrosoftIfExistsCondition(Result))588return false;589590BalancedDelimiterTracker Braces(*this, tok::l_brace);591if (Braces.consumeOpen()) {592Diag(Tok, diag::err_expected) << tok::l_brace;593return false;594}595596switch (Result.Behavior) {597case IEB_Parse:598// Parse the declarations below.599break;600601case IEB_Dependent:602Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)603<< Result.IsIfExists;604// Fall through to skip.605[[fallthrough]];606607case IEB_Skip:608Braces.skipToEnd();609return false;610}611612DesignatorCompletionInfo DesignatorCompletion{613InitExprs,614PreferredType.get(Braces.getOpenLocation()),615};616while (!isEofOrEom()) {617trailingComma = false;618// If we know that this cannot be a designation, just parse the nested619// initializer directly.620ExprResult SubElt;621if (MayBeDesignationStart())622SubElt = ParseInitializerWithPotentialDesignator(DesignatorCompletion);623else624SubElt = ParseInitializer();625626if (Tok.is(tok::ellipsis))627SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());628629// If we couldn't parse the subelement, bail out.630if (!SubElt.isInvalid())631InitExprs.push_back(SubElt.get());632else633InitExprsOk = false;634635if (Tok.is(tok::comma)) {636ConsumeToken();637trailingComma = true;638}639640if (Tok.is(tok::r_brace))641break;642}643644Braces.consumeClose();645646return !trailingComma;647}648649650