Skip to content

Replace current_expr_value with expression temporaries. #561

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

Merged
merged 21 commits into from
Sep 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e428eda
Add AST support for _Current_expr_value and _Return_value.
dtarditi Aug 5, 2018
cfddb97
Add keywors for _Current_expr_value and _Return_value.
dtarditi Aug 6, 2018
f48f470
Delay parse return bounds expressions.
dtarditi Aug 9, 2018
413c68b
Add delay parsing of return bounds.
dtarditi Aug 10, 2018
385ebde
Cleanup code.
dtarditi Aug 10, 2018
8762f7d
Add AST dumpiing tests and bound decl checking tests.
dtarditi Aug 10, 2018
2b550e2
Fix expected test output.
dtarditi Aug 10, 2018
95a9714
Commit TreeTransform.h before merging
dtarditi Aug 11, 2018
5a6d641
Merge branch 'issue205' of https://github.com/Microsoft/checkedc-clan…
dtarditi Aug 11, 2018
5d6e4e2
Semantic/codegen support for _Current_expr_value.
dtarditi Aug 13, 2018
966461c
Code generation for current_expr_value, including some testing.
dtarditi Aug 19, 2018
14468a8
Checkpoint work on replacing current_expr_value with expression tempo…
dtarditi Aug 28, 2018
0048cd6
Merge branch 'master' into issue205-part2
dtarditi Aug 28, 2018
46b089b
Passing some testing now.
dtarditi Aug 29, 2018
9906dde
Fix errors related to returning a CHKCBindTemporaryExprClass.
dtarditi Sep 4, 2018
2376a22
All but one clang test passes.
dtarditi Sep 5, 2018
1b80555
Remove unnecessary changes.
dtarditi Sep 5, 2018
1dd5ea3
Code clean up.
dtarditi Sep 5, 2018
97d1520
More code cleanup.
dtarditi Sep 5, 2018
ee41ef7
More code clean up.
dtarditi Sep 5, 2018
4e28a25
Fix LLVM IR test that fails on x64 targets.
dtarditi Sep 7, 2018
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
9 changes: 9 additions & 0 deletions include/clang/AST/CanonBounds.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
// This file defines the interface for comparing and canonicalizing
// bounds expressions.
//
// Bounds expressions must be non-modifying expressions, so these
// comparison methods should only be called on non-modifying expressions.
// In addition, sets of equivalent expressions should also only involve
// non-modifying expressions.
//
// TODO: check the invariant about expressions being non-modifying.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_CANON_BOUNDS_H
Expand Down Expand Up @@ -99,6 +106,8 @@ namespace clang {
Result CompareImpl(const PositionalParameterExpr *E1,
const PositionalParameterExpr *E2);
Result CompareImpl(const BoundsCastExpr *E1, const BoundsCastExpr *E2);
Result CompareImpl(const CHKCBindTemporaryExpr *E1,
const CHKCBindTemporaryExpr *E2);
Result CompareImpl(const BoundsValueExpr *E1, const BoundsValueExpr *E2);
Result CompareImpl(const AtomicExpr *E1, const AtomicExpr *E2);
Result CompareImpl(const BlockExpr *E1, const BlockExpr *E2);
Expand Down
72 changes: 68 additions & 4 deletions include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,14 @@ class Expr : public Stmt {
return const_cast<Expr*>(this)->ignoreParenBaseCasts();
}

/// Ignore Checked C expression temporaries (CHCKBindTemporaryExpr).
Expr *IgnoreExprTmp() LLVM_READONLY;

const Expr *IgnoreExprTmp() const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreExprTmp();
}


/// \brief Determine whether this expression is a default function argument.
///
/// Default arguments are implicitly generated in the abstract syntax tree
Expand Down Expand Up @@ -5441,29 +5449,85 @@ class PositionalParameterExpr : public Expr {
}
};

// \brief Represents the \c _Currrent_expr_value and _Return_value expressions
// in Checked C. These expressions can be used within bounds expressions.
/// \brief Represents binding the result of evaluating an expression
/// to an anonymous temporary. We use the binding node itself to
/// represent the temporary.
///
/// When a bounds expression is computed for an expression E, this
/// lets the bounds expression reference the value of a subexpression
/// of E.
class CHKCBindTemporaryExpr : public Expr {
Stmt *SubExpr;

public:
CHKCBindTemporaryExpr(Expr* SubExpr)
: Expr(CHKCBindTemporaryExprClass, SubExpr->getType(),
SubExpr->getValueKind(), SubExpr->getObjectKind(), SubExpr->isTypeDependent(),
SubExpr->isValueDependent(),
SubExpr->isInstantiationDependent(),
SubExpr->containsUnexpandedParameterPack()), SubExpr(SubExpr) { }

CHKCBindTemporaryExpr(EmptyShell Empty)
: Expr(CHKCBindTemporaryExprClass, Empty), SubExpr(nullptr) {}

const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
void setSubExpr(Expr *E) { SubExpr = E; }

SourceLocation getLocStart() const LLVM_READONLY {
return SubExpr->getLocStart();
}

SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd();}

