Skip to content

Commit

Permalink
Added an assertion to constant evaluation enty points that prohibits …
Browse files Browse the repository at this point in the history
…dependent expressions

Summary:
Constant evaluator does not work on value-dependent or type-dependent
expressions.

Also fixed bugs uncovered by these assertions.

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D61522

llvm-svn: 361050
  • Loading branch information
gribozavr authored and MrSidims committed May 24, 2019
1 parent bc4f6cb commit 807762c
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 4 deletions.
3 changes: 3 additions & 0 deletions clang/lib/AST/Expr.cpp
Expand Up @@ -2974,6 +2974,9 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {

bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
const Expr **Culprit) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

// This function is attempting whether an expression is an initializer
// which can be evaluated at compile-time. It very closely parallels
// ConstExprEmitter in CGExprConstant.cpp; if they don't match, it
Expand Down
50 changes: 50 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Expand Up @@ -11642,32 +11642,43 @@ static bool EvaluateAsFixedPoint(const Expr *E, Expr::EvalResult &ExprResult,
/// will be applied to the result.
bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = InConstantContext;
return ::EvaluateAsRValue(this, Result, Ctx, Info);
}

bool Expr::EvaluateAsBooleanCondition(bool &Result,
const ASTContext &Ctx) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
EvalResult Scratch;
return EvaluateAsRValue(Scratch, Ctx) &&
HandleConversionToBool(Scratch.Val, Result);
}

bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx,
SideEffectsKind AllowSideEffects) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info);
}

bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx,
SideEffectsKind AllowSideEffects) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
return ::EvaluateAsFixedPoint(this, Result, Ctx, AllowSideEffects, Info);
}

bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
SideEffectsKind AllowSideEffects) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

if (!getType()->isRealFloatingType())
return false;

Expand All @@ -11681,6 +11692,9 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
}

bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);

LValue LV;
Expand All @@ -11696,6 +11710,9 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {

bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage,
const ASTContext &Ctx) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
EvalInfo Info(Ctx, Result, EM);
Info.InConstantContext = true;
Expand All @@ -11710,6 +11727,9 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage,
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
const VarDecl *VD,
SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

// FIXME: Evaluating initializers for large array and record types can cause
// performance problems. Only do so in C++11 for now.
if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
Expand Down Expand Up @@ -11752,13 +11772,19 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
/// constant folded, but discard the result.
bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

EvalResult Result;
return EvaluateAsRValue(Result, Ctx, /* in constant context */ true) &&
!hasUnacceptableSideEffect(Result, SEK);
}

APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
SmallVectorImpl<PartialDiagnosticAt> *Diag) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

EvalResult EVResult;
EVResult.Diag = Diag;
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
Expand All @@ -11774,6 +11800,9 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,

APSInt Expr::EvaluateKnownConstIntCheckOverflow(
const ASTContext &Ctx, SmallVectorImpl<PartialDiagnosticAt> *Diag) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

EvalResult EVResult;
EVResult.Diag = Diag;
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_EvaluateForOverflow);
Expand All @@ -11788,6 +11817,9 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow(
}

void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

bool IsConst;
EvalResult EVResult;
if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) {
Expand Down Expand Up @@ -12269,6 +12301,9 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,

bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
SourceLocation *Loc) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc);

Expand All @@ -12282,6 +12317,9 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,

bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx,
SourceLocation *Loc, bool isEvaluated) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc);

Expand All @@ -12305,11 +12343,17 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx,
}

bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

return CheckICE(this, Ctx).Kind == IK_ICE;
}

bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
SourceLocation *Loc) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

// We support this checking in C++98 mode in order to diagnose compatibility
// issues.
assert(Ctx.getLangOpts().CPlusPlus);
Expand Down Expand Up @@ -12338,6 +12382,9 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
const FunctionDecl *Callee,
ArrayRef<const Expr*> Args,
const Expr *This) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated);
Info.InConstantContext = true;
Expand Down Expand Up @@ -12419,6 +12466,9 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
const FunctionDecl *FD,
SmallVectorImpl<
PartialDiagnosticAt> &Diags) {
assert(!E->isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");

Expr::EvalStatus Status;
Status.Diag = &Diags;

Expand Down
14 changes: 12 additions & 2 deletions clang/lib/Sema/SemaOpenMP.cpp
Expand Up @@ -5894,14 +5894,21 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
if (CollapseLoopCountExpr) {
// Found 'collapse' clause - calculate collapse number.
Expr::EvalResult Result;
if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
if (!CollapseLoopCountExpr->isValueDependent() &&
CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) {
NestedLoopCount = Result.Val.getInt().getLimitedValue();
} else {
Built.clear(/*size=*/1);
return 1;
}
}
unsigned OrderedLoopCount = 1;
if (OrderedLoopCountExpr) {
// Found 'ordered' clause - calculate collapse number.
Expr::EvalResult EVResult;
if (OrderedLoopCountExpr->EvaluateAsInt(EVResult, SemaRef.getASTContext())) {
if (!OrderedLoopCountExpr->isValueDependent() &&
OrderedLoopCountExpr->EvaluateAsInt(EVResult,
SemaRef.getASTContext())) {
llvm::APSInt Result = EVResult.Val.getInt();
if (Result.getLimitedValue() < NestedLoopCount) {
SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(),
Expand All @@ -5912,6 +5919,9 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
<< CollapseLoopCountExpr->getSourceRange();
}
OrderedLoopCount = Result.getLimitedValue();
} else {
Built.clear(/*size=*/1);
return 1;
}
}
// This is helper routine for loop directives (e.g., 'for', 'simd',
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Sema/SemaOverload.cpp
Expand Up @@ -6376,7 +6376,8 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
APValue Result;
// FIXME: This doesn't consider value-dependent cases, because doing so is
// very difficult. Ideally, we should handle them more gracefully.
if (!EIA->getCond()->EvaluateWithSubstitution(
if (EIA->getCond()->isValueDependent() ||
!EIA->getCond()->EvaluateWithSubstitution(
Result, Context, Function, llvm::makeArrayRef(ConvertedArgs)))
return EIA;

Expand Down Expand Up @@ -9562,7 +9563,8 @@ static bool isFunctionAlwaysEnabled(const ASTContext &Ctx,
const FunctionDecl *FD) {
for (auto *EnableIf : FD->specific_attrs<EnableIfAttr>()) {
bool AlwaysTrue;
if (!EnableIf->getCond()->EvaluateAsBooleanCondition(AlwaysTrue, Ctx))
if (EnableIf->getCond()->isValueDependent() ||
!EnableIf->getCond()->EvaluateAsBooleanCondition(AlwaysTrue, Ctx))
return false;
if (!AlwaysTrue)
return false;
Expand Down

0 comments on commit 807762c

Please sign in to comment.