r373160 - Fix checking for permitted results of constant expressions.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 28 22:58:31 PDT 2019
Author: rsmith
Date: Sat Sep 28 22:58:31 2019
New Revision: 373160
URL: http://llvm.org/viewvc/llvm-project?rev=373160&view=rev
Log:
Fix checking for permitted results of constant expressions.
In the presence of mutable state, we need to check whether temporaries
involved in a constant expression have permissible values at the end of
the overall evaluation, rather than at the end of the evaluation of the
initializer of the temporary.
Modified:
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=373160&r1=373159&r2=373160&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sat Sep 28 22:58:31 2019
@@ -1912,12 +1912,30 @@ static void NoteLValueLocation(EvalInfo
// We have no information to show for a typeid(T) object.
}
+enum class CheckEvaluationResultKind {
+ ConstantExpression,
+ FullyInitialized,
+};
+
+/// Materialized temporaries that we've already checked to determine if they're
+/// initializsed by a constant expression.
+using CheckedTemporaries =
+ llvm::SmallPtrSet<const MaterializeTemporaryExpr *, 8>;
+
+static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
+ EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value,
+ Expr::ConstExprUsage Usage,
+ SourceLocation SubobjectLoc,
+ CheckedTemporaries &CheckedTemps);
+
/// Check that this reference or pointer core constant expression is a valid
/// value for an address or reference constant expression. Return true if we
/// can fold this expression, whether or not it's a constant expression.
static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
QualType Type, const LValue &LVal,
- Expr::ConstExprUsage Usage) {
+ Expr::ConstExprUsage Usage,
+ CheckedTemporaries &CheckedTemps) {
bool IsReferenceType = Type->isReferenceType();
APValue::LValueBase Base = LVal.getLValueBase();
@@ -1978,6 +1996,16 @@ static bool CheckLValueConstantExpressio
// FIXME: Diagnostic!
return false;
}
+ } else if (const auto *MTE = dyn_cast_or_null<MaterializeTemporaryExpr>(
+ Base.dyn_cast<const Expr *>())) {
+ if (CheckedTemps.insert(MTE).second) {
+ APValue *V = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
+ assert(V && "evasluation result refers to uninitialised temporary");
+ if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
+ Info, MTE->getExprLoc(), getType(Base), *V,
+ Usage, SourceLocation(), CheckedTemps))
+ return false;
+ }
}
// Allow address constant expressions to be past-the-end pointers. This is
@@ -2050,16 +2078,12 @@ static bool CheckLiteralType(EvalInfo &I
return false;
}
-enum class CheckEvaluationResultKind {
- ConstantExpression,
- FullyInitialized,
-};
-
-static bool
-CheckEvaluationResult(CheckEvaluationResultKind CERK, EvalInfo &Info,
- SourceLocation DiagLoc, QualType Type,
- const APValue &Value, Expr::ConstExprUsage Usage,
- SourceLocation SubobjectLoc = SourceLocation()) {
+static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
+ EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value,
+ Expr::ConstExprUsage Usage,
+ SourceLocation SubobjectLoc,
+ CheckedTemporaries &CheckedTemps) {
if (!Value.hasValue()) {
Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
<< true << Type;
@@ -2081,18 +2105,20 @@ CheckEvaluationResult(CheckEvaluationRes
for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
if (!CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
Value.getArrayInitializedElt(I), Usage,
- SubobjectLoc))
+ SubobjectLoc, CheckedTemps))
return false;
}
if (!Value.hasArrayFiller())
return true;
return CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
- Value.getArrayFiller(), Usage, SubobjectLoc);
+ Value.getArrayFiller(), Usage, SubobjectLoc,
+ CheckedTemps);
}
if (Value.isUnion() && Value.getUnionField()) {
return CheckEvaluationResult(
CERK, Info, DiagLoc, Value.getUnionField()->getType(),
- Value.getUnionValue(), Usage, Value.getUnionField()->getLocation());
+ Value.getUnionValue(), Usage, Value.getUnionField()->getLocation(),
+ CheckedTemps);
}
if (Value.isStruct()) {
RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
@@ -2101,7 +2127,7 @@ CheckEvaluationResult(CheckEvaluationRes
for (const CXXBaseSpecifier &BS : CD->bases()) {
if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(),
Value.getStructBase(BaseIndex), Usage,
- BS.getBeginLoc()))
+ BS.getBeginLoc(), CheckedTemps))
return false;
++BaseIndex;
}
@@ -2112,7 +2138,7 @@ CheckEvaluationResult(CheckEvaluationRes
if (!CheckEvaluationResult(CERK, Info, DiagLoc, I->getType(),
Value.getStructField(I->getFieldIndex()),
- Usage, I->getLocation()))
+ Usage, I->getLocation(), CheckedTemps))
return false;
}
}
@@ -2121,7 +2147,8 @@ CheckEvaluationResult(CheckEvaluationRes
CERK == CheckEvaluationResultKind::ConstantExpression) {
LValue LVal;
LVal.setFrom(Info.Ctx, Value);
- return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage);
+ return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage,
+ CheckedTemps);
}
if (Value.isMemberPointer() &&
@@ -2139,17 +2166,20 @@ static bool
CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
const APValue &Value,
Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) {
+ CheckedTemporaries CheckedTemps;
return CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
- Info, DiagLoc, Type, Value, Usage);
+ Info, DiagLoc, Type, Value, Usage,
+ SourceLocation(), CheckedTemps);
}
/// Check that this evaluated value is fully-initialized and can be loaded by
/// an lvalue-to-rvalue conversion.
static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value) {
- return CheckEvaluationResult(CheckEvaluationResultKind::FullyInitialized,
- Info, DiagLoc, Type, Value,
- Expr::EvaluateForCodeGen);
+ CheckedTemporaries CheckedTemps;
+ return CheckEvaluationResult(
+ CheckEvaluationResultKind::FullyInitialized, Info, DiagLoc, Type, Value,
+ Expr::EvaluateForCodeGen, SourceLocation(), CheckedTemps);
}
/// Enforce C++2a [expr.const]/4.17, which disallows new-expressions unless
@@ -7189,9 +7219,7 @@ bool LValueExprEvaluator::VisitMateriali
QualType Type = Inner->getType();
// Materialize the temporary itself.
- if (!EvaluateInPlace(*Value, Info, Result, Inner) ||
- (E->getStorageDuration() == SD_Static &&
- !CheckConstantExpression(Info, E->getExprLoc(), Type, *Value))) {
+ if (!EvaluateInPlace(*Value, Info, Result, Inner)) {
*Value = APValue();
return false;
}
@@ -13218,11 +13246,12 @@ bool Expr::EvaluateAsLValue(EvalResult &
EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
Info.InConstantContext = InConstantContext;
LValue LV;
+ CheckedTemporaries CheckedTemps;
if (!EvaluateLValue(this, LV, Info) || !Info.discardCleanups() ||
Result.HasSideEffects ||
!CheckLValueConstantExpression(Info, getExprLoc(),
Ctx.getLValueReferenceType(getType()), LV,
- Expr::EvaluateForCodeGen))
+ Expr::EvaluateForCodeGen, CheckedTemps))
return false;
LV.moveInto(Result.Val);
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=373160&r1=373159&r2=373160&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Sat Sep 28 22:58:31 2019
@@ -1223,3 +1223,22 @@ namespace PR39728 {
~Comment1() = default;
};
}
+
+namespace TemporaryWithBadPointer {
+ constexpr int *get_bad_pointer() {
+ int n = 0; // expected-note 2{{here}}
+ return &n; // expected-warning {{stack}}
+ }
+ constexpr int *bad_pointer = get_bad_pointer(); // expected-error {{constant expression}} expected-note {{pointer to 'n' is not a constant expression}}
+
+ struct DoBadThings { int *&℘ int n; };
+ constexpr DoBadThings dbt = { // expected-error {{constant expression}}
+ nullptr, // expected-note {{pointer to 'n' is not a constant expression}}
+ (dbt.wp = get_bad_pointer(), 0)
+ };
+
+ constexpr DoBadThings dbt2 = { // ok
+ get_bad_pointer(),
+ (dbt2.wp = nullptr, 0)
+ };
+}
More information about the cfe-commits
mailing list