Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nonblocking/nonallocating attributes: 2nd pass caller/callee analysis #99656

Merged
merged 71 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
8c5f854
nonblocking/nonallocating attributes: 2nd pass caller/callee analysis…
May 5, 2024
95b7a00
- Sema.h: Move function decls to be in the correct per-source-file se…
Jul 20, 2024
21c780a
clang-format
Jul 20, 2024
ff10413
- Detect ObjC @throw and @catch, diagnose identically to their C++ co…
Jul 26, 2024
d472964
FunctionEffect constructors: cast Kind to uint8_t
May 5, 2024
f1142db
New file: EFfectAnalysis.cpp.
Jul 26, 2024
efe1b93
CallableInfo doesn't need to cache the name.
Jul 26, 2024
d4f8dd5
Merge branch 'main' into nonblocking-part2
Jul 26, 2024
7ffdbef
Simpler bitmap implementation of FunctionEffectKindSet
Aug 2, 2024
c39e28e
- function does not permit inference of '%0': include the name of the…
Aug 2, 2024
dec1a61
Merge remote-tracking branch 'llvm-origin/main' into nonblocking-part2
Aug 5, 2024
06ca4c5
Add tests around lambda traversal and contexts like decltype, sizeof,…
Aug 7, 2024
9e45e6f
Inline checks preceding maybeAddDeclWithEffects
Aug 7, 2024
b99f784
Remove dead code in EffectAnalysis.cpp. Add comment about AST travers…
Aug 7, 2024
dbdd8f8
Merge remote-tracking branch 'llvm-origin/main' into nonblocking-part2
Aug 7, 2024
1b9874f
patch what the bot's clang-format wishes clang-format on my system wo…
Aug 7, 2024
b8818a3
Merge branch 'main' into nonblocking-part2
Aug 8, 2024
8390e69
"function cannot be inferred" -> "declaration cannot be inferred"
Aug 8, 2024
7acda8c
No need to override VisitCXXDefaultInitExpr.
Aug 8, 2024
bffacc5
Begin a list of unsafe builtin functions, starting with malloc and fr…
Aug 13, 2024
c718b5a
Apply suggestions from code review
dougsonos Aug 14, 2024
8b225f4
- FunctionEffect and FunctionEffectKindSet are tiny, pass by value wh…
Aug 14, 2024
2cb4539
- Comments begin with capital letters and end with full stops.
Aug 14, 2024
0e07315
Implement FunctionEffectKindSet with std::bitset.
Aug 14, 2024
47dfce8
Merge remote-tracking branch 'llvm-origin/main' into nonblocking-part2
Aug 14, 2024
fddd9d2
- Diagnose __builtin_operator_new and delete
Aug 14, 2024
eb536ab
EffectAnalysis.cpp => SemaFunctionEffects.cpp (minimal first step; mo…
Aug 15, 2024
15b399f
Move most Sema methods involving effects into SemaFunctionEffects.cpp.
Aug 15, 2024
dfebc1a
Move FunctionEffectDiff/Differences into SemaFunctionEffects.cpp.
Aug 16, 2024
82cb07d
Combine the diagnostics for 5 violations into one using %select{}
Aug 16, 2024
a7060ad
Merge branch 'main' into nonblocking-part2
Aug 16, 2024
f93ee01
Violation constructor: use optional instead of pointer.
Aug 16, 2024
6cc0a62
clang-format
Aug 16, 2024
69e1ae6
emitDiagnostics doesn't need to receive another S
Aug 16, 2024
076302e
VisitVarDecl can reuse followTypeDtor().
Aug 16, 2024
7b891c6
Add a test for a delegating initializer.
Aug 16, 2024
d1fcceb
Fix typo in comment for TraverseLambdaExpr.
Aug 16, 2024
abcf022
Fix test broken by rewording of diagnostics.
Aug 17, 2024
47ebf27
Diagnostics are now more specific about where a construct was found, …
Aug 17, 2024
6650c1f
Two fixes for default arguments:
Aug 20, 2024
250b80b
Type.cpp: remove asserts preceding llvm_unreachable().
Aug 20, 2024
e8bcd9f
Fix pre-C++20 compile error.
Aug 22, 2024
ea7f3fc
Review feedback: ViolationSite can use a PointerIntPair. Expand list …
Aug 29, 2024
d1a39e2
Fix: was traversing virtual base class destructors twice, exposed by …
Aug 29, 2024
75365ef
More builtin functions.
Aug 29, 2024
6aadec0
Apply suggestions from code review
dougsonos Sep 4, 2024
9b123a6
Review feedback:
Sep 4, 2024
ba57bfb
Fix: Don't try to follow a deleted destructor. (Happens with a std::o…
Sep 4, 2024
54feb05
Fix test broken by rewording of warnings.
Sep 5, 2024
93cb74e
Fix: need to ignore concept requirements.
Sep 5, 2024
d583c85
clang-format
Sep 5, 2024
cda1a9c
Make the FunctionEffects and PerfConstraintImpliesNoexcept diagnostic…
Sep 7, 2024
9c971c6
Add a release note.
Sep 7, 2024
b23e942
Merge branch 'main' into nonblocking-part2
Sep 8, 2024
9bfbe12
Fix botched format string in warn_func_effect_calls_expr_without_effect
Sep 9, 2024
f06909b
Fix test failures introduced by last commit.
Sep 17, 2024
adcfd14
If a function is noexcept and noreturn, exempt it from effect analysis.
Sep 18, 2024
17320b8
Remove the new diagnostics from `-Wall`. Fix a couple of sentences in…
Sep 23, 2024
909d7ff
Apply suggestions from code review
dougsonos Sep 23, 2024
9367103
Review feedback:
Sep 23, 2024
eb782e0
- Add constraint tests for plain C.
Sep 24, 2024
eccc7cf
-Wperf-constraint-implies-noexcept is part of -Wall again
Sep 24, 2024
220a1bf
Remove FunctionEffect::Kind::None as a sentinel; use optionals instead.
Sep 25, 2024
a8fef93
Ensure that setjmp() is not included in the special treatment of `nor…
Sep 26, 2024
092bc16
Update clang/lib/Sema/SemaFunctionEffects.cpp
dougsonos Sep 26, 2024
ca3f44a
Merge branch 'main' into nonblocking-part2
Sep 26, 2024
424a74b
Builtins with effects don't get the noexcept/noreturn special treatment.
Sep 26, 2024
273871a
warning-wall test was broken a few commits ago; fix it now.
Sep 26, 2024
a77d4e3
- FunctionEffect::Kind: no need to be specific with enum values. Same…
Sep 26, 2024
f8d9189
Tweak release note, fix typo in comment.
Sep 26, 2024
da725c1
Tweak: "function with 'nonblocking' attribute should be declared noex…
Oct 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 87 additions & 9 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "llvm/Support/PointerLikeTypeTraits.h"
#include "llvm/Support/TrailingObjects.h"
#include "llvm/Support/type_traits.h"
#include <bitset>
#include <cassert>
#include <cstddef>
#include <cstdint>
Expand Down Expand Up @@ -118,6 +119,8 @@ class EnumDecl;
class Expr;
class ExtQualsTypeCommonBase;
class FunctionDecl;
class FunctionEffectsRef;
class FunctionEffectKindSet;
class FunctionEffectSet;
class IdentifierInfo;
class NamedDecl;
Expand Down Expand Up @@ -4774,26 +4777,30 @@ class FunctionEffect {
/// The description printed in diagnostics, e.g. 'nonblocking'.
StringRef name() const;

/// Return true if the effect is allowed to be inferred on the callee,
/// which is either a FunctionDecl or BlockDecl.
/// Determine whether the effect is allowed to be inferred on the callee,
/// which is either a FunctionDecl or BlockDecl. If the returned optional
/// is empty, inference is permitted; otherwise it holds the effect which
/// blocked inference.
/// Example: This allows nonblocking(false) to prevent inference for the
/// function.
bool canInferOnFunction(const Decl &Callee) const;
std::optional<FunctionEffect>
effectProhibitingInference(const Decl &Callee,
FunctionEffectKindSet CalleeFX) const;

// Return false for success. When true is returned for a direct call, then the
// FE_InferrableOnCallees flag may trigger inference rather than an immediate
// diagnostic. Caller should be assumed to have the effect (it may not have it
// explicitly when inferring).
bool shouldDiagnoseFunctionCall(bool Direct,
ArrayRef<FunctionEffect> CalleeFX) const;
FunctionEffectKindSet CalleeFX) const;

friend bool operator==(const FunctionEffect &LHS, const FunctionEffect &RHS) {
friend bool operator==(FunctionEffect LHS, FunctionEffect RHS) {
return LHS.FKind == RHS.FKind;
}
friend bool operator!=(const FunctionEffect &LHS, const FunctionEffect &RHS) {
friend bool operator!=(FunctionEffect LHS, FunctionEffect RHS) {
return !(LHS == RHS);
}
friend bool operator<(const FunctionEffect &LHS, const FunctionEffect &RHS) {
friend bool operator<(FunctionEffect LHS, FunctionEffect RHS) {
return LHS.FKind < RHS.FKind;
}
};
Expand Down Expand Up @@ -4822,8 +4829,7 @@ struct FunctionEffectWithCondition {
EffectConditionExpr Cond;

FunctionEffectWithCondition() = default;
FunctionEffectWithCondition(const FunctionEffect &E,
const EffectConditionExpr &C)
FunctionEffectWithCondition(FunctionEffect E, const EffectConditionExpr &C)
: Effect(E), Cond(C) {}

/// Return a textual description of the effect, and its condition, if any.
Expand Down Expand Up @@ -4932,6 +4938,78 @@ class FunctionEffectsRef {
void dump(llvm::raw_ostream &OS) const;
};

/// A mutable set of FunctionEffect::Kind.
class FunctionEffectKindSet {
Sirraide marked this conversation as resolved.
Show resolved Hide resolved
// For now this only needs to be a bitmap.
constexpr static size_t EndBitPos = 8;
Sirraide marked this conversation as resolved.
Show resolved Hide resolved
using KindBitsT = std::bitset<EndBitPos>;

KindBitsT KindBits{};

explicit FunctionEffectKindSet(KindBitsT KB) : KindBits(KB) {}

constexpr static size_t kindToPos(FunctionEffect::Kind K) {
return size_t(K);
dougsonos marked this conversation as resolved.
Show resolved Hide resolved
}

public:
FunctionEffectKindSet() = default;
explicit FunctionEffectKindSet(FunctionEffectsRef FX) { insert(FX); }

// Iterates through the bits which are set.
class iterator {
Sirraide marked this conversation as resolved.
Show resolved Hide resolved
const FunctionEffectKindSet *Outer = nullptr;
size_t Idx = 0;

// If Idx does not reference a set bit, advance it until it does,
// or until it reaches EndBitPos.
void advanceToNextSetBit() {
while (Idx < EndBitPos && !Outer->KindBits.test(Idx))
++Idx;
}

public:
iterator();
iterator(const FunctionEffectKindSet &O, size_t I) : Outer(&O), Idx(I) {
advanceToNextSetBit();
}
bool operator==(const iterator &Other) const { return Idx == Other.Idx; }
bool operator!=(const iterator &Other) const { return Idx != Other.Idx; }

iterator operator++() {
++Idx;
advanceToNextSetBit();
return *this;
}

FunctionEffect operator*() const {
assert(Idx < EndBitPos);
dougsonos marked this conversation as resolved.
Show resolved Hide resolved
return FunctionEffect(FunctionEffect::Kind(Idx));
}
};

iterator begin() const { return iterator(*this, 0); }
iterator end() const { return iterator(*this, EndBitPos); }

void insert(FunctionEffect Effect) { KindBits.set(kindToPos(Effect.kind())); }
void insert(FunctionEffectsRef FX) {
for (FunctionEffect Item : FX.effects())
insert(Item);
}
void insert(FunctionEffectKindSet Set) { KindBits |= Set.KindBits; }

bool empty() const { return KindBits.none(); }
bool contains(const FunctionEffect::Kind EK) const {
return KindBits.test(kindToPos(EK));
}
void dump(llvm::raw_ostream &OS) const;

static FunctionEffectKindSet difference(FunctionEffectKindSet LHS,
FunctionEffectKindSet RHS) {
return FunctionEffectKindSet(LHS.KindBits & ~RHS.KindBits);
}
};

/// A mutable set of FunctionEffects and possibly conditions attached to them.
/// Used to compare and merge effects on declarations.
///
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,7 @@ def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInCon
// Warnings and notes related to the function effects system underlying
// the nonblocking and nonallocating attributes.
def FunctionEffects : DiagGroup<"function-effects">;
def PerfConstraintImpliesNoexcept : DiagGroup<"perf-constraint-implies-noexcept">;

// Warnings and notes InstallAPI verification.
def InstallAPIViolation : DiagGroup<"installapi-violation">;
Expand Down
45 changes: 45 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10950,6 +10950,51 @@ def warn_imp_cast_drops_unaligned : Warning<
InGroup<DiagGroup<"unaligned-qualifier-implicit-cast">>;

// Function effects
def warn_func_effect_violation : Warning<
"'%0' %select{function|constructor|destructor|lambda|block|constructor's member initializer}1 "
Sirraide marked this conversation as resolved.
Show resolved Hide resolved
"must not %select{allocate or deallocate memory|throw or catch exceptions|"
"have static local variables|use thread-local variables|access ObjC methods or properties}2">,
InGroup<FunctionEffects>;
def note_func_effect_violation : Note<
"%select{function|constructor|destructor|lambda|block|member initializer}0 "
"cannot be inferred '%1' because it "
"%select{allocates or deallocates memory|throws or catches exceptions|"
"has a static local variable|uses a thread-local variable|"
"accesses an ObjC method or property}2">;
def warn_func_effect_calls_func_without_effect : Warning<
"'%0' %select{function|constructor|destructor|lambda|block|constructor's member initializer}1 "
"must not call non-'%0' "
"%select{function|constructor|destructor|lambda|block}2 "
"'%3'">,
InGroup<FunctionEffects>;
def note_func_effect_calls_func_without_effect : Note<
"%select{function|constructor|destructor|lambda|block|member initializer}0 "
"cannot be inferred '%1' because it calls non-'%1' "
"%select{function|constructor|destructor|lambda|block}2 "
"'%3'">;
def warn_func_effect_calls_expr_without_effect : Warning<
"'%0' %select{function|constructor|destructor|lambda|block|constructor's member initializer}1 "
"must not call non-'%0' expression">,
InGroup<FunctionEffects>;
def note_func_effect_call_extern : Note<
"declaration cannot be inferred '%0' because it has no definition in this translation unit">;
def note_func_effect_call_disallows_inference : Note<
"%select{function|constructor|destructor|lambda|block}0 "
"does not permit inference of '%1' because it is declared '%2'">;
def note_func_effect_call_indirect : Note<
"%select{virtual method|function pointer}0 cannot be inferred '%1'">;
def warn_perf_constraint_implies_noexcept : Warning<
"'%0' function should be declared noexcept">,
InGroup<PerfConstraintImpliesNoexcept>;

// FIXME: It would be nice if we could provide fuller template expansion notes.
dougsonos marked this conversation as resolved.
Show resolved Hide resolved
def note_func_effect_from_template : Note<
"in template expansion here">;
def note_func_effect_in_constructor : Note<
"in%select{| implicit}0 constructor here">;
def note_in_evaluating_default_argument : Note<
"in evaluating default argument here">;

// spoofing nonblocking/nonallocating
def warn_invalid_add_func_effects : Warning<
"attribute '%0' should not be added via type conversion">,
Expand Down
Loading