// Implement isa/cast/dyncast/etc.
static bool classof(const Stmt *T) {
return T->getStmtClass() == CHKCBindTemporaryExprClass;
}

// Iterators
child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
};


/// \brief Represent uses of expression temporaries and _Return_value
/// expressions. These expressions can be used within bounds expressions.
///
/// Uses of expression temporaries cannot be written at the source level.
/// These are constructed by the compiler during bounds inference.
class BoundsValueExpr : public Expr {
public:
enum Kind {
Current,
Temporary,
Return
};

private:
CHKCBindTemporaryExpr *Temp; // Binding which represents a temporary.
SourceLocation Loc;
Kind ValueExprKind;

public:
BoundsValueExpr(SourceLocation L, QualType Type, Kind K)
: Expr(BoundsValueExprClass, Type, VK_RValue, OK_Ordinary,
false, false, false, false), Loc(L), ValueExprKind(K) { }
false, false, false, false), Temp(nullptr), Loc(L),
ValueExprKind(K) { }

// Create a use of an expression temporary.
BoundsValueExpr(SourceLocation L, CHKCBindTemporaryExpr *Temp)
: Expr(BoundsValueExprClass, Temp->getType(), Temp->getValueKind(), OK_Ordinary,
false, false, false, false), Temp(Temp), Loc(L),
ValueExprKind(Kind::Temporary) { }

BoundsValueExpr(EmptyShell Empty) : Expr(BoundsValueExprClass, Empty) {}

SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }

CHKCBindTemporaryExpr *getTemporaryBinding() { return Temp; }
const CHKCBindTemporaryExpr *getTemporaryBinding() const { return Temp; }
void setTemporaryBinding(CHKCBindTemporaryExpr *T) { Temp = T; }

SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }

Expand Down
1 change: 1 addition & 0 deletions include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2556,6 +2556,7 @@ DEF_TRAVERSE_STMT(RangeBoundsExpr, {})
DEF_TRAVERSE_STMT(InteropTypeExpr, {})
DEF_TRAVERSE_STMT(PositionalParameterExpr, {})
DEF_TRAVERSE_STMT(BoundsValueExpr, {})
DEF_TRAVERSE_STMT(CHKCBindTemporaryExpr, {})

// For coroutines expressions, traverse either the operand
// as written or the implied calls, depending on what the
Expand Down
1 change: 1 addition & 0 deletions include/clang/Basic/StmtNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ def RangeBoundsExpr : DStmt<BoundsExpr>;
def InteropTypeExpr : DStmt<Expr>;
def PositionalParameterExpr : DStmt<Expr>;
def BoundsCastExpr : DStmt<ExplicitCastExpr>;
def CHKCBindTemporaryExpr : DStmt<Expr>;
def BoundsValueExpr : DStmt<Expr>;

// CUDA Expressions.
Expand Down
3 changes: 3 additions & 0 deletions include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4730,6 +4730,9 @@ class Sema {
NMM_Note
};

