Index: clang/include/clang/AST/ASTNodeTraverser.h =================================================================== --- clang/include/clang/AST/ASTNodeTraverser.h +++ clang/include/clang/AST/ASTNodeTraverser.h @@ -476,6 +476,8 @@ Visit(D->getAsmString()); } + void VisitTopLevelStmtDecl(const TopLevelStmtDecl *D) { Visit(D->getStmt()); } + void VisitCapturedDecl(const CapturedDecl *D) { Visit(D->getBody()); } void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -4252,6 +4252,36 @@ static bool classofKind(Kind K) { return K == FileScopeAsm; } }; +/// A declaration that models statements at global scope. This declaration +/// supports incremental and interactive C/C++. +/// +/// \note This is used in libInterpreter, clang -cc1 -fincremental-extensions +/// and in tools such as clang-repl. +class TopLevelStmtDecl : public Decl { + friend class ASTDeclReader; + friend class ASTDeclWriter; + + Stmt *Statement = nullptr; + unsigned NumStmts = 0; + FunctionDecl *FD = nullptr; + + TopLevelStmtDecl(DeclContext *DC, SourceLocation L) + : Decl(TopLevelStmt, DC, L) {} + + virtual void anchor(); + +public: + static TopLevelStmtDecl *Create(ASTContext &C, Stmt *Statement); + static TopLevelStmtDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + Stmt *getStmt() { return Statement; } + const Stmt *getStmt() const { return Statement; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == TopLevelStmt; } +}; + /// Represents a block literal declaration, which is like an /// unnamed FunctionDecl. For example: /// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -1543,6 +1543,8 @@ DEF_TRAVERSE_DECL(FileScopeAsmDecl, { TRY_TO(TraverseStmt(D->getAsmString())); }) +DEF_TRAVERSE_DECL(TopLevelStmtDecl, { TRY_TO(TraverseStmt(D->getStmt())); }) + DEF_TRAVERSE_DECL(ImportDecl, {}) DEF_TRAVERSE_DECL(FriendDecl, { Index: clang/include/clang/Basic/DeclNodes.td =================================================================== --- clang/include/clang/Basic/DeclNodes.td +++ clang/include/clang/Basic/DeclNodes.td @@ -95,6 +95,7 @@ def Export : DeclNode, DeclContext; def ObjCPropertyImpl : DeclNode; def FileScopeAsm : DeclNode; +def TopLevelStmt : DeclNode; def AccessSpec : DeclNode; def Friend : DeclNode; def FriendTemplate : DeclNode; Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -459,6 +459,11 @@ // on large _BitInts. BENIGN_VALUE_LANGOPT(MaxBitIntWidth, 32, 128, "Maximum width of a _BitInt") +LANGOPT(IncrementalExtensions, 1, 0, " True if we want to process statements" + "on the global scope, ignore EOF token and continue later on (thus " + "avoid tearing the Lexer and etc. down). Controlled by " + "-fincremental-extensions.") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2320,6 +2320,14 @@ HelpText<"Do not enforce -fmodules-decluse and private header restrictions for textual headers. " "This flag will be removed in a future Clang release.">; +def fincremental_extensions : + Flag<["-"], "fincremental-extensions">, + Group, Flags<[CC1Option]>, + HelpText<"Enable incremental processing extensions such as processing" + "statements on the global scope.">, + MarshallingInfoFlag>; + + def fvalidate_ast_input_files_content: Flag <["-"], "fvalidate-ast-input-files-content">, Group, Flags<[CC1Option]>, Index: clang/include/clang/Lex/Preprocessor.h =================================================================== --- clang/include/clang/Lex/Preprocessor.h +++ clang/include/clang/Lex/Preprocessor.h @@ -283,10 +283,6 @@ /// Empty line handler. EmptylineHandler *Emptyline = nullptr; - /// True if we want to ignore EOF token and continue later on (thus - /// avoid tearing the Lexer and etc. down). - bool IncrementalProcessing = false; - public: /// The kind of translation unit we are processing. const TranslationUnitKind TUKind; @@ -1778,11 +1774,14 @@ void recomputeCurLexerKind(); /// Returns true if incremental processing is enabled - bool isIncrementalProcessingEnabled() const { return IncrementalProcessing; } + bool isIncrementalProcessingEnabled() const { + return getLangOpts().IncrementalExtensions; + } /// Enables the incremental processing void enableIncrementalProcessing(bool value = true) { - IncrementalProcessing = value; + // FIXME: Drop this interface. + const_cast(getLangOpts()).IncrementalExtensions = value; } /// Specify the point at which code-completion will be performed. Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -464,6 +464,9 @@ typedef Sema::FullExprArg FullExprArg; + /// A SmallVector of statements. + typedef SmallVector StmtVector; + // Parsing methods. /// Initialize - Warm up the parser. @@ -2074,10 +2077,7 @@ //===--------------------------------------------------------------------===// // C99 6.8: Statements and Blocks. - /// A SmallVector of statements, with stack size 32 (as that is the only one - /// used.) - typedef SmallVector StmtVector; - /// A SmallVector of expressions, with stack size 12 (the maximum used.) + /// A SmallVector of expressions. typedef SmallVector ExprVector; /// A SmallVector of types. typedef SmallVector TypeVector; @@ -2456,6 +2456,8 @@ ParsingDeclSpec &DS, llvm::function_ref FieldsCallback); + Decl *ParseTopLevelStmtDecl(); + bool isDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, bool DisambiguatingWithExpression = false); bool isTypeSpecifierQualifier(); @@ -2477,10 +2479,13 @@ /// isDeclarationStatement - Disambiguates between a declaration or an /// expression statement, when parsing function bodies. + /// + /// \param DisambiguatingWithExpression - True to indicate that the purpose of + /// this check is to disambiguate between an expression and a declaration. /// Returns true for declaration, false for expression. - bool isDeclarationStatement() { + bool isDeclarationStatement(bool DisambiguatingWithExpression = false) { if (getLangOpts().CPlusPlus) - return isCXXDeclarationStatement(); + return isCXXDeclarationStatement(DisambiguatingWithExpression); return isDeclarationSpecifier(ImplicitTypenameContext::No, true); } @@ -2547,7 +2552,7 @@ /// isCXXDeclarationStatement - C++-specialized function that disambiguates /// between a declaration or an expression statement, when parsing function /// bodies. Returns true for declaration, false for expression. - bool isCXXDeclarationStatement(); + bool isCXXDeclarationStatement(bool DisambiguatingWithExpression = false); /// isCXXSimpleDeclaration - C++-specialized function that disambiguates /// between a simple-declaration or an expression-statement. Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -3106,6 +3106,8 @@ SourceLocation AsmLoc, SourceLocation RParenLoc); + Decl *ActOnTopLevelStmtDecl(Stmt *Statement); + /// Handle a C++11 empty-declaration and attribute-declaration. Decl *ActOnEmptyDeclaration(Scope *S, const ParsedAttributesView &AttrList, SourceLocation SemiLoc); Index: clang/include/clang/Sema/Template.h =================================================================== --- clang/include/clang/Sema/Template.h +++ clang/include/clang/Sema/Template.h @@ -571,6 +571,7 @@ // Decls which never appear inside a class or function. #define OBJCCONTAINER(DERIVED, BASE) #define FILESCOPEASM(DERIVED, BASE) +#define TOPLEVELSTMT(DERIVED, BASE) #define IMPORT(DERIVED, BASE) #define EXPORT(DERIVED, BASE) #define LINKAGESPEC(DERIVED, BASE) Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -1315,6 +1315,9 @@ /// A FileScopeAsmDecl record. DECL_FILE_SCOPE_ASM, + /// A TopLevelStmtDecl record. + DECL_TOP_LEVEL_STMT_DECL, + /// A BlockDecl record. DECL_BLOCK, Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -5236,6 +5236,30 @@ SourceLocation()); } +void TopLevelStmtDecl::anchor() {} + +TopLevelStmtDecl *TopLevelStmtDecl::Create(ASTContext &C, Stmt *Statement) { + assert(Statement); + assert(C.getLangOpts().IncrementalExtensions && + "Must be used only in incremental mode"); + + SourceLocation BeginLoc = Statement->getBeginLoc(); + DeclContext *DC = C.getTranslationUnitDecl(); + + auto *TLSD = new (C, DC) TopLevelStmtDecl(DC, BeginLoc); + TLSD->Statement = Statement; + return TLSD; +} + +TopLevelStmtDecl *TopLevelStmtDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + return new (C, ID) TopLevelStmtDecl(/*DC=*/nullptr, SourceLocation()); +} + +SourceRange TopLevelStmtDecl::getSourceRange() const { + return SourceRange(getLocation(), Statement->getEndLoc()); +} + void EmptyDecl::anchor() {} EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { Index: clang/lib/AST/DeclBase.cpp =================================================================== --- clang/lib/AST/DeclBase.cpp +++ clang/lib/AST/DeclBase.cpp @@ -843,6 +843,7 @@ case LinkageSpec: case Export: case FileScopeAsm: + case TopLevelStmt: case StaticAssert: case ObjCPropertyImpl: case PragmaComment: Index: clang/lib/AST/DeclPrinter.cpp =================================================================== --- clang/lib/AST/DeclPrinter.cpp +++ clang/lib/AST/DeclPrinter.cpp @@ -72,6 +72,7 @@ void VisitLabelDecl(LabelDecl *D); void VisitParmVarDecl(ParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitTopLevelStmtDecl(TopLevelStmtDecl *D); void VisitImportDecl(ImportDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); @@ -932,6 +933,10 @@ Out << ")"; } +void DeclPrinter::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) { + D->getStmt()->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context); +} + void DeclPrinter::VisitImportDecl(ImportDecl *D) { Out << "@import " << D->getImportedModule()->getFullModuleName() << ";\n"; Index: clang/lib/CodeGen/CGDecl.cpp =================================================================== --- clang/lib/CodeGen/CGDecl.cpp +++ clang/lib/CodeGen/CGDecl.cpp @@ -90,6 +90,7 @@ case Decl::Export: case Decl::ObjCPropertyImpl: case Decl::FileScopeAsm: + case Decl::TopLevelStmt: case Decl::Friend: case Decl::FriendTemplate: case Decl::Block: Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -1590,6 +1590,7 @@ void EmitDeclContext(const DeclContext *DC); void EmitLinkageSpec(const LinkageSpecDecl *D); + void EmitTopLevelStmt(const TopLevelStmtDecl *D); /// Emit the function that initializes C++ thread_local variables. void EmitCXXThreadLocalInitFunc(); Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -6146,6 +6146,28 @@ EmitDeclContext(LSD); } +void CodeGenModule::EmitTopLevelStmt(const TopLevelStmtDecl *D) { + // void __stmts_N__(void) + std::string Name = "__stmts__" + llvm::utostr(CXXGlobalInits.size()); + FunctionArgList Args; + QualType RetTy = getContext().VoidTy; + const CGFunctionInfo &FnInfo = + getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args); + llvm::FunctionType *FnTy = getTypes().GetFunctionType(FnInfo); + llvm::Function *Fn = llvm::Function::Create( + FnTy, llvm::GlobalValue::InternalLinkage, Name, &getModule()); + + CodeGenFunction CGF(*this); + CGF.StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args, D->getBeginLoc(), + D->getBeginLoc()); + auto *TLSD = cast(D); + CGF.EmitStmt(TLSD->getStmt()); + + CGF.FinishFunction(D->getEndLoc()); + + CXXGlobalInits.push_back(Fn); +} + void CodeGenModule::EmitDeclContext(const DeclContext *DC) { for (auto *I : DC->decls()) { // Unlike other DeclContexts, the contents of an ObjCImplDecl at TU scope @@ -6355,6 +6377,10 @@ break; } + case Decl::TopLevelStmt: + EmitTopLevelStmt(cast(D)); + break; + case Decl::Import: { auto *Import = cast(D); Index: clang/lib/CodeGen/ModuleBuilder.cpp =================================================================== --- clang/lib/CodeGen/ModuleBuilder.cpp +++ clang/lib/CodeGen/ModuleBuilder.cpp @@ -179,6 +179,7 @@ } bool HandleTopLevelDecl(DeclGroupRef DG) override { + // FIXME: Why not return false and abort parsing? if (Diags.hasErrorOccurred()) return true; Index: clang/lib/Interpreter/IncrementalParser.cpp =================================================================== --- clang/lib/Interpreter/IncrementalParser.cpp +++ clang/lib/Interpreter/IncrementalParser.cpp @@ -101,7 +101,6 @@ CompletionConsumer = &CI.getCodeCompletionConsumer(); Preprocessor &PP = CI.getPreprocessor(); - PP.enableIncrementalProcessing(); PP.EnterMainSourceFile(); if (!CI.hasSema()) @@ -174,9 +173,6 @@ Sema::ModuleImportState ImportState; for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF; AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) { - // If we got a null return and something *was* parsed, ignore it. This - // is due to a top-level semicolon, an action override, or a parse error - // skipping something. if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) return llvm::make_error("Parsing failed. " "The consumer rejected a decl", Index: clang/lib/Interpreter/Interpreter.cpp =================================================================== --- clang/lib/Interpreter/Interpreter.cpp +++ clang/lib/Interpreter/Interpreter.cpp @@ -138,13 +138,11 @@ // specified. By prepending we allow users to override the default // action and use other actions in incremental mode. // FIXME: Print proper driver diagnostics if the driver flags are wrong. - ClangArgv.insert(ClangArgv.begin() + 1, "-c"); - - if (!llvm::is_contained(ClangArgv, " -x")) { - // We do C++ by default; append right after argv[0] if no "-x" given - ClangArgv.push_back("-x"); - ClangArgv.push_back("c++"); - } + // We do C++ by default; append right after argv[0] if no "-x" given + ClangArgv.insert(ClangArgv.end(), "-xc++"); + ClangArgv.insert(ClangArgv.end(), "-Xclang"); + ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions"); + ClangArgv.insert(ClangArgv.end(), "-c"); // Put a dummy C++ file on to ensure there's at least one compile job for the // driver to construct. Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -5388,6 +5388,22 @@ } } +Decl *Parser::ParseTopLevelStmtDecl() { + assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode"); + + // Parse a top-level-stmt. + Parser::StmtVector Stmts; + ParsedStmtContext SubStmtCtx = ParsedStmtContext(); + StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); + if (!R.isUsable()) + return nullptr; + + // FIXME: What do we do if we get something in Stmts? + assert(!Stmts.size() && "Unsupported multiple stmt!"); + + return Actions.ActOnTopLevelStmtDecl(R.get()); +} + /// isDeclarationSpecifier() - Return true if the current token is part of a /// declaration specifier. /// Index: clang/lib/Parse/ParseTentative.cpp =================================================================== --- clang/lib/Parse/ParseTentative.cpp +++ clang/lib/Parse/ParseTentative.cpp @@ -46,7 +46,10 @@ /// 'using' 'namespace' '::'[opt] nested-name-specifier[opt] /// namespace-name ';' /// -bool Parser::isCXXDeclarationStatement() { +bool Parser::isCXXDeclarationStatement( + bool DisambiguatingWithExpression /*=false*/) { + assert(getLangOpts().CPlusPlus && "Must be called for C++ only."); + switch (Tok.getKind()) { // asm-definition case tok::kw_asm: @@ -59,6 +62,41 @@ case tok::kw_static_assert: case tok::kw__Static_assert: return true; + case tok::identifier: { + if (DisambiguatingWithExpression) { + RevertingTentativeParsingAction TPA(*this); + // Parse the C++ scope specifier. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, + /*ObjectHasErrors=*/false, + /*EnteringContext=*/true); + + switch (Tok.getKind()) { + case tok::identifier: { + IdentifierInfo *II = Tok.getIdentifierInfo(); + bool isDeductionGuide = + Actions.isDeductionGuideName(getCurScope(), *II, Tok.getLocation()); + if (Actions.isCurrentClassName(*II, getCurScope(), &SS) || + isDeductionGuide) { + if (isConstructorDeclarator(/*Unqualified=*/SS.isEmpty(), + isDeductionGuide, + DeclSpec::FriendSpecified::No)) + return true; + } + break; + } + case tok::kw_operator: + return true; + case tok::annot_cxxscope: // Check if this is a dtor. + if (NextToken().is(tok::tilde)) + return true; + break; + default: + break; + } + } + } + [[fallthrough]]; // simple-declaration default: return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false); Index: clang/lib/Parse/Parser.cpp =================================================================== --- clang/lib/Parse/Parser.cpp +++ clang/lib/Parse/Parser.cpp @@ -1025,8 +1025,16 @@ ConsumeToken(); return nullptr; } + // FIXME: Remove the incremental processing pre-condition and verify clang + // still can pass its test suite, which will harden + // `isDeclarationStatement`. + if (PP.isIncrementalProcessingEnabled() && + !isDeclarationStatement(/*DisambiguatingWithExpression=*/true)) + SingleDecl = ParseTopLevelStmtDecl(); + // We can't tell whether this is a function-definition or declaration yet. - return ParseDeclarationOrFunctionDefinition(Attrs, DS); + if (!SingleDecl) + return ParseDeclarationOrFunctionDefinition(Attrs, DS); } // This routine returns a DeclGroup, if the thing we parsed only contains a Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -19549,6 +19549,12 @@ return New; } +Decl *Sema::ActOnTopLevelStmtDecl(Stmt *Statement) { + auto *New = TopLevelStmtDecl::Create(Context, Statement); + Context.getTranslationUnitDecl()->addDecl(New); + return New; +} + void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, Index: clang/lib/Serialization/ASTCommon.cpp =================================================================== --- clang/lib/Serialization/ASTCommon.cpp +++ clang/lib/Serialization/ASTCommon.cpp @@ -412,6 +412,7 @@ case Decl::PragmaComment: case Decl::PragmaDetectMismatch: case Decl::FileScopeAsm: + case Decl::TopLevelStmt: case Decl::AccessSpec: case Decl::Friend: case Decl::FriendTemplate: Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -402,6 +402,7 @@ void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitExportDecl(ExportDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD); + void VisitTopLevelStmtDecl(TopLevelStmtDecl *D); void VisitImportDecl(ImportDecl *D); void VisitAccessSpecDecl(AccessSpecDecl *D); void VisitFriendDecl(FriendDecl *D); @@ -1678,6 +1679,11 @@ AD->setRParenLoc(readSourceLocation()); } +void ASTDeclReader::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) { + VisitDecl(D); + D->Statement = Record.readStmt(); +} + void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { VisitDecl(BD); BD->setBody(cast_or_null(Record.readStmt())); @@ -3021,8 +3027,8 @@ return false; } - if (isa(D)) + if (isa(D)) return true; if (isa(D)) @@ -3828,6 +3834,9 @@ case DECL_FILE_SCOPE_ASM: D = FileScopeAsmDecl::CreateDeserialized(Context, ID); break; + case DECL_TOP_LEVEL_STMT_DECL: + D = TopLevelStmtDecl::CreateDeserialized(Context, ID); + break; case DECL_BLOCK: D = BlockDecl::CreateDeserialized(Context, ID); break; Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -124,6 +124,7 @@ void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitExportDecl(ExportDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitTopLevelStmtDecl(TopLevelStmtDecl *D); void VisitImportDecl(ImportDecl *D); void VisitAccessSpecDecl(AccessSpecDecl *D); void VisitFriendDecl(FriendDecl *D); @@ -1171,6 +1172,12 @@ Code = serialization::DECL_FILE_SCOPE_ASM; } +void ASTDeclWriter::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) { + VisitDecl(D); + Record.AddStmt(D->getStmt()); + Code = serialization::DECL_TOP_LEVEL_STMT_DECL; +} + void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) { VisitDecl(D); Code = serialization::DECL_EMPTY; @@ -2417,7 +2424,7 @@ // File scoped assembly or obj-c or OMP declare target implementation must be // seen. - if (isa(D)) + if (isa(D)) return true; if (WritingModule && isPartOfPerModuleInitializer(D)) { Index: clang/test/Interpreter/disambiguate-decl-stmt.cpp =================================================================== --- /dev/null +++ clang/test/Interpreter/disambiguate-decl-stmt.cpp @@ -0,0 +1,51 @@ +// REQUIRES: host-supports-jit +// UNSUPPORTED: system-aix +// RUN: cat %s | clang-repl -Xcc -std=c++20 -Xcc -Xclang -Xcc -verify | FileCheck %s +// RUN: %clang_cc1 -fsyntax-only -verify -fincremental-extensions -std=c++20 %s + +// expected-no-diagnostics + +extern "C" int printf(const char*,...); + +// Decls which are hard to disambiguate + +// Operators. +struct S1 { operator int(); }; +S1::operator int() { return 0; } + +// Dtors +using I = int; +I x = 10; +x.I::~I(); +x = 20; + +// Ctors + +// Deduction guide +template struct A { A(); A(T); }; +A() -> A; + +struct S2 { S2(); }; +S2::S2() = default; + +namespace N { struct S { S(); }; } +N::S::S() { printf("N::S::S()\n"); } +N::S s; +// CHECK: N::S::S() + +namespace Ns {namespace Ns { void Ns(); void Fs();}} +void Ns::Ns::Ns() { printf("void Ns::Ns::Ns()\n"); } +void Ns::Ns::Fs() {} + +Ns::Ns::Fs(); +Ns::Ns::Ns(); +// CHECK-NEXT: void Ns::Ns::Ns() + +struct Attrs1 { Attrs1(); }; +Attrs1::Attrs1() __attribute((pure)) = default; + +struct Attrs2 { Attrs2(); }; +__attribute((pure)) Attrs2::Attrs2() = default; + +// Extra semicolon +namespace N {}; Index: clang/test/Interpreter/execute-stmts.cpp =================================================================== --- /dev/null +++ clang/test/Interpreter/execute-stmts.cpp @@ -0,0 +1,33 @@ +// REQUIRES: host-supports-jit +// UNSUPPORTED: system-aix +// RUN: cat %s | clang-repl -Xcc -Xclang -Xcc -verify | FileCheck %s +// RUN: %clang_cc1 -fsyntax-only -verify -fincremental-extensions %s + +// expected-no-diagnostics + +extern "C" int printf(const char*,...); + +template T call() { printf("called\n"); return T(); } +call(); +// CHECK: called + +int i = 1; +++i; +printf("i = %d\n", i); +// CHECK: i = 2 + +namespace Ns { void f(){ i++; } } +Ns::f(); + +void g() { ++i; } +g(); +::g(); + +printf("i = %d\n", i); +// CHECK-NEXT: i = 5 + +for (; i > 4; --i) printf("i = %d\n", i); +// CHECK-NEXT: i = 5 + +int j = i; printf("j = %d\n", j); +// CHECK-NEXT: j = 4 Index: clang/test/Interpreter/stmt-serialization.cpp =================================================================== --- /dev/null +++ clang/test/Interpreter/stmt-serialization.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -std=c++20 -fincremental-extensions -fmodules-cache-path=%t \ +// RUN: -x c++ %s -verify +// expected-no-diagnostics + +#pragma clang module build TopLevelStmt +module TopLevelStmt { module Statements {} } +#pragma clang module contents + +#pragma clang module begin TopLevelStmt.Statements +extern "C" int printf(const char*,...); +int i = 0; +i++; +#pragma clang module end /*TopLevelStmt.Statements*/ +#pragma clang module endbuild /*TopLevelStmt*/ + +#pragma clang module import TopLevelStmt.Statements + +printf("Value of i is '%d'", i); Index: clang/unittests/Interpreter/InterpreterTest.cpp =================================================================== --- clang/unittests/Interpreter/InterpreterTest.cpp +++ clang/unittests/Interpreter/InterpreterTest.cpp @@ -124,14 +124,8 @@ auto *PTU1 = R1->TUPart; EXPECT_EQ(2U, DeclsSize(PTU1)); - // FIXME: Add support for wrapping and running statements. auto R2 = Interp->Parse("var1++; printf(\"var1 value %d\\n\", var1);"); - EXPECT_FALSE(!!R2); - using ::testing::HasSubstr; - EXPECT_THAT(DiagnosticsOS.str(), - HasSubstr("error: unknown type name 'var1'")); - auto Err = R2.takeError(); - EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err))); + EXPECT_TRUE(!!R2); } TEST(InterpreterTest, UndoCommand) {