summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/ExprConstant.cpp79
-rw-r--r--clang/test/SemaCXX/constant-expression-cxx1y.cpp19
2 files changed, 73 insertions, 25 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 33608db6e42..b0c0c2e8d98 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1912,12 +1912,30 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
// 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 CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// 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 &Info, const Expr *E,
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(CheckEvaluationResultKind CERK, EvalInfo &Info,
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(CheckEvaluationResultKind CERK, EvalInfo &Info,
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(CheckEvaluationResultKind CERK, EvalInfo &Info,
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(CheckEvaluationResultKind CERK, EvalInfo &Info,
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::VisitMaterializeTemporaryExpr(
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 &Result, const ASTContext &Ctx,
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);
diff --git a/clang/test/SemaCXX/constant-expression-cxx1y.cpp b/clang/test/SemaCXX/constant-expression-cxx1y.cpp
index 1d4549b6182..2a8304ebda6 100644
--- a/clang/test/SemaCXX/constant-expression-cxx1y.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx1y.cpp
@@ -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 *&&wp; 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)
+ };
+}
OpenPOWER on IntegriCloud