/// \brief Checks whether an expression is non-modifying
/// (see Checked C Spec, 3.6.1). Returns true if the expression is non-modifying,
/// false otherwise.
bool CheckIsNonModifying(Expr *E, NonModifyingContext Req =
NonModifyingContext::NMC_Unknown,
NonModifyingMessage = NMM_Error);
Expand Down
4 changes: 3 additions & 1 deletion include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1495,7 +1495,9 @@ namespace clang {
EXPR_INTEROPTYPE_BOUNDS_ANNOTATION,// InteropTypeBoundsAnnotation
EXPR_POSITIONAL_PARAMETER_EXPR, // PositionalParameterExpr
EXPR_BOUNDS_CAST,
EXPR_BOUNDS_VALUE_EXPR, // BoundsValueExpr
EXPR_BOUNDS_VALUE_EXPR, // BoundsValueExpr
EXPR_CHKC_BIND_TEMPORARY_EXPR, // CHKCBindTemporaryExpr

// OpenCL
EXPR_ASTYPE, // AsTypeExpr

Expand Down
6 changes: 6 additions & 0 deletions include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,12 @@ class ExprEngine : public SubEngine {
void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);

/// VisitCHKCBindTemporaryExpr - Transfer function logic for binding an
/// expression to a temporary
void VisitCHKCBindTemporaryExpr(const CHKCBindTemporaryExpr *Binding,
const Expr *SE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);

/// Create a C++ temporary object for an rvalue.
void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
Expand Down
8 changes: 6 additions & 2 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2847,8 +2847,12 @@ void ASTDumper::VisitPositionalParameterExpr(

void ASTDumper::VisitBoundsValueExpr(const BoundsValueExpr *Node) {
VisitExpr(Node);
OS << (Node->getKind() == BoundsValueExpr::Kind::Current ?
" _Current_expr_value" : " _Return_value");
if (Node->getKind() == BoundsValueExpr::Kind::Temporary) {
OS << " _BoundTemporary ";
dumpPointer(Node->getTemporaryBinding());
}
else
OS << " _Return_value";
}

//===----------------------------------------------------------------------===//
Expand Down
44 changes: 41 additions & 3 deletions lib/AST/CanonBounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,22 @@ Result Lexicographic::CompareExpr(const Expr *Arg1, const Expr *Arg2) {
if (E1 == E2)
return Result::Equal;

// Commpare expressions structurally, recursively invoking
// The use of an expression temporary is equal to the
// value of the binding expression.
if (BoundsValueExpr *BV1 = dyn_cast<BoundsValueExpr>(E1))
if (BV1->getTemporaryBinding() == E2)
return Result::Equal;

if (BoundsValueExpr *BV2 = dyn_cast<BoundsValueExpr>(E2))
if (BV2->getTemporaryBinding() == E1)
return Result::Equal;

// Compare expressions structurally, recursively invoking
// comparison for subcomponents. If that fails, consult
// EquivExprs to see if the expressions are considered
// equivalent.
// - Treat different kinds of casts (implicit/explicit) as
// equivalent if the operation kinds are the same.
Stmt::StmtClass E1Kind = E1->getStmtClass();
Stmt::StmtClass E2Kind = E2->getStmtClass();
Result Cmp = CompareInteger(E1Kind, E2Kind);
Expand Down Expand Up @@ -383,6 +395,9 @@ Result Lexicographic::CompareExpr(const Expr *Arg1, const Expr *Arg2) {
case Expr::PositionalParameterExprClass: Cmp = Compare<PositionalParameterExpr>(E1, E2); break;
case Expr::BoundsCastExprClass: Cmp = Compare<BoundsCastExpr>(E1, E2); break;
case Expr::BoundsValueExprClass: Cmp = Compare<BoundsValueExpr>(E1, E2); break;
// Binding of a tempoary to the result of an expression. These are
// equal if their child expressions are equal.
case Expr::CHKCBindTemporaryExprClass: break;

// Clang extensions
case Expr::ShuffleVectorExprClass: break;
Expand Down Expand Up @@ -745,15 +760,38 @@ Lexicographic::CompareImpl(const BoundsCastExpr *E1,
return CompareType(E1->getType(), E2->getType());
}

Result
Lexicographic::CompareImpl(const CHKCBindTemporaryExpr *E1,
const CHKCBindTemporaryExpr *E2) {
bool ordered;
Result Cmp = ComparePointers(E1, E2, ordered);
if (!ordered) {
// Order binding expressions by the source location of
// the source-level expression.
if (E1->getSubExpr()->getLocStart() <
E2->getSubExpr()->getLocStart())
Cmp = Result::LessThan;
else
Cmp = Result::GreaterThan;
}
return Cmp;
}

Result
Lexicographic::CompareImpl(const BoundsValueExpr *E1,
const BoundsValueExpr *E2) {
Result Cmp = CompareInteger(E1->getKind(), E2->getKind());
if (Cmp != Result::Equal)
return Cmp;
return CompareType(E1->getType(), E2->getType());
}

// The type doesn't matter - the value is the same no matter what the type.

// If these are uses of an expression temporary, check that the binding
// expression is the same.
if (E1->getKind() == BoundsValueExpr::Kind::Temporary)
Cmp = CompareImpl(E1->getTemporaryBinding(), E2->getTemporaryBinding());
return Cmp;
}

Result
Lexicographic::CompareImpl(const BlockExpr *E1, const BlockExpr *E2) {
Expand Down
Loading