Index: clang/include/clang/AST/ASTNodeTraverser.h =================================================================== --- clang/include/clang/AST/ASTNodeTraverser.h +++ clang/include/clang/AST/ASTNodeTraverser.h @@ -476,6 +476,11 @@ Visit(D->getAsmString()); } + void VisitTopLevelStmtDecl(const TopLevelStmtDecl *D) { + for (const Stmt *S : D->statements()) + Visit(S); + } + 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,44 @@ 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 **Stmts = nullptr; + unsigned NumStmts = 0; + FunctionDecl *FD = nullptr; + + TopLevelStmtDecl(DeclContext *DC, SourceLocation L) + : Decl(TopLevelStmt, DC, L) {} + + void setStmts(ASTContext &C, ArrayRef Statements) { + assert(!Statements.empty()); + Stmts = new (C) Stmt *[Statements.size()]; + std::uninitialized_copy(Statements.begin(), Statements.end(), Stmts); + NumStmts = Statements.size(); + } + + virtual void anchor(); + +public: + static TopLevelStmtDecl *Create(ASTContext &C, ArrayRef Stmts); + static TopLevelStmtDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + FunctionDecl *getOrConvertToFunction(); + ArrayRef statements() { return {Stmts, NumStmts}; } + ArrayRef statements() const { return {Stmts, NumStmts}; } + + 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,11 @@ DEF_TRAVERSE_DECL(FileScopeAsmDecl, { TRY_TO(TraverseStmt(D->getAsmString())); }) +DEF_TRAVERSE_DECL(TopLevelStmtDecl, { + for (auto *I : D->statements()) + TRY_TO(TraverseStmt(I)); +}) + 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(const SmallVectorImpl &Stmts); + /// 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,54 @@ SourceLocation()); } +void TopLevelStmtDecl::anchor() {} + +TopLevelStmtDecl *TopLevelStmtDecl::Create(ASTContext &C, + llvm::ArrayRef Stmts) { + assert(!Stmts.empty()); + assert(C.getLangOpts().IncrementalExtensions && + "Must be used only in incremental mode"); + + SourceLocation BeginLoc = Stmts[0]->getBeginLoc(); + DeclContext *DC = C.getTranslationUnitDecl(); + + auto *TLSD = new (C, DC) TopLevelStmtDecl(DC, BeginLoc); + TLSD->setStmts(C, Stmts); + return TLSD; +} + +TopLevelStmtDecl *TopLevelStmtDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + return new (C, ID) TopLevelStmtDecl(/*DC=*/nullptr, SourceLocation()); +} + +SourceRange TopLevelStmtDecl::getSourceRange() const { + return SourceRange(getLocation(), Stmts[NumStmts - 1]->getEndLoc()); +} + +FunctionDecl *TopLevelStmtDecl::getOrConvertToFunction() { + if (FD) + return FD; + + ASTContext &C = getASTContext(); + IdentifierInfo *Name = + &C.Idents.get("__stmts__" + llvm::utostr((uintptr_t)this)); + SourceLocation NoLoc; + SourceLocation BeginLoc = getBeginLoc(); + FunctionProtoType::ExtProtoInfo EPI; + QualType FunctionTy = C.getFunctionType(C.VoidTy, llvm::None, EPI); + TypeSourceInfo *TSI = C.getTrivialTypeSourceInfo(FunctionTy); + auto *TUDecl = cast(getDeclContext()); + FD = FunctionDecl::Create(C, TUDecl, BeginLoc, NoLoc, Name, FunctionTy, TSI, + SC_None); + + auto StmtArrayRef = llvm::makeArrayRef(Stmts, NumStmts); + auto *Body = CompoundStmt::Create(C, StmtArrayRef, FPOptionsOverride(), + BeginLoc, getEndLoc()); + FD->setBody(Body); + return FD; +} + 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,11 @@ Out << ")"; } +void DeclPrinter::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) { + for (const Stmt *S : D->statements()) + S->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.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -6354,6 +6354,14 @@ getModule().appendModuleInlineAsm(AD->getAsmString()->getString()); break; } + case Decl::TopLevelStmt: { + FunctionDecl *FD = cast(D)->getOrConvertToFunction(); + EmitTopLevelDecl(FD); + GlobalDecl GD(FD); + auto *Fn = cast(GetGlobalValue(getMangledName(GD))); + CXXGlobalInits.push_back(Fn); + 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 @@ -139,6 +139,8 @@ // 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"); + ClangArgv.insert(ClangArgv.begin() + 2, "-Xclang"); + ClangArgv.insert(ClangArgv.begin() + 3, "-fincremental-extensions"); if (!llvm::is_contained(ClangArgv, " -x")) { // We do C++ by default; append right after argv[0] if no "-x" given Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -5388,6 +5388,25 @@ } } +Decl *Parser::ParseTopLevelStmtDecl() { + if (!PP.isIncrementalProcessingEnabled()) + return nullptr; + + // Parse a top-level-stmt. + Parser::StmtVector Stmts; + ParsedStmtContext SubStmtCtx = ParsedStmtContext(); + StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); + if (!R.isUsable()) + return nullptr; + + Stmts.push_back(R.get()); + + if (!Stmts.empty()) + return Actions.ActOnTopLevelStmtDecl(Stmts); + + return nullptr; +} + /// 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,44 @@ /// '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."); + if (DisambiguatingWithExpression) { + if (Tok.is(tok::identifier)) { + 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; + } + } + } + switch (Tok.getKind()) { // asm-definition case tok::kw_asm: 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(const SmallVectorImpl &Stmts) { + auto *New = TopLevelStmtDecl::Create(Context, Stmts); + 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,16 @@ AD->setRParenLoc(readSourceLocation()); } +void ASTDeclReader::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) { + VisitDecl(D); + unsigned NumStmts = Record.readInt(); + llvm::SmallVector Statements; + Statements.reserve(NumStmts); + for (unsigned I = 0; I != NumStmts; ++I) + Statements.push_back(Record.readStmt()); + D->setStmts(Reader.getContext(), llvm::makeArrayRef(Statements)); +} + void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { VisitDecl(BD); BD->setBody(cast_or_null(Record.readStmt())); @@ -3021,8 +3032,8 @@ return false; } - if (isa(D)) + if (isa(D)) return true; if (isa(D)) @@ -3828,6 +3839,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,14 @@ Code = serialization::DECL_FILE_SCOPE_ASM; } +void ASTDeclWriter::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) { + VisitDecl(D); + Record.push_back(D->statements().size()); + for (Stmt *S : D->statements()) + Record.AddStmt(S); + Code = serialization::DECL_TOP_LEVEL_STMT_DECL; +} + void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) { VisitDecl(D); Code = serialization::DECL_EMPTY; @@ -2417,7 +2426,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) {