diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6af50291e..1c683dd5c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,6 +54,11 @@ jobs: compiler: clang clang-runtime: '16' + - name: osx-clang-runtime17 + os: macos-latest + compiler: clang + clang-runtime: '17' + - name: win-msvc-runtime14 os: windows-latest compiler: msvc @@ -394,6 +399,10 @@ jobs: clang-runtime: '16' doc_build: true + - name: ubu22-clang16-runtime17 + os: ubuntu-22.04 + compiler: clang-16 + clang-runtime: '17' steps: - uses: actions/checkout@v3 with: @@ -521,13 +530,13 @@ jobs: echo "/usr/local/opt/ccache/libexec" >> $GITHUB_PATH PATH_TO_LLVM_BUILD=/usr/local/opt/llvm@${{ matrix.clang-runtime }}/ - # For now Package llvm@17 is unsuported on brew, llvm <=@11 are deprecated or deleted. + # For now Package llvm@18 is unsuported on brew, llvm <=@11 are deprecated or deleted. # Install llvm from github releases. - if [[ '${{ matrix.clang-runtime }}' == '17' || ${{ matrix.clang-runtime }} -le 11 ]]; then + if [[ '${{ matrix.clang-runtime }}' == '18' || ${{ matrix.clang-runtime }} -le 11 ]]; then PATH_TO_LLVM_BUILD=/usr/local/opt/llvm@${{ matrix.clang-runtime }}/ pushd /usr/local/opt w="0" - [ '${{ matrix.clang-runtime }}' == '17' ] && w="5" + [ '${{ matrix.clang-runtime }}' == '17' ] && w="6" sudo curl -L https://github.com/llvm/llvm-project/releases/download/llvmorg-${{ matrix.clang-runtime }}.0.$w/clang+llvm-${{ matrix.clang-runtime }}.0.$w-x86_64-apple-darwin.tar.xz | sudo xz -d -c | sudo tar -x sudo rm -fr /usr/local/clang* sudo mv clang+llvm-${{ matrix.clang-runtime }}.0.$w-x86_64-apple-darwin/ llvm@${{ matrix.clang-runtime }}/ @@ -544,7 +553,7 @@ jobs: popd fi - if [[ '${{ matrix.clang-runtime }}' != '17' && ${{ matrix.clang-runtime }} -gt 11 ]]; then + if [[ '${{ matrix.clang-runtime }}' != '18' && ${{ matrix.clang-runtime }} -gt 11 ]]; then brew install llvm@${{ matrix.clang-runtime }} else # Remove the c++ headers that come with the llvm package from homebrew diff --git a/README.md b/README.md index 03efa06ac..bd13047f4 100644 --- a/README.md +++ b/README.md @@ -231,7 +231,7 @@ Clad also provides certain flags to save and print the generated derivative code - To print the Clad generated derivative: `-Xclang -plugin-arg-clad -Xclang -fdump-derived-fn` ## How to install -At the moment, LLVM/Clang 5.0.x - 16.0.x are supported. +At the moment, LLVM/Clang 5.0.x - 17.0.x are supported. ### Conda Installation diff --git a/docs/internalDocs/ReleaseNotes.md b/docs/internalDocs/ReleaseNotes.md index 4d2b1aa0a..c210c56ec 100644 --- a/docs/internalDocs/ReleaseNotes.md +++ b/docs/internalDocs/ReleaseNotes.md @@ -21,7 +21,7 @@ described first. External Dependencies --------------------- -* Clad now works with clang-5.0 to clang-16 +* Clad now works with clang-5.0 to clang-17 Forward Mode & Reverse Mode diff --git a/include/clad/Differentiator/ReverseModeVisitor.h b/include/clad/Differentiator/ReverseModeVisitor.h index c49b8c0d8..0968055a6 100644 --- a/include/clad/Differentiator/ReverseModeVisitor.h +++ b/include/clad/Differentiator/ReverseModeVisitor.h @@ -453,7 +453,8 @@ namespace clad { /// Returns `ConditionResult` object for the counter. clang::Sema::ConditionResult getCounterConditionResult() { - return m_RMV.m_Sema.ActOnCondition(m_RMV.m_CurScope, noLoc, m_Ref, + return m_RMV.m_Sema.ActOnCondition(m_RMV.getCurrentScope(), noLoc, + m_Ref, clang::Sema::ConditionKind::Boolean); } }; diff --git a/include/clad/Differentiator/VisitorBase.h b/include/clad/Differentiator/VisitorBase.h index 09a7af293..f46addf2a 100644 --- a/include/clad/Differentiator/VisitorBase.h +++ b/include/clad/Differentiator/VisitorBase.h @@ -103,9 +103,8 @@ namespace clad { VisitorBase(DerivativeBuilder& builder) : m_Builder(builder), m_Sema(builder.m_Sema), m_CladPlugin(builder.m_CladPlugin), m_Context(builder.m_Context), - m_CurScope(m_Sema.TUScope), m_DerivativeFnScope(nullptr), - m_DerivativeInFlight(false), m_Derivative(nullptr), - m_Function(nullptr) {} + m_DerivativeFnScope(nullptr), m_DerivativeInFlight(false), + m_Derivative(nullptr), m_Function(nullptr) {} using Stmts = llvm::SmallVector; @@ -114,7 +113,6 @@ namespace clad { plugin::CladPlugin& m_CladPlugin; clang::ASTContext& m_Context; /// Current Scope at the point of visiting. - clang::Scope* m_CurScope; /// Pointer to the topmost Scope in the created derivative function. clang::Scope* m_DerivativeFnScope; bool m_DerivativeInFlight; @@ -148,10 +146,12 @@ namespace clad { // FIXME: Fix this inconsistency, by making `this` pointer derivative // expression to be of object type in the reverse mode as well. clang::Expr* m_ThisExprDerivative = nullptr; + /// A function used to wrap result of visiting E in a lambda. Returns a call /// to the built lambda. Func is a functor that will be invoked inside /// lambda scope and block. Statements inside lambda are expected to be /// added by addToCurrentBlock from func invocation. + // FIXME: This will become problematic when we try to support C. template static clang::Expr* wrapInLambda(VisitorBase& V, clang::Sema& S, const clang::Expr* E, F&& func) { @@ -168,11 +168,26 @@ namespace clad { clang::Declarator D(DS, CLAD_COMPAT_CLANG15_Declarator_DeclarationAttrs_ExtraParam CLAD_COMPAT_CLANG12_Declarator_LambdaExpr); +#if CLANG_VERSION_MAJOR > 16 + V.beginScope(clang::Scope::LambdaScope | clang::Scope::DeclScope | + clang::Scope::FunctionDeclarationScope | + clang::Scope::FunctionPrototypeScope); +#endif // CLANG_VERSION_MAJOR S.PushLambdaScope(); +#if CLANG_VERSION_MAJOR > 16 + S.ActOnLambdaExpressionAfterIntroducer(Intro, V.getCurrentScope()); + + S.ActOnLambdaClosureParameters(V.getCurrentScope(), /*ParamInfo=*/{}); +#endif // CLANG_VERSION_MAJOR + V.beginScope(clang::Scope::BlockScope | clang::Scope::FnScope | - clang::Scope::DeclScope); + clang::Scope::DeclScope | clang::Scope::CompoundStmtScope); S.ActOnStartOfLambdaDefinition(Intro, D, clad_compat::Sema_ActOnStartOfLambdaDefinition_ScopeOrDeclSpec(V.getCurrentScope(), DS)); +#if CLANG_VERSION_MAJOR > 16 + V.endScope(); +#endif // CLANG_VERSION_MAJOR + V.beginBlock(); func(); clang::CompoundStmt* body = V.endBlock(); @@ -211,22 +226,17 @@ namespace clad { bool addToBlock(clang::Stmt* S, Stmts& block); /// Get a current scope. - clang::Scope* getCurrentScope() { return m_CurScope; } + /// FIXME: Remove the pointer-ref + // clang::Scope* getCurrentScope() { return m_Sema.getCurScope(); } + clang::Scope*& getCurrentScope(); + void setCurrentScope(clang::Scope* S); + /// Returns the innermost enclosing file context which can be either a + /// namespace or the TU scope. + clang::Scope* getEnclosingNamespaceOrTUScope(); + /// Enters a new scope. - void beginScope(unsigned ScopeFlags) { - // FIXME: since Sema::CurScope is private, we cannot access it and have - // to use separate member variable m_CurScope. The only options to set - // CurScope of Sema seemt to be through Parser or ContextAndScopeRAII. - m_CurScope = - new clang::Scope(getCurrentScope(), ScopeFlags, m_Sema.Diags); - } - void endScope() { - // This will remove all the decls in the scope from the IdResolver. - m_Sema.ActOnPopScope(noLoc, m_CurScope); - auto oldScope = m_CurScope; - m_CurScope = oldScope->getParent(); - delete oldScope; - } + void beginScope(unsigned ScopeFlags); + void endScope(); /// A shorthand to simplify syntax for creation of new expressions. /// This function uses m_Sema.BuildUnOp internally to build unary diff --git a/lib/Differentiator/BaseForwardModeVisitor.cpp b/lib/Differentiator/BaseForwardModeVisitor.cpp index 986b61bdf..d65fae998 100644 --- a/lib/Differentiator/BaseForwardModeVisitor.cpp +++ b/lib/Differentiator/BaseForwardModeVisitor.cpp @@ -165,7 +165,7 @@ BaseForwardModeVisitor::Derive(const FunctionDecl* FD, SourceLocation loc{m_Function->getLocation()}; DeclarationNameInfo name(II, loc); llvm::SaveAndRestore SaveContext(m_Sema.CurContext); - llvm::SaveAndRestore SaveScope(m_CurScope); + llvm::SaveAndRestore SaveScope(getCurrentScope()); DeclContext* DC = const_cast(m_Function->getDeclContext()); m_Sema.CurContext = DC; DeclWithContext result = @@ -426,7 +426,8 @@ BaseForwardModeVisitor::DerivePushforward(const FunctionDecl* FD, QualType derivedFnType = m_Context.getFunctionType( returnType, paramTypes, originalFnType->getExtProtoInfo()); llvm::SaveAndRestore saveContext(m_Sema.CurContext); - llvm::SaveAndRestore saveScope(m_CurScope); + llvm::SaveAndRestore saveScope(getCurrentScope(), + getEnclosingNamespaceOrTUScope()); auto* DC = const_cast(m_Function->getDeclContext()); m_Sema.CurContext = DC; @@ -625,11 +626,11 @@ StmtDiff BaseForwardModeVisitor::VisitConditionalOperator( StmtDiff ifFalseDiff = Visit(CO->getFalseExpr()); cond = StoreAndRef(cond); - cond = - m_Sema - .ActOnCondition(m_CurScope, noLoc, cond, Sema::ConditionKind::Boolean) - .get() - .second; + cond = m_Sema + .ActOnCondition(getCurrentScope(), noLoc, cond, + Sema::ConditionKind::Boolean) + .get() + .second; Expr* condExpr = m_Sema @@ -737,7 +738,8 @@ StmtDiff BaseForwardModeVisitor::VisitReturnStmt(const ReturnStmt* RS) { StmtDiff retValDiff = Visit(RS->getRetValue()); Stmt* returnStmt = - m_Sema.ActOnReturnStmt(noLoc, retValDiff.getExpr_dx(), m_CurScope).get(); + m_Sema.ActOnReturnStmt(noLoc, retValDiff.getExpr_dx(), getCurrentScope()) + .get(); return StmtDiff(returnStmt); } diff --git a/lib/Differentiator/HessianModeVisitor.cpp b/lib/Differentiator/HessianModeVisitor.cpp index a85bfd49a..b44131a16 100644 --- a/lib/Differentiator/HessianModeVisitor.cpp +++ b/lib/Differentiator/HessianModeVisitor.cpp @@ -228,7 +228,8 @@ namespace clad { // Create the gradient function declaration. DeclContext* DC = const_cast(m_Function->getDeclContext()); llvm::SaveAndRestore SaveContext(m_Sema.CurContext); - llvm::SaveAndRestore SaveScope(m_CurScope); + llvm::SaveAndRestore SaveScope(getCurrentScope(), + getEnclosingNamespaceOrTUScope()); m_Sema.CurContext = DC; DeclWithContext result = m_Builder.cloneFunction( diff --git a/lib/Differentiator/ReverseModeForwPassVisitor.cpp b/lib/Differentiator/ReverseModeForwPassVisitor.cpp index 606664301..3e8fb1f11 100644 --- a/lib/Differentiator/ReverseModeForwPassVisitor.cpp +++ b/lib/Differentiator/ReverseModeForwPassVisitor.cpp @@ -39,7 +39,8 @@ ReverseModeForwPassVisitor::Derive(const FunctionDecl* FD, sourceFnType->getExtProtoInfo()); llvm::SaveAndRestore saveContext(m_Sema.CurContext); - llvm::SaveAndRestore saveScope(m_CurScope); + llvm::SaveAndRestore saveScope(getCurrentScope(), + getEnclosingNamespaceOrTUScope()); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) m_Sema.CurContext = const_cast(m_Function->getDeclContext()); diff --git a/lib/Differentiator/ReverseModeVisitor.cpp b/lib/Differentiator/ReverseModeVisitor.cpp index 0b3d53d0f..542f80a26 100644 --- a/lib/Differentiator/ReverseModeVisitor.cpp +++ b/lib/Differentiator/ReverseModeVisitor.cpp @@ -346,7 +346,8 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, // Create the gradient function declaration. llvm::SaveAndRestore SaveContext(m_Sema.CurContext); - llvm::SaveAndRestore SaveScope(m_CurScope); + llvm::SaveAndRestore SaveScope(getCurrentScope(), + getEnclosingNamespaceOrTUScope()); auto* DC = const_cast(m_Function->getDeclContext()); m_Sema.CurContext = DC; DeclWithContext result = m_Builder.cloneFunction( @@ -488,7 +489,8 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, m_Context.VoidTy, paramTypes, originalFnType->getExtProtoInfo()); llvm::SaveAndRestore saveContext(m_Sema.CurContext); - llvm::SaveAndRestore saveScope(m_CurScope); + llvm::SaveAndRestore saveScope(getCurrentScope(), + getEnclosingNamespaceOrTUScope()); m_Sema.CurContext = const_cast(m_Function->getDeclContext()); DeclWithContext fnBuildRes = m_Builder.cloneFunction( @@ -815,9 +817,7 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, for (Stmt*& S : cond.getBothStmts()) if (S) S = m_Sema - .ActOnCondition(m_CurScope, - noLoc, - cast(S), + .ActOnCondition(getCurrentScope(), noLoc, cast(S), Sema::ConditionKind::Boolean) .get() .second; @@ -935,9 +935,7 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, // StmtDiff. for (Stmt*& S : cond.getBothStmts()) S = m_Sema - .ActOnCondition(m_CurScope, - noLoc, - cast(S), + .ActOnCondition(getCurrentScope(), noLoc, cast(S), Sema::ConditionKind::Boolean) .get() .second; @@ -2842,9 +2840,9 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, // to let Sema::LookupName see the whole scope. auto* identifier = CreateUniqueIdentifier(prefix); // Save current scope and temporarily go to topmost function scope. - llvm::SaveAndRestore SaveScope(m_CurScope); + llvm::SaveAndRestore SaveScope(getCurrentScope()); assert(m_DerivativeFnScope && "must be set"); - m_CurScope = m_DerivativeFnScope; + setCurrentScope(m_DerivativeFnScope); VarDecl* Var = nullptr; if (isa(Type)) { diff --git a/lib/Differentiator/VectorForwardModeVisitor.cpp b/lib/Differentiator/VectorForwardModeVisitor.cpp index 87f268176..f07458814 100644 --- a/lib/Differentiator/VectorForwardModeVisitor.cpp +++ b/lib/Differentiator/VectorForwardModeVisitor.cpp @@ -117,7 +117,7 @@ VectorForwardModeVisitor::DeriveVectorMode(const FunctionDecl* FD, // Function declaration scope llvm::SaveAndRestore SaveContext(m_Sema.CurContext); - llvm::SaveAndRestore SaveScope(m_CurScope); + llvm::SaveAndRestore SaveScope(getCurrentScope()); beginScope(Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | Scope::DeclScope); m_Sema.PushFunctionScope(); diff --git a/lib/Differentiator/VisitorBase.cpp b/lib/Differentiator/VisitorBase.cpp index 80b6678c6..888fc54bf 100644 --- a/lib/Differentiator/VisitorBase.cpp +++ b/lib/Differentiator/VisitorBase.cpp @@ -44,6 +44,10 @@ namespace clad { ignoreExpr, ignoreLoc, ignoreRange, ignoreRange, m_Context); } + bool VisitorBase::addToCurrentBlock(Stmt* S) { + return addToBlock(S, getCurrentBlock()); + } + bool VisitorBase::addToBlock(Stmt* S, Stmts& block) { if (!S) return false; @@ -55,8 +59,69 @@ namespace clad { return true; } - bool VisitorBase::addToCurrentBlock(Stmt* S) { - return addToBlock(S, getCurrentBlock()); + // A facility allowing us to access the private member CurScope of the Sema + // object using standard-conforming C++. + namespace { + template struct Rob { + friend typename Tag::type get(Tag) { return M; } + }; + + template struct TagBase { + using type = Member; +#ifdef MSVC +#pragma warning(push, 0) +#endif // MSVC +#pragma GCC diagnostic push +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Wnon-template-friend" + friend type get(Tag); +#pragma GCC diagnostic pop +#ifdef MSVC +#pragma warning(pop) +#endif // MSVC + }; + + // Tag used to access Sema::CurScope. + using namespace clang; + struct Sema_CurScope : TagBase {}; + template struct Rob; + } // namespace + + clang::Scope*& VisitorBase::getCurrentScope() { + return m_Sema.*get(Sema_CurScope()); + } + + void VisitorBase::setCurrentScope(clang::Scope* S) { + m_Sema.*get(Sema_CurScope()) = S; + assert(getEnclosingNamespaceOrTUScope() && "Lost path to base."); + } + + clang::Scope* VisitorBase::getEnclosingNamespaceOrTUScope() { + auto isNamespaceOrTUScope = [](const clang::Scope* S) { + if (clang::DeclContext* DC = S->getEntity()) + return DC->isFileContext(); + return false; + }; + clang::Scope* InnermostFileScope = getCurrentScope(); + while (InnermostFileScope && !isNamespaceOrTUScope(InnermostFileScope)) + InnermostFileScope = InnermostFileScope->getParent(); + + return InnermostFileScope; + } + + void VisitorBase::beginScope(unsigned ScopeFlags) { + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + auto* S = new clang::Scope(getCurrentScope(), ScopeFlags, m_Sema.Diags); + setCurrentScope(S); + } + + void VisitorBase::endScope() { + // This will remove all the decls in the scope from the IdResolver. + m_Sema.ActOnPopScope(noLoc, getCurrentScope()); + clang::Scope* oldScope = getCurrentScope(); + setCurrentScope(oldScope->getParent()); + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + delete oldScope; } VarDecl* VisitorBase::BuildVarDecl(QualType Type, IdentifierInfo* Identifier, @@ -125,7 +190,7 @@ namespace clad { NamespaceDecl* NDecl = clad_compat::NamespaceDecl_Create( m_Context, m_Sema.CurContext, isInline, noLoc, noLoc, II, PrevNS); if (II) - m_Sema.PushOnScopeChains(NDecl, m_CurScope); + m_Sema.PushOnScopeChains(NDecl, getCurrentScope()); else { // Link the anonymous namespace into its parent. // From Sema::ActOnStartNamespaceDef: @@ -152,7 +217,7 @@ namespace clad { } // Namespace scope and declcontext. Must be exited by the user. beginScope(Scope::DeclScope); - m_Sema.PushDeclContext(m_CurScope, NDecl); + m_Sema.PushDeclContext(getCurrentScope(), NDecl); return NDecl; } @@ -206,7 +271,7 @@ namespace clad { IdentifierInfo* name = &m_Context.Idents.get(nameBase.str() + idStr); LookupResult R( m_Sema, DeclarationName(name), noLoc, Sema::LookupOrdinaryName); - m_Sema.LookupName(R, m_CurScope, /*AllowBuiltinCreation*/ false); + m_Sema.LookupName(R, getCurrentScope(), /*AllowBuiltinCreation*/ false); if (R.empty()) { return name; } else { diff --git a/test/FirstDerivative/Loops.C b/test/FirstDerivative/Loops.C index 4fef1c66b..03257ff34 100644 --- a/test/FirstDerivative/Loops.C +++ b/test/FirstDerivative/Loops.C @@ -378,7 +378,7 @@ double fn10_darg0(double x, size_t n); // CHECK-NEXT: { // CHECK-NEXT: size_t _d_count = 0; // CHECK-NEXT: size_t _d_max_count = _d_n; -// CHECK-NEXT: for (size_t count = 0; max_count; ++count) { +// CHECK-NEXT: for (size_t count = 0; {{.*}}max_count{{.*}}; ++count) { // CHECK-NEXT: if (count >= max_count) // CHECK-NEXT: break; // CHECK-NEXT: {