aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Decl.h6
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td18
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td1
-rw-r--r--lib/AST/ExprConstant.cpp292
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp355
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp6
-rw-r--r--test/SemaCXX/enum-bitfield.cpp4
8 files changed, 587 insertions, 96 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index c8120eb361..92a6a5469c 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -3162,6 +3162,12 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
DiagnosticsEngine::ak_nameddecl);
return DB;
}
+inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ const NamedDecl* ND) {
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(ND),
+ DiagnosticsEngine::ak_nameddecl);
+ return PD;
+}
template<typename decl_type>
void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 4f7169dade..e9b3147521 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -15,6 +15,24 @@ def note_expr_divide_by_zero : Note<"division by zero">;
def note_constexpr_invalid_cast : Note<
"%select{reinterpret_cast|dynamic_cast|cast which performs the conversions of"
" a reinterpret_cast|cast from %1}0 is not allowed in a constant expression">;
+def note_constexpr_overflow : Note<
+ "value %0 is outside the range of representable values of type %1">;
+def note_constexpr_invalid_function : Note<
+ "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot "
+ "be used in a constant expression">;
+def note_constexpr_nonliteral : Note<
+ "non-literal type %0 cannot be used in a constant expression">;
+def note_constexpr_non_global : Note<
+ "%select{pointer|reference}0 to %select{|subobject of }1"
+ "%select{temporary|%4}2 %select{is not a constant expression|"
+ "cannot be returned from a constexpr function|"
+ "cannot be used to initialize a member in a constant expression}3">;
+def note_constexpr_past_end : Note<
+ "dereferenced pointer past the end of %select{|subobject of}0 "
+ "%select{temporary|%2}1 is not a constant expression">;
+def note_constexpr_temporary_here : Note<"temporary created here">;
+def note_constexpr_depth_limit_exceeded : Note<
+ "constexpr evaluation exceeded maximum depth of %0 calls">;
// inline asm related.
let CategoryName = "Inline Assembly Issue" in {
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index b02edab1f3..077b24fd1d 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -18,6 +18,7 @@ let Component = "Common" in {
def fatal_too_many_errors
: Error<"too many errors emitted, stopping now">, DefaultFatal;
+def note_declared_at : Note<"declared here">;
def note_previous_definition : Note<"previous definition is here">;
def note_previous_declaration : Note<"previous declaration is here">;
def note_previous_implicit_declaration : Note<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 7c7b920119..56d5348275 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -485,7 +485,6 @@ def warn_strict_multiple_method_decl : Warning<
"multiple methods named %0 found">, InGroup<StrictSelector>, DefaultIgnore;
def warn_accessor_property_type_mismatch : Warning<
"type of property %0 does not match type of accessor %1">;
-def note_declared_at : Note<"declared here">;
def note_method_declared_at : Note<"method declared here">;
def err_setter_type_void : Error<"type of setter must be void">;
def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 3a897ab348..dd1110ab11 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -293,11 +293,15 @@ namespace {
/// declaration whose initializer is being evaluated, if any.
APValue *EvaluatingDeclValue;
+ /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
+ /// notes attached to it will also be stored, otherwise they will not be.
+ bool HasActiveDiagnostic;
+
EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
: Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
CallStackDepth(0), BottomFrame(*this, 0, 0), EvaluatingDecl(0),
- EvaluatingDeclValue(0) {}
+ EvaluatingDeclValue(0), HasActiveDiagnostic(false) {}
const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const {
MapTy::const_iterator i = OpaqueValues.find(e);
@@ -312,33 +316,55 @@ namespace {
const LangOptions &getLangOpts() const { return Ctx.getLangOptions(); }
- bool atCallLimit() const {
- return CallStackDepth > getLangOpts().ConstexprCallDepth;
+ bool CheckCallLimit(SourceLocation Loc) {
+ if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
+ return true;
+ Diag(Loc, diag::note_constexpr_depth_limit_exceeded)
+ << getLangOpts().ConstexprCallDepth;
+ return false;
}
+ private:
+ /// Add a diagnostic to the diagnostics list.
+ PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) {
+ PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
+ EvalStatus.Diag->push_back(std::make_pair(Loc, PD));
+ return EvalStatus.Diag->back().second;
+ }
+
+ public:
/// Diagnose that the evaluation cannot be folded.
- OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId) {
+ OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes = 0) {
// If we have a prior diagnostic, it will be noting that the expression
// isn't a constant expression. This diagnostic is more important.
// FIXME: We might want to show both diagnostics to the user.
if (EvalStatus.Diag) {
+ HasActiveDiagnostic = true;
EvalStatus.Diag->clear();
- EvalStatus.Diag->reserve(1);
- PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator());
- EvalStatus.Diag->push_back(std::make_pair(Loc, PD));
+ EvalStatus.Diag->reserve(1 + ExtraNotes);
// FIXME: Add a call stack for constexpr evaluation.
- return OptionalDiagnostic(&EvalStatus.Diag->back().second);
+ return OptionalDiagnostic(&addDiag(Loc, DiagId));
}
+ HasActiveDiagnostic = false;
return OptionalDiagnostic();
}
/// Diagnose that the evaluation does not produce a C++11 core constant
/// expression.
- OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId) {
+ OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes = 0) {
// Don't override a previous diagnostic.
if (!EvalStatus.Diag || !EvalStatus.Diag->empty())
return OptionalDiagnostic();
- return Diag(Loc, DiagId);
+ return Diag(Loc, DiagId, ExtraNotes);
+ }
+
+ /// Add a note to a prior diagnostic.
+ OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId) {
+ if (!HasActiveDiagnostic)
+ return OptionalDiagnostic();
+ return OptionalDiagnostic(&addDiag(Loc, DiagId));
}
};
@@ -515,11 +541,20 @@ namespace {
return castBack(Base);
}
};
+
+ /// Kinds of constant expression checking, for diagnostics.
+ enum CheckConstantExpressionKind {
+ CCEK_Constant, ///< A normal constant.
+ CCEK_ReturnValue, ///< A constexpr function return value.
+ CCEK_MemberInit ///< A constexpr constructor mem-initializer.
+ };
}
static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E);
static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
- const LValue &This, const Expr *E);
+ const LValue &This, const Expr *E,
+ CheckConstantExpressionKind CCEK
+ = CCEK_Constant);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
@@ -586,22 +621,53 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
/// value for a constant expression. Type T should be either LValue or CCValue.
template<typename T>
static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
- const T &LVal, APValue &Value) {
- if (!IsGlobalLValue(LVal.getLValueBase())) {
- Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+ const T &LVal, APValue &Value,
+ CheckConstantExpressionKind CCEK) {
+ APValue::LValueBase Base = LVal.getLValueBase();
+ const SubobjectDesignator &Designator = LVal.getLValueDesignator();
+
+ if (!IsGlobalLValue(Base)) {
+ if (Info.getLangOpts().CPlusPlus0x) {
+ const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+ Info.Diag(E->getExprLoc(), diag::note_constexpr_non_global, 1)
+ << E->isGLValue() << !Designator.Entries.empty()
+ << !!VD << CCEK << VD;
+ if (VD)
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ else
+ Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
+ diag::note_constexpr_temporary_here);
+ } else {
+ Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+ }
return false;
}
- const SubobjectDesignator &Designator = LVal.getLValueDesignator();
// A constant expression must refer to an object or be a null pointer.
if (Designator.Invalid ||
(!LVal.getLValueBase() && !Designator.Entries.empty())) {
- // FIXME: This is not a constant expression.
+ // FIXME: This is not a core constant expression. We should have already
+ // produced a CCE diagnostic.
Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
APValue::NoLValuePath());
return true;
}
+ // Does this refer one past the end of some object?
+ // This is technically not an address constant expression nor a reference
+ // constant expression, but we allow it for address constant expressions.
+ if (E->isGLValue() && Base && Designator.OnePastTheEnd) {
+ const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+ Info.Diag(E->getExprLoc(), diag::note_constexpr_past_end, 1)
+ << !Designator.Entries.empty() << !!VD << VD;
+ if (VD)
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ else
+ Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
+ diag::note_constexpr_temporary_here);
+ return false;
+ }
+
Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
Designator.Entries, Designator.OnePastTheEnd);
return true;
@@ -611,12 +677,14 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
/// constant expression, and if it is, produce the corresponding constant value.
/// If not, report an appropriate diagnostic.
static bool CheckConstantExpression(EvalInfo &Info, const Expr *E,
- const CCValue &CCValue, APValue &Value) {
+ const CCValue &CCValue, APValue &Value,
+ CheckConstantExpressionKind CCEK
+ = CCEK_Constant) {
if (!CCValue.isLValue()) {
Value = CCValue;
return true;
}
- return CheckLValueConstantExpression(Info, E, CCValue, Value);
+ return CheckLValueConstantExpression(Info, E, CCValue, Value, CCEK);
}
const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
@@ -693,26 +761,41 @@ static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
return HandleConversionToBool(Val, Result);
}
-static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
- APFloat &Value, const ASTContext &Ctx) {
- unsigned DestWidth = Ctx.getIntWidth(DestType);
+template<typename T>
+static bool HandleOverflow(EvalInfo &Info, const Expr *E,
+ const T &SrcValue, QualType DestType) {
+ llvm::SmallVector<char, 32> Buffer;
+ SrcValue.toString(Buffer);
+ Info.Diag(E->getExprLoc(), diag::note_constexpr_overflow)
+ << StringRef(Buffer.data(), Buffer.size()) << DestType;
+ return false;
+}
+
+static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
+ QualType SrcType, const APFloat &Value,
+ QualType DestType, APSInt &Result) {
+ unsigned DestWidth = Info.Ctx.getIntWidth(DestType);
// Determine whether we are converting to unsigned or signed.
bool DestSigned = DestType->isSignedIntegerOrEnumerationType();
- // FIXME: Warning for overflow.
- APSInt Result(DestWidth, !DestSigned);
+ Result = APSInt(DestWidth, !DestSigned);
bool ignored;
- (void)Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored);
- return Result;
+ if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored)
+ & APFloat::opInvalidOp)
+ return HandleOverflow(Info, E, Value, DestType);
+ return true;
}
-static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType,
- APFloat &Value, const ASTContext &Ctx) {
+static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
+ QualType SrcType, QualType DestType,
+ APFloat &Result) {
+ APFloat Value = Result;
bool ignored;
- APFloat Result = Value;
- Result.convert(Ctx.getFloatTypeSemantics(DestType),
- APFloat::rmNearestTiesToEven, &ignored);
- return Result;
+ if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
+ APFloat::rmNearestTiesToEven, &ignored)
+ & APFloat::opOverflow)
+ return HandleOverflow(Info, E, Value, DestType);
+ return true;
}
static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
@@ -726,13 +809,15 @@ static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
return Result;
}
-static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
- APSInt &Value, const ASTContext &Ctx) {
-
- APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1);
- Result.convertFromAPInt(Value, Value.isSigned(),
- APFloat::rmNearestTiesToEven);
- return Result;
+static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
+ QualType SrcType, const APSInt &Value,
+ QualType DestType, APFloat &Result) {
+ Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
+ if (Result.convertFromAPInt(Value, Value.isSigned(),
+ APFloat::rmNearestTiesToEven)
+ & APFloat::opOverflow)
+ return HandleOverflow(Info, E, Value, DestType);
+ return true;
}
static bool FindMostDerivedObject(EvalInfo &Info, const LValue &LVal,
@@ -1311,7 +1396,7 @@ enum EvalStmtResult {
}
// Evaluate a statement.
-static EvalStmtResult EvaluateStmt(CCValue &Result, EvalInfo &Info,
+static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
const Stmt *S) {
switch (S->getStmtClass()) {
default:
@@ -1321,10 +1406,15 @@ static EvalStmtResult EvaluateStmt(CCValue &Result, EvalInfo &Info,
case Stmt::DeclStmtClass:
return ESR_Succeeded;
- case Stmt::ReturnStmtClass:
- if (Evaluate(Result, Info, cast<ReturnStmt>(S)->getRetValue()))
- return ESR_Returned;
- return ESR_Failed;
+ case Stmt::ReturnStmtClass: {
+ CCValue CCResult;
+ const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
+ if (!Evaluate(CCResult, Info, RetExpr) ||
+ !CheckConstantExpression(Info, RetExpr, CCResult, Result,
+ CCEK_ReturnValue))
+ return ESR_Failed;
+ return ESR_Returned;
+ }
case Stmt::CompoundStmtClass: {
const CompoundStmt *CS = cast<CompoundStmt>(S);
@@ -1339,6 +1429,27 @@ static EvalStmtResult EvaluateStmt(CCValue &Result, EvalInfo &Info,
}
}
+/// CheckConstexprFunction - Check that a function can be called in a constant
+/// expression.
+static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
+ const FunctionDecl *Declaration,
+ const FunctionDecl *Definition) {
+ // Can we evaluate this function call?
+ if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
+ return true;
+
+ if (Info.getLangOpts().CPlusPlus0x) {
+ const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
+ Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1)
+ << DiagDecl->isConstexpr() << isa<CXXConstructorDecl>(DiagDecl)
+ << DiagDecl;
+ Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
+ } else {
+ Info.Diag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
+ }
+ return false;
+}
+
namespace {
typedef SmallVector<CCValue, 8> ArgVector;
}
@@ -1356,12 +1467,9 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
/// Evaluate a function call.
static bool HandleFunctionCall(const Expr *CallExpr, const LValue *This,
ArrayRef<const Expr*> Args, const Stmt *Body,
- EvalInfo &Info, CCValue &Result) {
- if (Info.atCallLimit()) {
- // FIXME: Add a specific proper diagnostic for this.
- Info.Diag(CallExpr->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+ EvalInfo &Info, APValue &Result) {
+ if (!Info.CheckCallLimit(CallExpr->getExprLoc()))
return false;
- }
ArgVector ArgValues(Args.size());
if (!EvaluateArgs(Args, ArgValues, Info))
@@ -1377,11 +1485,8 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This,
const CXXConstructorDecl *Definition,
EvalInfo &Info,
APValue &Result) {
- if (Info.atCallLimit()) {
- // FIXME: Add a specific diagnostic for this.
- Info.Diag(CallExpr->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+ if (!Info.CheckCallLimit(CallExpr->getExprLoc()))
return false;
- }
ArgVector ArgValues(Args.size());
if (!EvaluateArgs(Args, ArgValues, Info))
@@ -1430,12 +1535,12 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This,
HandleLValueMember(Info, Subobject, FD, &Layout);
if (RD->isUnion()) {
Result = APValue(FD);
- if (!EvaluateConstantExpression(Result.getUnionValue(), Info,
- Subobject, (*I)->getInit()))
+ if (!EvaluateConstantExpression(Result.getUnionValue(), Info, Subobject,
+ (*I)->getInit(), CCEK_MemberInit))
return false;
} else if (!EvaluateConstantExpression(
Result.getStructField(FD->getFieldIndex()),
- Info, Subobject, (*I)->getInit()))
+ Info, Subobject, (*I)->getInit(), CCEK_MemberInit))
return false;
} else {
// FIXME: handle indirect field initializers
@@ -1745,16 +1850,12 @@ public:
} else
return Error(E);
- const FunctionDecl *Definition;
+ const FunctionDecl *Definition = 0;
Stmt *Body = FD->getBody(Definition);
- CCValue CCResult;
APValue Result;
- if (!Body || !Definition->isConstexpr() || Definition->isInvalidDecl())
- return Error(E);
-
- if (!HandleFunctionCall(E, This, Args, Body, Info, CCResult) ||
- !CheckConstantExpression(Info, E, CCResult, Result))
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) ||
+ !HandleFunctionCall(E, This, Args, Body, Info, Result))
return false;
return DerivedSuccess(CCValue(Result, CCValue::GlobalValue()), E);
@@ -1878,6 +1979,10 @@ public:
if (!EvaluatePointer(E->getBase(), Result, this->Info))
return false;
BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
+ } else if (E->getBase()->isRValue()) {
+ if (!EvaluateTemporary(E->getBase(), Result, this->Info))
+ return false;
+ BaseTy = E->getBase()->getType();
} else {
if (!this->Visit(E->getBase()))
return false;
@@ -2516,8 +2621,8 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
const FunctionDecl *Definition = 0;
FD->getBody(Definition);
- if (!Definition || !Definition->isConstexpr() || Definition->isInvalidDecl())
- return Error(E);
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
+ return false;
// FIXME: Elide the copy/move construction wherever we can.
if (E->isElidable())
@@ -2837,8 +2942,8 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
const FunctionDecl *Definition = 0;
FD->getBody(Definition);
- if (!Definition || !Definition->isConstexpr() || Definition->isInvalidDecl())
- return Error(E);
+ if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
+ return false;
// FIXME: The Subobject here isn't necessarily right. This rarely matters,
// but sometimes does:
@@ -3881,7 +3986,10 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!EvaluateFloat(SubExpr, F, Info))
return false;
- return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E);
+ APSInt Value;
+ if (!HandleFloatToIntCast(Info, E, SrcType, F, DestType, Value))
+ return false;
+ return Success(Value, E);
}
}
@@ -4130,19 +4238,16 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralToFloating: {
APSInt IntResult;
- if (!EvaluateInteger(SubExpr, IntResult, Info))
- return false;
- Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(),
- IntResult, Info.Ctx);
- return true;
+ return EvaluateInteger(SubExpr, IntResult, Info) &&
+ HandleIntToFloatCast(Info, E, SubExpr->getType(), IntResult,
+ E->getType(), Result);
}
case CK_FloatingCast: {
if (!Visit(SubExpr))
return false;
- Result = HandleFloatToFloatCast(E->getType(), SubExpr->getType(),
- Result, Info.Ctx);
- return true;
+ return HandleFloatToFloatCast(Info, E, SubExpr->getType(), E->getType(),
+ Result);
}
case CK_FloatingComplexToReal: {
@@ -4289,11 +4394,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType From
= E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
- Result.FloatReal
- = HandleFloatToFloatCast(To, From, Result.FloatReal, Info.Ctx);
- Result.FloatImag
- = HandleFloatToFloatCast(To, From, Result.FloatImag, Info.Ctx);
- return true;
+ return HandleFloatToFloatCast(Info, E, From, To, Result.FloatReal) &&
+ HandleFloatToFloatCast(Info, E, From, To, Result.FloatImag);
}
case CK_FloatingComplexToIntegralComplex: {
@@ -4304,9 +4406,10 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType From
= E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
Result.makeComplexInt();
- Result.IntReal = HandleFloatToIntCast(To, From, Result.FloatReal, Info.Ctx);
- Result.IntImag = HandleFloatToIntCast(To, From, Result.FloatImag, Info.Ctx);
- return true;
+ return HandleFloatToIntCast(Info, E, From, Result.FloatReal,
+ To, Result.IntReal) &&
+ HandleFloatToIntCast(Info, E, From, Result.FloatImag,
+ To, Result.IntImag);
}
case CK_IntegralRealToComplex: {
@@ -4340,9 +4443,10 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType From
= E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
Result.makeComplexFloat();
- Result.FloatReal = HandleIntToFloatCast(To, From, Result.IntReal, Info.Ctx);
- Result.FloatImag = HandleIntToFloatCast(To, From, Result.IntImag, Info.Ctx);
- return true;
+ return HandleIntToFloatCast(Info, E, From, Result.IntReal,
+ To, Result.FloatReal) &&
+ HandleIntToFloatCast(Info, E, From, Result.IntImag,
+ To, Result.FloatImag);
}
}
@@ -4581,8 +4685,16 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) {
return false;
Result = Info.CurrentCall->Temporaries[E];
} else if (E->getType()->isVoidType()) {
+ if (Info.getLangOpts().CPlusPlus0x)
+ Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_nonliteral)
+ << E->getType();
+ else
+ Info.CCEDiag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
if (!EvaluateVoid(E, Info))
return false;
+ } else if (Info.getLangOpts().CPlusPlus0x) {
+ Info.Diag(E->getExprLoc(), diag::note_constexpr_nonliteral) << E->getType();
+ return false;
} else {
Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -4596,7 +4708,8 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) {
/// since later initializers for an object can indirectly refer to subobjects
/// which were initialized earlier.
static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
- const LValue &This, const Expr *E) {
+ const LValue &This, const Expr *E,
+ CheckConstantExpressionKind CCEK) {
if (E->isRValue() && E->getType()->isLiteralType()) {
// Evaluate arrays and record types in-place, so that later initializers can
// refer to earlier-initialized members of the object.
@@ -4609,7 +4722,7 @@ static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
// For any other type, in-place evaluation is unimportant.
CCValue CoreConstResult;
return Evaluate(CoreConstResult, Info, E) &&
- CheckConstantExpression(Info, E, CoreConstResult, Result);
+ CheckConstantExpression(Info, E, CoreConstResult, Result, CCEK);
}
/// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
@@ -4681,7 +4794,8 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
LValue LV;
return EvaluateLValue(this, LV, Info) && !Result.HasSideEffects &&
- CheckLValueConstantExpression(Info, this, LV, Result.Val);
+ CheckLValueConstantExpression(Info, this, LV, Result.Val,
+ CCEK_Constant);
}
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 2c6a46b3be..dcb4bf4619 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -1,4 +1,357 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -pedantic -verify -fcxx-exceptions %s
+
+// A conditional-expression is a core constant expression unless it involves one
+// of the following as a potentially evaluated subexpression [...]:
+
+// - this (5.1.1 [expr.prim.general]) [Note: when evaluating a constant
+// expression, function invocation substitution (7.1.5 [dcl.constexpr])
+// replaces each occurrence of this in a constexpr member function with a
+// pointer to the class object. -end note];
+struct This {
+ int this1 : this1; // expected-error {{undeclared}}
+ int this2 : this->this1; // expected-error {{invalid}}
+ void this3() {
+ int n1[this->this1]; // expected-warning {{variable length array}}
+ int n2[this1]; // expected-warning {{variable length array}}
+ (void)n1, (void)n2;
+ }
+};
+
+// - an invocation of a function other than a constexpr constructor for a
+// literal class or a constexpr function [ Note: Overload resolution (13.3)
+// is applied as usual - end note ];
+struct NonConstexpr1 {
+ static int f() { return 1; } // expected-note {{here}}
+ int n : f(); // expected-error {{constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}}
+};
+struct NonConstexpr2 {
+ constexpr NonConstexpr2(); // expected-note {{here}}
+ int n;
+};
+struct NonConstexpr3 {
+ NonConstexpr3();
+ int m : NonConstexpr2().n; // expected-error {{constant expression}} expected-note {{undefined constructor 'NonConstexpr2'}}
+};
+struct NonConstexpr4 {
+ NonConstexpr4();
+ int n;
+};
+struct NonConstexpr5 {
+ int n : NonConstexpr4().n; // expected-error {{constant expression}} expected-note {{non-literal type 'NonConstexpr4' cannot be used in a constant expression}}
+};
+
+// - an invocation of an undefined constexpr function or an undefined
+// constexpr constructor;
+struct UndefinedConstexpr {
+ constexpr UndefinedConstexpr();
+ static constexpr int undefinedConstexpr1(); // expected-note {{here}}
+ int undefinedConstexpr2 : undefinedConstexpr1(); // expected-error {{constant expression}} expected-note {{undefined function 'undefinedConstexpr1' cannot be used in a constant expression}}
+};
+
+// - an invocation of a constexpr function with arguments that, when substituted
+// by function invocation substitution (7.1.5), do not produce a constant
+// expression;
+namespace NonConstExprReturn {
+ static constexpr const int &id_ref(const int &n) {
+ return n; // expected-note {{reference to temporary cannot be returned from a constexpr function}}
+ }
+ struct NonConstExprFunction {
+ int n : id_ref( // expected-error {{constant expression}}
+ 16 // expected-note {{temporary created here}}
+ );
+ };
+ constexpr const int *address_of(const int &a) {
+ return &a; // expected-note {{pointer to 'n' cannot be returned from a constexpr function}}
+ }
+ constexpr const int *return_param(int n) { // expected-note {{declared here}}
+ return address_of(n);
+ }
+ struct S {
+ int n : *return_param(0); // expected-error {{constant expression}}
+ };
+}
+
+// - an invocation of a constexpr constructor with arguments that, when
+// substituted by function invocation substitution (7.1.5), do not produce all
+// constant expressions for the constructor calls and full-expressions in the
+// mem-initializers (including conversions);
+namespace NonConstExprCtor {
+ struct T {
+ constexpr T(const int &r) :
+ r(r) { // expected-note {{reference to temporary cannot be used to initialize a member in a constant expression}}
+ }
+ const int &r;
+ };
+ constexpr int n = 0;
+ constexpr T t1(n); // ok
+ constexpr T t2(0); // expected-error {{must be initialized by a constant expression}}
+
+ struct S {
+ int n : T(4).r; // expected-error {{constant expression}} expected-note {{temporary created here}}
+ };
+}
+
+// - an invocation of a constexpr function or a constexpr constructor that would
+// exceed the implementation-defined recursion limits (see Annex B);
+namespace RecursionLimits {
+ constexpr int RecurseForever(int n) {
+ return n + RecurseForever(n+1); // expected-note {{constexpr evaluation exceeded maximum depth of 512 calls}}
+ }
+ struct AlsoRecurseForever {
+ constexpr AlsoRecurseForever(int n) :
+ n(AlsoRecurseForever(n+1).n) // expected-note {{constexpr evaluation exceeded maximum depth of 512 calls}}
+ {}
+ int n;
+ };
+ struct S {
+ int k : RecurseForever(0); // expected-error {{constant expression}}
+ int l : AlsoRecurseForever(0).n; // expected-error {{constant expression}}
+ };
+}
+
+// FIXME:
+// - an operation that would have undefined behavior [Note: including, for
+// example, signed integer overflow (Clause 5 [expr]), certain pointer
+// arithmetic (5.7 [expr.add]), division by zero (5.6 [expr.mul]), or certain
+// shift operations (5.8 [expr.shift]) -end note];
+namespace UndefinedBehavior {
+ void f(int n) {
+ switch (n) {
+ case (int)4.4e9: // expected-error {{constant expression}} expected-note {{value 4.4E+9 is outside the range of representable values of type 'int'}}
+ case (int)(unsigned)(long long)4.4e9: // ok
+ case (float)1e300: // expected-error {{constant expression}} expected-note {{value 1.0E+300 is outside the range of representable values of type 'float'}}
+ case (int)((float)1e37 / 1e30): // ok
+ case (int)(__fp16)65536: // expected-error {{constant expression}} expected-note {{value 65536 is outside the range of representable values of type 'half'}}
+ break;
+ }
+ }
+
+ struct S {
+ int m;
+ };
+ constexpr S s = { 5 }; // expected-note {{declared here}}
+ constexpr const int *p = &s.m + 1;
+ constexpr const int &f(const int *q) {
+ return q[0]; // expected-note {{dereferenced pointer past the end of subobject of 's' is not a constant expression}}
+ }
+ struct T {
+ int n : f(p); // expected-error {{not an integer constant expression}}
+ };
+}
+
+// - a lambda-expression (5.1.2);
+struct Lambda {
+ // FIXME: clang crashes when trying to parse this! Revisit this check once
+ // lambdas are fully implemented.
+ //int n : []{ return 1; }();
+};
+
+// FIXME:
+// - an lvalue-to-rvalue conversion (4.1) unless it is applied to
+//
+// - a non-volatile glvalue of integral or enumeration type that refers to a
+// non-volatile const object with a preceding initialization, initialized with
+// a constant expression [Note: a string literal (2.14.5 [lex.string])
+// corresponds to an array of such objects. -end note], or
+//
+// - a non-volatile glvalue of literal type that refers to a non-volatile
+// object defined with constexpr, or that refers to a sub-object of such an
+// object, or
+//
+// - a non-volatile glvalue of literal type that refers to a non-volatile
+// temporary object whose lifetime has not ended, initialized with a constant
+// expression;
+
+// FIXME:
+//
+// DR1312: The proposed wording for this defect has issues, so we instead
+// prohibit casts from pointers to cv void (see core-20842 and core-20845).
+//
+// - an lvalue-to-rvalue conversion (4.1 [conv.lval]) that is applied to a
+// glvalue of type cv1 T that refers to an object of type cv2 U, where T and U
+// are neither the same type nor similar types (4.4 [conv.qual]);
+
+// FIXME:
+// - an lvalue-to-rvalue conversion (4.1) that is applied to a glvalue that
+// refers to a non-active member of a union or a subobject thereof;
+
+// FIXME:
+// - an id-expression that refers to a variable or data member of reference type
+// unless the reference has a preceding initialization, initialized with a
+// constant expression;
+namespace References {
+ const int a = 2;
+ int &b = *const_cast<int*>(&a);
+ int c = 10;
+ int &d = c;
+ constexpr int e = 42;
+ int &f = const_cast<int&>(e);
+ extern int &g;
+ constexpr int &h(); // expected-note {{here}}
+ int &i = h();
+ constexpr int &j() { return b; }
+ int &k = j();
+
+ struct S {
+ int A : a;
+ int B : b;
+ int C : c; // expected-error {{constant expression}}
+ int D : d; // expected-error {{constant expression}}
+ int D2 : &d - &c + 1;
+ int E : e / 2;
+ int F : f - 11;
+ int G : g; // expected-error {{constant expression}}
+ int H : h(); // expected-error {{constant expression}} expected-note {{undefined function 'h'}}
+ int I : i; // expected-error {{constant expression}}
+ int J : j();
+ int K : k;
+ };
+}
+
+// - a dynamic_cast (5.2.7);
+namespace DynamicCast {
+ struct S { int n; };
+ constexpr S s { 16 };
+ struct T {
+ int n : dynamic_cast<const S*>(&s)->n; // expected-warning {{constant expression}} expected-note {{dynamic_cast}}
+ };
+}
+
+// - a reinterpret_cast (5.2.10);
+namespace ReinterpretCast {
+ struct S { int n; };
+ constexpr S s { 16 };
+ struct T {
+ int n : reinterpret_cast<const S*>(&s)->n; // expected-warning {{constant expression}} expected-note {{reinterpret_cast}}
+ };
+ struct U {
+ int m : (long)(S*)6; // expected-warning {{constant expression}} expected-note {{reinterpret_cast}}
+ };
+}
+
+// - a pseudo-destructor call (