From: Richard Smith Date: Sat, 23 Nov 2013 04:06:09 +0000 (+0000) Subject: Generate a marker token when entering or leaving a submodule when building a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8a88a0b71520b418800ce1a4eb8bd4541b02d057;p=clang Generate a marker token when entering or leaving a submodule when building a module. Use the marker to diagnose cases where we try to transition between submodules when not at the top level (most likely because a closing brace was missing at the end of a header file, but is also possible if submodule headers attempt to do something fundamentally non-modular, like our .def files). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@195543 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 6812cce2db..90d3370c64 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -667,8 +667,10 @@ ANNOTATION(pragma_opencl_extension) ANNOTATION(pragma_openmp) ANNOTATION(pragma_openmp_end) -// Annotation for module import translated from #include etc. +// Annotations for module import translated from #include etc. ANNOTATION(module_include) +ANNOTATION(module_begin) +ANNOTATION(module_end) #undef ANNOTATION #undef TESTING_KEYWORD diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 223fd470ec..15159ff4da 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -276,22 +276,26 @@ class Preprocessor : public RefCountedBase { CLK_LexAfterModuleImport } CurLexerKind; + /// \brief True if the current lexer is for a submodule. + bool CurIsSubmodule; + /// IncludeMacroStack - This keeps track of the stack of files currently /// \#included, and macros currently being expanded from, not counting /// CurLexer/CurTokenLexer. struct IncludeStackInfo { enum CurLexerKind CurLexerKind; + bool IsSubmodule; Lexer *TheLexer; PTHLexer *ThePTHLexer; PreprocessorLexer *ThePPLexer; TokenLexer *TheTokenLexer; const DirectoryLookup *TheDirLookup; - IncludeStackInfo(enum CurLexerKind K, Lexer *L, PTHLexer* P, - PreprocessorLexer* PPL, - TokenLexer* TL, const DirectoryLookup *D) - : CurLexerKind(K), TheLexer(L), ThePTHLexer(P), ThePPLexer(PPL), - TheTokenLexer(TL), TheDirLookup(D) {} + IncludeStackInfo(enum CurLexerKind K, bool SM, Lexer *L, PTHLexer *P, + PreprocessorLexer *PPL, TokenLexer *TL, + const DirectoryLookup *D) + : CurLexerKind(K), IsSubmodule(SM), TheLexer(L), ThePTHLexer(P), + ThePPLexer(PPL), TheTokenLexer(TL), TheDirLookup(D) {} }; std::vector IncludeMacroStack; @@ -662,7 +666,7 @@ public: /// start lexing tokens from it instead of the current buffer. Emit an error /// and don't enter the file on error. void EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir, - SourceLocation Loc); + SourceLocation Loc, bool IsSubmodule = false); /// EnterMacro - Add a Macro to the top of the include stack and start lexing /// tokens from it instead of the current buffer. Args specifies the @@ -1155,6 +1159,9 @@ private: IdentifierInfo *Ident__abnormal_termination, *Ident___abnormal_termination, *Ident_AbnormalTermination; + + const char *getCurLexerEndPos(); + public: void PoisonSEHIdentifiers(bool Poison = true); // Borland @@ -1265,6 +1272,7 @@ private: void PushIncludeMacroStack() { IncludeMacroStack.push_back(IncludeStackInfo(CurLexerKind, + CurIsSubmodule, CurLexer.take(), CurPTHLexer.take(), CurPPLexer, @@ -1280,6 +1288,7 @@ private: CurTokenLexer.reset(IncludeMacroStack.back().TheTokenLexer); CurDirLookup = IncludeMacroStack.back().TheDirLookup; CurLexerKind = IncludeMacroStack.back().CurLexerKind; + CurIsSubmodule = IncludeMacroStack.back().IsSubmodule; IncludeMacroStack.pop_back(); } @@ -1380,11 +1389,13 @@ private: /// EnterSourceFileWithLexer - Add a lexer to the top of the include stack and /// start lexing tokens from it instead of the current buffer. - void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir); + void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir, + bool IsSubmodule = false); /// EnterSourceFileWithPTH - Add a lexer to the top of the include stack and /// start getting tokens from it using the PTH cache. - void EnterSourceFileWithPTH(PTHLexer *PL, const DirectoryLookup *Dir); + void EnterSourceFileWithPTH(PTHLexer *PL, const DirectoryLookup *Dir, + bool IsSubmodule = false); /// \brief Set the file ID for the preprocessor predefines. void setPredefinesFileID(FileID FID) { diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 0bf30453ce..884ab56fea 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -73,7 +73,7 @@ class Parser : public CodeCompletionHandler { SourceLocation PrevTokLocation; unsigned short ParenCount, BracketCount, BraceCount; - + /// Actions - These are the callbacks we invoke as we parse various constructs /// in the file. Sema &Actions; @@ -408,6 +408,14 @@ private: Tok.setKind(tok::eof); } + /// \brief Determine if we're at the end of the file or at a transition + /// between modules. + bool isEofOrEom() { + tok::TokenKind Kind = Tok.getKind(); + return Kind == tok::eof || Kind == tok::annot_module_begin || + Kind == tok::annot_module_end || Kind == tok::annot_module_include; + } + /// \brief Handle the annotation token produced for #pragma unused(...) void HandlePragmaUnused(); diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 55a66d87f8..f3393bfe51 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -657,7 +657,9 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // -traditional-cpp the lexer keeps /all/ whitespace, including comments. SourceLocation StartLoc = Tok.getLocation(); Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength())); - } else if (Tok.is(tok::annot_module_include)) { + } else if (Tok.is(tok::annot_module_include) || + Tok.is(tok::annot_module_begin) || + Tok.is(tok::annot_module_end)) { // PrintPPOutputPPCallbacks::InclusionDirective handles producing // appropriate output here. Ignore this token entirely. PP.Lex(Tok); diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 86c508fe9b..1e3602e84f 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -1389,6 +1389,19 @@ bool Preprocessor::ConcatenateIncludeName( return true; } +/// \brief Push a token onto the token stream containing an annotation. +static void EnterAnnotationToken(Preprocessor &PP, + SourceLocation Begin, SourceLocation End, + tok::TokenKind Kind, void *AnnotationVal) { + Token *Tok = new Token[1]; + Tok[0].startToken(); + Tok[0].setKind(Kind); + Tok[0].setLocation(Begin); + Tok[0].setAnnotationEndLoc(End); + Tok[0].setAnnotationValue(AnnotationVal); + PP.EnterTokenStream(Tok, 1, true, true); +} + /// HandleIncludeDirective - The "\#include" tokens have just been read, read /// the file to be included from the lexer, then include it! This is a common /// routine with functionality shared between \#include, \#include_next and @@ -1590,7 +1603,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // include directive maps to. bool BuildingImportedModule = Path[0].first->getName() == getLangOpts().CurrentModule; - + if (!BuildingImportedModule && getLangOpts().ObjC2) { // If we're not building the imported module, warn that we're going // to automatically turn this inclusion directive into a module import. @@ -1639,13 +1652,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // make the module visible. // FIXME: Produce this as the current token directly, rather than // allocating a new token for it. - Token *Tok = new Token[1]; - Tok[0].startToken(); - Tok[0].setKind(tok::annot_module_include); - Tok[0].setLocation(HashLoc); - Tok[0].setAnnotationEndLoc(End); - Tok[0].setAnnotationValue(Imported); - EnterTokenStream(Tok, 1, true, true); + EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_include, + Imported); } return; } @@ -1692,8 +1700,23 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, FileID FID = SourceMgr.createFileID(File, IncludePos, FileCharacter); assert(!FID.isInvalid() && "Expected valid file ID"); - // Finally, if all is good, enter the new file! - EnterSourceFile(FID, CurDir, FilenameTok.getLocation()); + // Determine if we're switching to building a new submodule, and which one. + ModuleMap::KnownHeader BuildingModule; + if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty()) { + Module *RequestingModule = getModuleForLocation(FilenameLoc); + BuildingModule = + HeaderInfo.getModuleMap().findModuleForHeader(File, RequestingModule); + } + + // If all is good, enter the new file! + EnterSourceFile(FID, CurDir, FilenameTok.getLocation(), + static_cast(BuildingModule)); + + // If we're walking into another part of the same module, let the parser + // know that any future declarations are within that other submodule. + if (BuildingModule) + EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_begin, + BuildingModule.getModule()); } /// HandleIncludeNextDirective - Implements \#include_next. diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 1f970a4450..3b3c5a9192 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -69,7 +69,7 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const { /// EnterSourceFile - Add a source file to the top of the include stack and /// start lexing tokens from it instead of the current buffer. void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, - SourceLocation Loc) { + SourceLocation Loc, bool IsSubmodule) { assert(!CurTokenLexer && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; @@ -78,7 +78,7 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, if (PTH) { if (PTHLexer *PL = PTH->CreateLexer(FID)) { - EnterSourceFileWithPTH(PL, CurDir); + EnterSourceFileWithPTH(PL, CurDir, IsSubmodule); return; } } @@ -101,14 +101,16 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, CodeCompletionFileLoc.getLocWithOffset(CodeCompletionOffset); } - EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); + EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir, + IsSubmodule); return; } /// EnterSourceFileWithLexer - Add a source file to the top of the include stack /// and start lexing tokens from it instead of the current buffer. void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer, - const DirectoryLookup *CurDir) { + const DirectoryLookup *CurDir, + bool IsSubmodule) { // Add the current lexer to the include stack. if (CurPPLexer || CurTokenLexer) @@ -117,6 +119,7 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer, CurLexer.reset(TheLexer); CurPPLexer = TheLexer; CurDirLookup = CurDir; + CurIsSubmodule = IsSubmodule; if (CurLexerKind != CLK_LexAfterModuleImport) CurLexerKind = CLK_Lexer; @@ -133,7 +136,8 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer, /// EnterSourceFileWithPTH - Add a source file to the top of the include stack /// and start getting tokens from it using the PTH cache. void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL, - const DirectoryLookup *CurDir) { + const DirectoryLookup *CurDir, + bool IsSubmodule) { if (CurPPLexer || CurTokenLexer) PushIncludeMacroStack(); @@ -141,6 +145,7 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL, CurDirLookup = CurDir; CurPTHLexer.reset(PL); CurPPLexer = CurPTHLexer.get(); + CurIsSubmodule = IsSubmodule; if (CurLexerKind != CLK_LexAfterModuleImport) CurLexerKind = CLK_PTHLexer; @@ -244,6 +249,29 @@ void Preprocessor::PropagateLineStartLeadingSpaceInfo(Token &Result) { // but it might if they're empty? } +/// \brief Determine the location to use as the end of the buffer for a lexer. +/// +/// If the file ends with a newline, form the EOF token on the newline itself, +/// rather than "on the line following it", which doesn't exist. This makes +/// diagnostics relating to the end of file include the last file that the user +/// actually typed, which is goodness. +const char *Preprocessor::getCurLexerEndPos() { + const char *EndPos = CurLexer->BufferEnd; + if (EndPos != CurLexer->BufferStart && + (EndPos[-1] == '\n' || EndPos[-1] == '\r')) { + --EndPos; + + // Handle \n\r and \r\n: + if (EndPos != CurLexer->BufferStart && + (EndPos[-1] == '\n' || EndPos[-1] == '\r') && + EndPos[-1] != EndPos[0]) + --EndPos; + } + + return EndPos; +} + + /// HandleEndOfFile - This callback is invoked when the lexer hits the end of /// the current file. This either returns the EOF token or pops a level off /// the include stack and keeps going. @@ -342,7 +370,19 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { FileID ExitedFID; if (Callbacks && !isEndOfMacro && CurPPLexer) ExitedFID = CurPPLexer->getFileID(); - + + // If this file corresponded to a submodule, notify the parser that we've + // left that submodule. + bool LeavingSubmodule = CurIsSubmodule && CurLexer; + if (LeavingSubmodule) { + const char *EndPos = getCurLexerEndPos(); + Result.startToken(); + CurLexer->BufferPtr = EndPos; + CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_module_end); + Result.setAnnotationEndLoc(Result.getLocation()); + Result.setAnnotationValue(0); + } + // We're done with the #included file. RemoveTopOfLexerStack(); @@ -357,27 +397,13 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { PPCallbacks::ExitFile, FileType, ExitedFID); } - // Client should lex another token. - return false; + // Client should lex another token unless we generated an EOM. + return LeavingSubmodule; } - // If the file ends with a newline, form the EOF token on the newline itself, - // rather than "on the line following it", which doesn't exist. This makes - // diagnostics relating to the end of file include the last file that the user - // actually typed, which is goodness. + // If this is the end of the main file, form an EOF token. if (CurLexer) { - const char *EndPos = CurLexer->BufferEnd; - if (EndPos != CurLexer->BufferStart && - (EndPos[-1] == '\n' || EndPos[-1] == '\r')) { - --EndPos; - - // Handle \n\r and \r\n: - if (EndPos != CurLexer->BufferStart && - (EndPos[-1] == '\n' || EndPos[-1] == '\r') && - EndPos[-1] != EndPos[0]) - --EndPos; - } - + const char *EndPos = getCurLexerEndPos(); Result.startToken(); CurLexer->BufferPtr = EndPos; CurLexer->FormTokenWithChars(Result, EndPos, tok::eof); diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index b500efee4e..92aeb5c3e5 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -67,8 +67,8 @@ Preprocessor::Preprocessor(IntrusiveRefCntPtr PPOpts, CodeComplete(0), CodeCompletionFile(0), CodeCompletionOffset(0), LastTokenWasAt(false), ModuleImportExpectsIdentifier(false), CodeCompletionReached(0), SkipMainFilePreamble(0, true), CurPPLexer(0), - CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), - MacroArgCache(0), Record(0), MIChainHead(0), MICache(0), + CurDirLookup(0), CurLexerKind(CLK_Lexer), CurIsSubmodule(false), + Callbacks(0), MacroArgCache(0), Record(0), MIChainHead(0), MICache(0), DeserialMIChainHead(0) { OwnsHeaderSearch = OwnsHeaders; diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 7792305165..9a69bec167 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -580,6 +580,9 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, switch (Tok.getKind()) { case tok::eof: + case tok::annot_module_begin: + case tok::annot_module_end: + case tok::annot_module_include: // Ran out of tokens. return false; @@ -965,6 +968,9 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, goto consume_token; case tok::eof: + case tok::annot_module_begin: + case tok::annot_module_end: + case tok::annot_module_include: // Ran out of tokens. return false; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b93979127a..7185de6fed 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1561,6 +1561,9 @@ void Parser::SkipMalformedDecl() { break; case tok::eof: + case tok::annot_module_begin: + case tok::annot_module_end: + case tok::annot_module_include: return; default: @@ -3371,7 +3374,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SmallVector FieldDecls; // While we still have something to read, read the declarations in the struct. - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // Each iteration of this loop reads one struct-declaration. // Check for extraneous top-level semicolon. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 382ed043ab..d2d9b220fd 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -195,7 +195,7 @@ void Parser::ParseInnerNamespace(std::vector& IdentLoc, ParsedAttributes& attrs, BalancedDelimiterTracker &Tracker) { if (index == Ident.size()) { - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); MaybeParseMicrosoftAttributes(attrs); @@ -318,7 +318,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); MaybeParseMicrosoftAttributes(attrs); @@ -2452,7 +2452,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, // a top-level comma always ends the initializer expression. const Token &Next = NextToken(); if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) || - Next.is(tok::eof)) { + Next.is(tok::eof)) { if (IsFunction) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) << 1 /* delete */; @@ -2597,7 +2597,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) { // While we still have something to read, read the member-declarations. - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // Each iteration of this loop reads one member-declaration. if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) || @@ -3420,7 +3420,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, return; } - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // __if_exists, __if_not_exists can nest. if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 37f74bbcd5..56d8edcdb4 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -512,7 +512,7 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, return false; } - while (Tok.isNot(tok::eof)) { + while (!isEofOrEom()) { trailingComma = false; // If we know that this cannot be a designation, just parse the nested // initializer directly. diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 86f38cfee3..238474b93a 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -423,7 +423,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, } // If we got to the end of the file, exit the loop. - if (Tok.is(tok::eof)) + if (isEofOrEom()) break; // Code completion within an Objective-C interface. @@ -1289,7 +1289,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); // While we still have something to read, read the instance variables. - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // Each iteration of this loop reads one objc-instance-variable-decl. // Check for extraneous top-level semicolon. @@ -1582,7 +1582,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { { ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl); - while (!ObjCImplParsing.isFinished() && Tok.isNot(tok::eof)) { + while (!ObjCImplParsing.isFinished() && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); MaybeParseMicrosoftAttributes(attrs); @@ -1612,7 +1612,7 @@ Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() { if (!Finished) { finish(P.Tok.getLocation()); - if (P.Tok.is(tok::eof)) { + if (P.isEofOrEom()) { P.Diag(P.Tok, diag::err_objc_missing_end) << FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n"); P.Diag(Dcl->getLocStart(), diag::note_objc_container_start) diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index d1f2138db4..5f939fc354 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -890,7 +890,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { Stmts.push_back(R.release()); } - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { if (Tok.is(tok::annot_pragma_unused)) { HandlePragmaUnused(); continue; @@ -2058,7 +2058,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { SourceLocation TokLoc = Tok.getLocation(); do { // If we hit EOF, we're done, period. - if (Tok.is(tok::eof)) + if (isEofOrEom()) break; if (!InAsmComment && Tok.is(tok::semi)) { diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 0f18abac75..cacff4a3ee 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -288,7 +288,7 @@ bool Parser::SkipUntil(ArrayRef Toks, SkipUntilFlags Flags) { if (Toks.size() == 1 && Toks[0] == tok::eof && !HasFlagsSet(Flags, StopAtSemi) && !HasFlagsSet(Flags, StopAtCodeCompletion)) { - while (Tok.getKind() != tok::eof) + while (Tok.isNot(tok::eof)) ConsumeAnyToken(); return true; } @@ -297,7 +297,15 @@ bool Parser::SkipUntil(ArrayRef Toks, SkipUntilFlags Flags) { case tok::eof: // Ran out of tokens. return false; - + + case tok::annot_module_begin: + case tok::annot_module_end: + case tok::annot_module_include: + // Stop before we change submodules. They generally indicate a "good" + // place to pick up parsing again (except in the special case where + // we're trying to skip to EOF). + return false; + case tok::code_completion: if (!HasFlagsSet(Flags, StopAtCodeCompletion)) ConsumeToken(); @@ -574,10 +582,12 @@ namespace { bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds); - // Skip over the EOF token, flagging end of previous input for incremental + // Skip over the EOF token, flagging end of previous input for incremental // processing - if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) + if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) { ConsumeToken(); + return false; + } Result = DeclGroupPtrTy(); switch (Tok.getKind()) { @@ -592,6 +602,12 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { ConsumeToken(); return false; + case tok::annot_module_begin: + case tok::annot_module_end: + // FIXME: Update visibility based on the submodule we're in. + ConsumeToken(); + return false; + case tok::eof: // Late template parsing can begin. if (getLangOpts().DelayedTemplateParsing) @@ -1917,14 +1933,15 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() { } // Parse the declarations. - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // FIXME: Support module import within __if_exists? + while (Tok.isNot(tok::r_brace) && !isEofOrEom()) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); MaybeParseMicrosoftAttributes(attrs); DeclGroupPtrTy Result = ParseExternalDeclaration(attrs); if (Result && !getCurScope()->getParent()) Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); - } + } Braces.consumeClose(); } @@ -1980,8 +1997,8 @@ bool BalancedDelimiterTracker::diagnoseOverflow() { P.Diag(P.Tok, diag::err_bracket_depth_exceeded) << P.getLangOpts().BracketDepth; P.Diag(P.Tok, diag::note_bracket_depth); - P.SkipUntil(tok::eof); - return true; + P.cutOffParsing(); + return true; } bool BalancedDelimiterTracker::expectAndConsume(unsigned DiagID, diff --git a/test/Modules/Inputs/malformed/a1.h b/test/Modules/Inputs/malformed/a1.h new file mode 100644 index 0000000000..400b916e21 --- /dev/null +++ b/test/Modules/Inputs/malformed/a1.h @@ -0,0 +1 @@ +void f() { diff --git a/test/Modules/Inputs/malformed/a2.h b/test/Modules/Inputs/malformed/a2.h new file mode 100644 index 0000000000..5c34318c21 --- /dev/null +++ b/test/Modules/Inputs/malformed/a2.h @@ -0,0 +1 @@ +} diff --git a/test/Modules/Inputs/malformed/b1.h b/test/Modules/Inputs/malformed/b1.h new file mode 100644 index 0000000000..3d98bc1b55 --- /dev/null +++ b/test/Modules/Inputs/malformed/b1.h @@ -0,0 +1,3 @@ +struct S { + #include "b2.h" +}; diff --git a/test/Modules/Inputs/malformed/b2.h b/test/Modules/Inputs/malformed/b2.h new file mode 100644 index 0000000000..7fc5340164 --- /dev/null +++ b/test/Modules/Inputs/malformed/b2.h @@ -0,0 +1 @@ +void g() {} diff --git a/test/Modules/Inputs/malformed/module.map b/test/Modules/Inputs/malformed/module.map new file mode 100644 index 0000000000..8fb6d7bd7d --- /dev/null +++ b/test/Modules/Inputs/malformed/module.map @@ -0,0 +1,8 @@ +module a { + module a1 { header "a1.h" } + module a2 { header "a2.h" } +} +module b { + module b1 { header "b1.h" } + module b2 { header "b2.h" } +} diff --git a/test/Modules/auto-module-import.m b/test/Modules/auto-module-import.m index d7fb9d1f9f..bf99377786 100644 --- a/test/Modules/auto-module-import.m +++ b/test/Modules/auto-module-import.m @@ -83,6 +83,6 @@ int getNotInModule() { return not_in_module; } -void includeNotAtTopLevel() { - #include // expected-warning {{treating #include as an import}} expected-error {{expected expression}} -} +void includeNotAtTopLevel() { // expected-note {{to match this '{'}} + #include // expected-warning {{treating #include as an import}} expected-error {{expected '}'}} +} // expected-error {{extraneous closing brace}} diff --git a/test/Modules/malformed.cpp b/test/Modules/malformed.cpp new file mode 100644 index 0000000000..705d289853 --- /dev/null +++ b/test/Modules/malformed.cpp @@ -0,0 +1,23 @@ +// RUN: rm -rf %t +// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/malformed -DHEADER="a1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-A +// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/malformed -DHEADER="b1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-B + +#define STR2(x) #x +#define STR(x) STR2(x) +#include STR(HEADER) + +// CHECK-A: While building module 'a' +// CHECK-A: a1.h:1:{{.*}} error: expected '}' +// CHECK-A: a1.h:1:{{.*}} note: to match this '{' +// +// CHECK-A: While building module 'a' +// CHECK-A: a2.h:1:{{.*}} error: extraneous closing brace + +// CHECK-B: While building module 'b' +// CHECK-B: b1.h:2:{{.*}} error: expected '}' +// CHECK-B: b1.h:1:{{.*}} note: to match this '{' +// CHECK-B: b1.h:3:{{.*}} error: extraneous closing brace ('}') +// +// CHECK-B: While building module 'b' +// CHECK-B: b2.h:1:{{.*}} error: redefinition of 'g' +// CHECK-B: b2.h:1:{{.*}} note: previous definition is here