Skip to content

Commit c6edde1

Browse files
authored
Normalize bounds for BoundsDeclFacts (#1113)
* Add NormalizedBounds field to BoundsDeclFact * Add getVarDecl and getBoundsExpr methods to BoundsDeclFact * Add a NormalizeBounds method to Sema for BoundsDeclFact * Do not normalize bounds for BoundsDeclFacts with invalid VarDecls * Normalize bounds when creating a BoundsDeclFact * Make BoundsUtil::ExpandToRange for VarDecl private * Make BoundsDeclFact members private
1 parent fbd6648 commit c6edde1

6 files changed

Lines changed: 98 additions & 11 deletions

File tree

clang/include/clang/AST/Expr.h

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7156,17 +7156,63 @@ class WhereClauseFact {
71567156

71577157
/// \brief Represents a Checked C where clause bounds decl fact.
71587158
class BoundsDeclFact : public WhereClauseFact {
7159-
public:
7159+
private:
71607160
VarDecl *Var;
71617161
BoundsExpr *Bounds;
7162+
BoundsExpr *NormalizedBounds;
71627163

7164+
public:
71637165
BoundsDeclFact(VarDecl *Var, BoundsExpr *Bounds, SourceLocation Loc)
71647166
: WhereClauseFact(FactKind::BoundsDeclFact, Loc),
7165-
Var(Var), Bounds(Bounds) {}
7167+
Var(Var), Bounds(Bounds), NormalizedBounds(nullptr) {}
71667168

71677169
static bool classof(const WhereClauseFact *Fact) {
71687170
return Fact->Kind == FactKind::BoundsDeclFact;
71697171
}
7172+
7173+
// \brief The variable declaration associated with this bounds fact.
7174+
VarDecl *getVarDecl() const {
7175+
return const_cast<BoundsDeclFact *>(this)->getVarDecl();
7176+
}
7177+
7178+
// \brief The variable declaration associated with this bounds fact.
7179+
VarDecl *getVarDecl() {
7180+
return Var;
7181+
}
7182+
7183+
// \brief The bounds expression associated with this bounds fact.
7184+
BoundsExpr *getBoundsExpr() const {
7185+
return const_cast<BoundsDeclFact *>(this)->getBoundsExpr();
7186+
}
7187+
7188+
// \brief The bounds expression associated with this bounds fact.
7189+
BoundsExpr *getBoundsExpr() {
7190+
return Bounds;
7191+
}
7192+
7193+
// \brief The bounds expression for this bounds fact, expanded to a
7194+
// range bounds expression.
7195+
BoundsExpr *getNormalizedBounds() const {
7196+
return const_cast<BoundsDeclFact *>(this)->getNormalizedBounds();
7197+
}
7198+
7199+
// \brief The bounds expression for this bounds fact, expanded to a
7200+
// range bounds expression.
7201+
BoundsExpr *getNormalizedBounds() {
7202+
return NormalizedBounds;
7203+
}
7204+
7205+
// \brief Set the bounds expression for this bounds fact, expanded to a
7206+
// range bounds expression.
7207+
void setNormalizedBounds(BoundsExpr *E) const {
7208+
const_cast<BoundsDeclFact *>(this)->setNormalizedBounds(E);
7209+
}
7210+
7211+
// \brief Set the bounds expression for this bounds fact, expanded to a
7212+
// range bounds expression.
7213+
void setNormalizedBounds(BoundsExpr *E) {
7214+
NormalizedBounds = E;
7215+
}
71707216
};
71717217

71727218
/// \brief Represents a Checked C relational operator fact.

clang/include/clang/Sema/BoundsUtils.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ class BoundsUtil {
5353

5454
// Given a byte_count or count bounds expression for the VarDecl D,
5555
// ExpandBoundsToRange will expand it to a range bounds expression.
56+
//
57+
// ExpandBoundsToRange creates a DeclRefExpr for D. Clients should not
58+
// call ExpandBoundsToRange directly. Instead, clients should call
59+
// Sema::NormalizeBounds, which computes the expanded bounds for D once
60+
// and attaches the expanded bounds to D.
5661
static BoundsExpr *ExpandBoundsToRange(Sema &S, VarDecl *D, BoundsExpr *B);
5762

5863
// Given a byte_count or count bounds expression for the expression Base,
@@ -62,10 +67,6 @@ class BoundsUtil {
6267
// (array_ptr<char>) E + C)
6368
static BoundsExpr *ExpandToRange(Sema &S, Expr *Base, BoundsExpr *B);
6469

65-
// ExpandToRange expands the bounds expression for a variable declaration
66-
// to a range bounds expression.
67-
static BoundsExpr *ExpandToRange(Sema &S, VarDecl *D, BoundsExpr *B);
68-
6970
// If Bounds uses the value of LValue and an original value is provided,
7071
// ReplaceLValueInBounds will return a bounds expression where the uses
7172
// of LValue are replaced with the original value.
@@ -82,6 +83,11 @@ class BoundsUtil {
8283
static Expr *ReplaceLValue(Sema &S, Expr *E, Expr *LValue,
8384
Expr *OriginalValue,
8485
CheckedScopeSpecifier CSS);
86+
87+
private:
88+
// ExpandToRange expands the bounds expression for a variable declaration
89+
// to a range bounds expression.
90+
static BoundsExpr *ExpandToRange(Sema &S, VarDecl *D, BoundsExpr *B);
8591
};
8692

8793
} // end namespace clang

clang/include/clang/Sema/Sema.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5732,6 +5732,12 @@ class Sema final {
57325732
// normalized bounds for D.
57335733
BoundsExpr *NormalizeBounds(const VarDecl *D);
57345734

5735+
// If the BoundsDeclFact F has a byte_count or count bounds expression,
5736+
// NormalizeBounds expands it to a range bounds expression. The expanded
5737+
// range bounds are attached to the BoundsDeclFact F to avoid recomputing
5738+
// the normalized bounds for F.
5739+
BoundsExpr *NormalizeBounds(const BoundsDeclFact *F);
5740+
57355741
// Returns the declared bounds for the lvalue expression E. Assignments
57365742
// to E must satisfy these bounds. After checking a top-level statement,
57375743
// the inferred bounds of E must imply these declared bounds.

clang/lib/Sema/CheckedCAnalysesPrepass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,8 @@ class PrepassHelper : public RecursiveASTVisitor<PrepassHelper> {
216216

217217
for (WhereClauseFact *Fact : WC->getFacts()) {
218218
if (BoundsDeclFact *BDF = dyn_cast<BoundsDeclFact>(Fact)) {
219-
VarDecl *V = BDF->Var;
220-
BoundsExpr *B = BDF->Bounds;
219+
VarDecl *V = BDF->getVarDecl();
220+
BoundsExpr *B = BDF->getBoundsExpr();
221221

222222
VarDecl *OrigVarWithBounds = VarWithBounds;
223223
VarWithBounds = V;

clang/lib/Sema/SemaBounds.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3941,8 +3941,7 @@ namespace {
39413941
<< Init->getSourceRange();
39423942
InitBounds = S.CreateInvalidBoundsExpr();
39433943
} else if (CheckBounds) {
3944-
BoundsExpr *NormalizedDeclaredBounds =
3945-
BoundsUtil::ExpandToRange(S, D, DeclaredBounds);
3944+
BoundsExpr *NormalizedDeclaredBounds = S.NormalizeBounds(D);
39463945
CheckBoundsDeclAtInitializer(D->getLocation(), D, NormalizedDeclaredBounds,
39473946
Init, InitBounds, State.EquivExprs, CSS);
39483947
}
@@ -6386,6 +6385,34 @@ BoundsExpr *Sema::NormalizeBounds(const VarDecl *D) {
63866385
return ExpandedBounds;
63876386
}
63886387

6388+
// If the BoundsDeclFact F has a byte_count or count bounds expression,
6389+
// NormalizeBounds expands it to a range bounds expression. The expanded
6390+
// range bounds are attached to the BoundsDeclFact F to avoid recomputing
6391+
// the normalized bounds for F.
6392+
BoundsExpr *Sema::NormalizeBounds(const BoundsDeclFact *F) {
6393+
// Do not attempt to normalize bounds for bounds facts that are
6394+
// associated with invalid declarations.
6395+
const VarDecl *D = F->getVarDecl();
6396+
if (D->isInvalidDecl())
6397+
return nullptr;
6398+
6399+
// If F already has a normalized bounds expression, do not recompute it.
6400+
if (BoundsExpr *NormalizedBounds = F->getNormalizedBounds())
6401+
return NormalizedBounds;
6402+
6403+
// Expand the bounds expression of F to a RangeBoundsExpr if possible.
6404+
const BoundsExpr *B = F->getBoundsExpr();
6405+
BoundsExpr *ExpandedBounds = BoundsUtil::ExpandBoundsToRange(*this,
6406+
const_cast<VarDecl *>(D),
6407+
const_cast<BoundsExpr *>(B));
6408+
if (!ExpandedBounds)
6409+
return nullptr;
6410+
6411+
// Attach the normalized bounds to F to avoid recomputing them.
6412+
F->setNormalizedBounds(ExpandedBounds);
6413+
return ExpandedBounds;
6414+
}
6415+
63896416
// Returns the declared bounds for the lvalue expression E. Assignments
63906417
// to E must satisfy these bounds. After checking a top-level statement,
63916418
// the inferred bounds of E must imply these declared bounds.

clang/lib/Sema/SemaStmt.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4533,7 +4533,9 @@ BoundsDeclFact
45334533
return nullptr;
45344534
}
45354535

4536-
return new (Context) BoundsDeclFact(VD, Bounds, IdLoc);
4536+
BoundsDeclFact *F = new (Context) BoundsDeclFact(VD, Bounds, IdLoc);
4537+
NormalizeBounds(F);
4538+
return F;
45374539
}
45384540

45394541
EqualityOpFact *Sema::ActOnEqualityOpFact(Expr *E, SourceLocation ExprLoc) {

0 commit comments

Comments
 (0)