From 4ee5a9bd7cb290aa6d8c4c0adb04c81ab9cd694c Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Mon, 4 Mar 2024 17:51:43 +0000 Subject: [PATCH] Try to fix llvm/llvm-project#83802 --- clang/include/clang/AST/Decl.h | 16 ++++++++++------ clang/include/clang/AST/DeclBase.h | 1 + clang/include/clang/Basic/DeclNodes.td | 2 +- clang/include/clang/Sema/Sema.h | 3 ++- clang/lib/AST/Decl.cpp | 11 ++++++++--- clang/lib/AST/DeclBase.cpp | 1 + clang/lib/Parse/ParseDecl.cpp | 24 ++++++++++++++++-------- clang/lib/Sema/SemaDecl.cpp | 15 ++++++++++++--- clang/test/Interpreter/execute-stmts.cpp | 10 ++++++++++ 9 files changed, 61 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 788f6ab97b1bbf..6d3176e7b9d07a 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -4335,7 +4335,7 @@ class FileScopeAsmDecl : public Decl { /// /// \note This is used in libInterpreter, clang -cc1 -fincremental-extensions /// and in tools such as clang-repl. -class TopLevelStmtDecl : public Decl { +class TopLevelStmtDecl : public Decl, public DeclContext { friend class ASTDeclReader; friend class ASTDeclWriter; @@ -4343,7 +4343,7 @@ class TopLevelStmtDecl : public Decl { bool IsSemiMissing = false; TopLevelStmtDecl(DeclContext *DC, SourceLocation L, Stmt *S) - : Decl(TopLevelStmt, DC, L), Statement(S) {} + : Decl(TopLevelStmt, DC, L), DeclContext(TopLevelStmt), Statement(S) {} virtual void anchor(); @@ -4354,15 +4354,19 @@ class TopLevelStmtDecl : public Decl { SourceRange getSourceRange() const override LLVM_READONLY; Stmt *getStmt() { return Statement; } const Stmt *getStmt() const { return Statement; } - void setStmt(Stmt *S) { - assert(IsSemiMissing && "Operation supported for printing values only!"); - Statement = S; - } + void setStmt(Stmt *S); bool isSemiMissing() const { return IsSemiMissing; } void setSemiMissing(bool Missing = true) { IsSemiMissing = Missing; } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == TopLevelStmt; } + + static DeclContext *castToDeclContext(const TopLevelStmtDecl *D) { + return static_cast(const_cast(D)); + } + static TopLevelStmtDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast(const_cast(DC)); + } }; /// Represents a block literal declaration, which is like an diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 12137387b676a7..8835b1c5258260 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -2005,6 +2005,7 @@ class DeclContext { case Decl::Block: case Decl::Captured: case Decl::ObjCMethod: + case Decl::TopLevelStmt: return true; default: return getDeclKind() >= Decl::firstFunction && diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 5e726c1bdf8fa5..cdd9b5cd07e1a5 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -95,7 +95,7 @@ def LinkageSpec : DeclNode, DeclContext; def Export : DeclNode, DeclContext; def ObjCPropertyImpl : DeclNode; def FileScopeAsm : DeclNode; -def TopLevelStmt : DeclNode; +def TopLevelStmt : DeclNode, DeclContext; def AccessSpec : DeclNode; def Friend : DeclNode; def FriendTemplate : DeclNode; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index cfd1c0f977c018..db116a82e6ead1 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3171,7 +3171,8 @@ class Sema final { SourceLocation AsmLoc, SourceLocation RParenLoc); - Decl *ActOnTopLevelStmtDecl(Stmt *Statement); + TopLevelStmtDecl *ActOnStartTopLevelStmtDecl(Scope *S); + void ActOnFinishTopLevelStmtDecl(TopLevelStmtDecl* D, Stmt *Statement); /// Handle a C++11 empty-declaration and attribute-declaration. Decl *ActOnEmptyDeclaration(Scope *S, const ParsedAttributesView &AttrList, diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index fbc45fb6397fdc..54f6e7d95aa068 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -5404,14 +5404,13 @@ FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C, 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(); + SourceLocation Loc = Statement ? Statement->getBeginLoc() : SourceLocation(); DeclContext *DC = C.getTranslationUnitDecl(); - return new (C, DC) TopLevelStmtDecl(DC, BeginLoc, Statement); + return new (C, DC) TopLevelStmtDecl(DC, Loc, Statement); } TopLevelStmtDecl *TopLevelStmtDecl::CreateDeserialized(ASTContext &C, @@ -5424,6 +5423,12 @@ SourceRange TopLevelStmtDecl::getSourceRange() const { return SourceRange(getLocation(), Statement->getEndLoc()); } +void TopLevelStmtDecl::setStmt(Stmt *S) { + assert(S); + Statement = S; + setLocation(Statement->getBeginLoc()); +} + void EmptyDecl::anchor() {} EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 834beef49a4441..85aa6fc1cf5716 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1301,6 +1301,7 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::ExternCContext: case Decl::LinkageSpec: case Decl::Export: + case Decl::TopLevelStmt: case Decl::Block: case Decl::Captured: case Decl::OMPDeclareReduction: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 43b2a32cce71ca..0c3ae23838726b 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5488,24 +5488,32 @@ Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() { // Parse a top-level-stmt. Parser::StmtVector Stmts; ParsedStmtContext SubStmtCtx = ParsedStmtContext(); - Actions.PushFunctionScope(); + ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); + TopLevelStmtDecl *TLSD = Actions.ActOnStartTopLevelStmtDecl(getCurScope()); StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx); - Actions.PopFunctionScopeInfo(); if (!R.isUsable()) return nullptr; - SmallVector DeclsInGroup; - DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(R.get())); + Actions.ActOnFinishTopLevelStmtDecl(TLSD, R.get()); if (Tok.is(tok::annot_repl_input_end) && Tok.getAnnotationValue() != nullptr) { ConsumeAnnotationToken(); - cast(DeclsInGroup.back())->setSemiMissing(); + TLSD->setSemiMissing(); } - // Currently happens for things like -fms-extensions and use `__if_exists`. - for (Stmt *S : Stmts) - DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(S)); + SmallVector DeclsInGroup; + DeclsInGroup.push_back(TLSD); + + // Currently happens for things like -fms-extensions and use `__if_exists`. + for (Stmt *S : Stmts) { + // Here we should be safe as `__if_exists` and friends are not introducing + // new variables which need to live outside file scope. + TopLevelStmtDecl *D = Actions.ActOnStartTopLevelStmtDecl(getCurScope()); + Actions.ActOnFinishTopLevelStmtDecl(D, S); + DeclsInGroup.push_back(D); + } return Actions.BuildDeclaratorGroup(DeclsInGroup); } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 21b5781a71cddd..dcda2091c223be 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -19949,12 +19949,21 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, return New; } -Decl *Sema::ActOnTopLevelStmtDecl(Stmt *Statement) { - auto *New = TopLevelStmtDecl::Create(Context, Statement); - Context.getTranslationUnitDecl()->addDecl(New); +TopLevelStmtDecl *Sema::ActOnStartTopLevelStmtDecl(Scope *S) { + auto *New = TopLevelStmtDecl::Create(Context, /*Statement=*/nullptr); + PushFunctionScope(); + ActOnStartOfCompoundStmt(/*IsStmtExpr=*/false); + PushDeclContext(S, New); return New; } +void Sema::ActOnFinishTopLevelStmtDecl(TopLevelStmtDecl* D, Stmt *Statement) { + D->setStmt(Statement); + PopDeclContext(); + ActOnFinishOfCompoundStmt(); + PopFunctionScopeInfo(); +} + void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, diff --git a/clang/test/Interpreter/execute-stmts.cpp b/clang/test/Interpreter/execute-stmts.cpp index 2d4c17e0c91e66..64bcd759350edf 100644 --- a/clang/test/Interpreter/execute-stmts.cpp +++ b/clang/test/Interpreter/execute-stmts.cpp @@ -41,3 +41,13 @@ for (; i > 4; --i) { printf("i = %d\n", i); }; int j = i; printf("j = %d\n", j); // CHECK-NEXT: j = 4 + +for(int i=0; i<2; i+=1) {}; + +for(int i=0; i<2; i+=1) ; + +int a = 2; +for(int i=0; i<2; i+=1) a-=1; + +int *aa=nullptr; +if (auto *b=aa) *b += 1;