Skip to content

Add an opt-in mechanism for non-differentiable types. - #1930

Merged
vgvassilev merged 1 commit into
masterfrom
clad-nondiff-engine
Jul 29, 2026
Merged

Add an opt-in mechanism for non-differentiable types.#1930
vgvassilev merged 1 commit into
masterfrom
clad-nondiff-engine

Conversation

@vgvassilev

Copy link
Copy Markdown
Owner

When clad has no custom derivative for a called function it synthesizes one by cloning the function's body. For a type whose internals are not meant to be differentiated -- a standard-library primitive, an I/O stream -- that clone is at best wasteful and at worst ill-formed: cloning std::string's char-pointer constructor emits a static reverse-forward propagator that dereferences a null this and crashes CodeGen.

A type is now non-differentiable when it carries the non_differentiable annotation -- on the type itself for code the user owns (CLAD_NONDIFFERENTIABLE), or on a clad::Tag specialization for a foreign type the user cannot annotate at its declaration (CLAD_NONDIFFERENTIABLE_TYPE). utils::isNonDifferentiableType detects it, so clad never clones such a type's constructor or member bodies, and callOperatesOnNonDifferentiableType extends the treatment to a call whose object is opaque (e.g. a std::ostream operation). Seed std::string, std::allocator and the stream family in STLBuiltins.h.

-fclad-porting-hints prints the paste-able CLAD_NONDIFFERENTIABLE_TYPE spelling and, for a reverse-forward pass, the elidable_reverse_forw route with its signature -- pointing at existing mechanisms rather than inventing new ones. isElidableConstructor is renamed to constructorReverseForwIsElidable and documented so its "a trivial copy is a shallow share" coverage is discoverable; that made a separate data-less-copy heuristic unnecessary.

The user guide documents both macros; tests cover marker-based construction opacity (StringConstructor) and a marked-type call (NonDifferentiableMarkedType).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

/// declaration -- non-differentiable, by specializing clad::Tag for it. Use at
/// global scope. The type may contain commas, e.g.
/// CLAD_NONDIFFERENTIABLE_TYPE(std::map<int, double>);
#define CLAD_NONDIFFERENTIABLE_TYPE(...) \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variadic macro 'CLAD_NONDIFFERENTIABLE_TYPE' used; consider using a 'constexpr' variadic template function [cppcoreguidelines-macro-usage]

#define CLAD_NONDIFFERENTIABLE_TYPE(...)                                       \
        ^

class CLAD_NONDIFFERENTIABLE Tag<::std::basic_streambuf<C, Tr>> {};
template <class C, class Tr>
class CLAD_NONDIFFERENTIABLE Tag<::std::basic_ios<C, Tr>> {};
template <> class CLAD_NONDIFFERENTIABLE Tag<::std::ios_base> {};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "std::ios_base" is directly included [misc-include-cleaner]

include/clad/Differentiator/STLBuiltins.h:9:

- #include <iosfwd>
+ #include <ios>
+ #include <iosfwd>

// The value-level macro marks a single type; a template instantiation is
// only that specialization. Marking the whole family needs a clad::Tag
// partial specialization the macro cannot express.
if (isa<clang::ClassTemplateSpecializationDecl>(RD))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "clang::ClassTemplateSpecializationDecl" is directly included [misc-include-cleaner]

lib/Differentiator/DerivativeBuilder.cpp:52:

- #include <cstddef>
+ #include <clang/AST/DeclTemplate.h>
+ #include <cstddef>

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.41270% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
lib/Differentiator/ReverseModeVisitor.cpp 95.83% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@vgvassilev
vgvassilev force-pushed the clad-nondiff-engine branch 2 times, most recently from 094ae6a to 72afcb2 Compare July 29, 2026 16:23
When clad has no custom derivative for a called function it synthesizes
one by cloning the function's body. For a type whose internals are not
meant to be differentiated -- a standard-library primitive, an I/O
stream -- that clone is at best wasteful and at worst ill-formed:
cloning std::string's char-pointer constructor emits a static
reverse-forward propagator that dereferences a null `this` and crashes
CodeGen.

A type is now non-differentiable when it carries the `non_differentiable`
annotation -- on the type itself for code the user owns
(CLAD_NONDIFFERENTIABLE), or on a clad::Tag<T> specialization for a
foreign type the user cannot annotate at its declaration
(CLAD_NONDIFFERENTIABLE_TYPE). utils::isNonDifferentiableType detects it,
so clad never clones such a type's constructor or member bodies, and
callOperatesOnNonDifferentiableType extends the treatment to a call whose
object is opaque (e.g. a std::ostream operation). Seed std::string,
std::allocator and the stream family in STLBuiltins.h.

-fclad-porting-hints prints the paste-able CLAD_NONDIFFERENTIABLE_TYPE
spelling and, for a reverse-forward pass, the elidable_reverse_forw
route with its signature -- pointing at existing mechanisms rather than
inventing new ones. isElidableConstructor is renamed to
constructorReverseForwIsElidable and documented so its "a trivial copy is
a shallow share" coverage is discoverable; that made a separate
data-less-copy heuristic unnecessary.

The user guide documents both macros; tests cover marker-based
construction opacity (StringConstructor) and a marked-type call
(NonDifferentiableMarkedType).
@vgvassilev
vgvassilev force-pushed the clad-nondiff-engine branch from 72afcb2 to 42cb8e2 Compare July 29, 2026 17:29
@vgvassilev
vgvassilev merged commit 67937c2 into master Jul 29, 2026
40 checks passed
@vgvassilev
vgvassilev deleted the clad-nondiff-engine branch July 29, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant