v.g.vassilev updated this revision to Diff 475470.
v.g.vassilev marked an inline comment as not done.
v.g.vassilev added a comment.
Rebase + fix the failure on windows
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D127284/new/
https://reviews.llvm.org/D127284
Files:
clang/include/clang/AST/ASTNodeTraverser.h
clang/include/clang/AST/Decl.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/Basic/DeclNodes.td
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Driver/Options.td
clang/include/clang/Lex/Preprocessor.h
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/Template.h
clang/include/clang/Serialization/ASTBitCodes.h
clang/lib/AST/Decl.cpp
clang/lib/AST/DeclBase.cpp
clang/lib/AST/DeclPrinter.cpp
clang/lib/CodeGen/CGDecl.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/ModuleBuilder.cpp
clang/lib/Interpreter/IncrementalParser.cpp
clang/lib/Interpreter/Interpreter.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseTentative.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Serialization/ASTCommon.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/Interpreter/disambiguate-decl-stmt.cpp
clang/test/Interpreter/execute-stmts.cpp
clang/test/Interpreter/stmt-serialization.cpp
clang/unittests/Interpreter/InterpreterTest.cpp
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) {
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/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 <typename T> T call() { printf("called\n"); return T(); }
+call<int>();
+// 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/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<typename T> struct A { A(); A(T); };
+A() -> A<int>;
+
+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/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<FileScopeAsmDecl, ObjCImplDecl>(D))
+ if (isa<FileScopeAsmDecl, TopLevelStmtDecl, ObjCImplDecl>(D))
return true;
if (WritingModule && isPartOfPerModuleInitializer(D)) {
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<Stmt *, 32> 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<CompoundStmt>(Record.readStmt()));
@@ -3021,8 +3032,8 @@
return false;
}
- if (isa<FileScopeAsmDecl, ObjCProtocolDecl, ObjCImplDecl, ImportDecl,
- PragmaCommentDecl, PragmaDetectMismatchDecl>(D))
+ if (isa<FileScopeAsmDecl, TopLevelStmtDecl, ObjCProtocolDecl, ObjCImplDecl,
+ ImportDecl, PragmaCommentDecl, PragmaDetectMismatchDecl>(D))
return true;
if (isa<OMPThreadPrivateDecl, OMPDeclareReductionDecl, OMPDeclareMapperDecl,
OMPAllocateDecl, OMPRequiresDecl>(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/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/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -19549,6 +19549,12 @@
return New;
}
+Decl *Sema::ActOnTopLevelStmtDecl(const SmallVectorImpl<Stmt *> &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/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/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/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/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/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<llvm::StringError>("Parsing failed. "
"The consumer rejected a decl",
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/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<TopLevelStmtDecl>(D)->getOrConvertToFunction();
+ EmitTopLevelDecl(FD);
+ GlobalDecl GD(FD);
+ auto *Fn = cast<llvm::Function>(GetGlobalValue(getMangledName(GD)));
+ CXXGlobalInits.push_back(Fn);
+ break;
+ }
case Decl::Import: {
auto *Import = cast<ImportDecl>(D);
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/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/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/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<Stmt *> 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<TranslationUnitDecl>(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/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/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/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<Stmt *> &Stmts);
+
/// Handle a C++11 empty-declaration and attribute-declaration.
Decl *ActOnEmptyDeclaration(Scope *S, const ParsedAttributesView &AttrList,
SourceLocation SemiLoc);
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<Stmt *, 32> 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<Stmt*, 32> StmtVector;
- /// A SmallVector of expressions, with stack size 12 (the maximum used.)
+ /// A SmallVector of expressions.
typedef SmallVector<Expr*, 12> ExprVector;
/// A SmallVector of types.
typedef SmallVector<ParsedType, 12> TypeVector;
@@ -2456,6 +2456,8 @@
ParsingDeclSpec &DS,
llvm::function_ref<void(ParsingFieldDeclarator &)> 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/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<LangOptions &>(getLangOpts()).IncrementalExtensions = value;
}
/// Specify the point at which code-completion will be performed.
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<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable incremental processing extensions such as processing"
+ "statements on the global scope.">,
+ MarshallingInfoFlag<LangOpts<"IncrementalExtensions">>;
+
+
def fvalidate_ast_input_files_content:
Flag <["-"], "fvalidate-ast-input-files-content">,
Group<f_Group>, Flags<[CC1Option]>,
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/Basic/DeclNodes.td
===================================================================
--- clang/include/clang/Basic/DeclNodes.td
+++ clang/include/clang/Basic/DeclNodes.td
@@ -95,6 +95,7 @@
def Export : DeclNode<Decl>, DeclContext;
def ObjCPropertyImpl : DeclNode<Decl>;
def FileScopeAsm : DeclNode<Decl>;
+def TopLevelStmt : DeclNode<Decl>;
def AccessSpec : DeclNode<Decl>;
def Friend : DeclNode<Decl>;
def FriendTemplate : DeclNode<Decl>;
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/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<Stmt *> 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<Stmt *> Stmts);
+ static TopLevelStmtDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ SourceRange getSourceRange() const override LLVM_READONLY;
+ FunctionDecl *getOrConvertToFunction();
+ ArrayRef<Stmt *> statements() { return {Stmts, NumStmts}; }
+ ArrayRef<const Stmt *> 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/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) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits