forked from OSchip/llvm-project
Initial support for C++11 constexpr function invocation substitution. Using
constexpr function arguments outside of their function (passing or returning them by reference) does not work correctly yet. Calling constexpr function templates does not work yet, since the bodies are not instantiated until the end of the translation unit. llvm-svn: 143234
This commit is contained in:
parent
d1f1b79b52
commit
254a73d636
|
@ -1959,6 +1959,9 @@ public:
|
|||
Expr **getArgs() {
|
||||
return reinterpret_cast<Expr **>(SubExprs+getNumPreArgs()+PREARGS_START);
|
||||
}
|
||||
const Expr *const *getArgs() const {
|
||||
return const_cast<CallExpr*>(this)->getArgs();
|
||||
}
|
||||
|
||||
/// getArg - Return the specified argument.
|
||||
Expr *getArg(unsigned Arg) {
|
||||
|
|
|
@ -43,12 +43,23 @@ using llvm::APFloat;
|
|||
/// evaluate the expression regardless of what the RHS is, but C only allows
|
||||
/// certain things in certain situations.
|
||||
namespace {
|
||||
struct CallStackFrame;
|
||||
|
||||
struct EvalInfo {
|
||||
const ASTContext &Ctx;
|
||||
|
||||
/// EvalStatus - Contains information about the evaluation.
|
||||
Expr::EvalStatus &EvalStatus;
|
||||
|
||||
/// CurrentCall - The top of the constexpr call stack.
|
||||
const CallStackFrame *CurrentCall;
|
||||
|
||||
/// NumCalls - The number of calls we've evaluated so far.
|
||||
unsigned NumCalls;
|
||||
|
||||
/// CallStackDepth - The number of calls in the call stack right now.
|
||||
unsigned CallStackDepth;
|
||||
|
||||
typedef llvm::DenseMap<const OpaqueValueExpr*, APValue> MapTy;
|
||||
MapTy OpaqueValues;
|
||||
const APValue *getOpaqueValue(const OpaqueValueExpr *e) const {
|
||||
|
@ -58,11 +69,40 @@ namespace {
|
|||
}
|
||||
|
||||
EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
|
||||
: Ctx(C), EvalStatus(S) {}
|
||||
: Ctx(C), EvalStatus(S), CurrentCall(0), NumCalls(0), CallStackDepth(0) {}
|
||||
|
||||
const LangOptions &getLangOpts() { return Ctx.getLangOptions(); }
|
||||
};
|
||||
|
||||
/// A stack frame in the constexpr call stack.
|
||||
struct CallStackFrame {
|
||||
EvalInfo &Info;
|
||||
|
||||
/// Parent - The caller of this stack frame.
|
||||
const CallStackFrame *Caller;
|
||||
|
||||
/// ParmBindings - Parameter bindings for this function call, indexed by
|
||||
/// parameters' function scope indices.
|
||||
const APValue *Arguments;
|
||||
|
||||
/// CallIndex - The index of the current call. This is used to match lvalues
|
||||
/// referring to parameters up with the corresponding stack frame, and to
|
||||
/// detect when the parameter is no longer in scope.
|
||||
unsigned CallIndex;
|
||||
|
||||
CallStackFrame(EvalInfo &Info, const APValue *Arguments)
|
||||
: Info(Info), Caller(Info.CurrentCall), Arguments(Arguments),
|
||||
CallIndex(Info.NumCalls++) {
|
||||
Info.CurrentCall = this;
|
||||
++Info.CallStackDepth;
|
||||
}
|
||||
~CallStackFrame() {
|
||||
assert(Info.CurrentCall == this && "calls retired out of order");
|
||||
--Info.CallStackDepth;
|
||||
Info.CurrentCall = Caller;
|
||||
}
|
||||
};
|
||||
|
||||
struct ComplexValue {
|
||||
private:
|
||||
bool IsInt;
|
||||
|
@ -269,11 +309,17 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
|
|||
}
|
||||
|
||||
/// Try to evaluate the initializer for a variable declaration.
|
||||
static APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) {
|
||||
// FIXME: If this is a parameter to an active constexpr function call, perform
|
||||
// substitution now.
|
||||
if (isa<ParmVarDecl>(VD))
|
||||
static const APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) {
|
||||
// If this is a parameter to an active constexpr function call, perform
|
||||
// argument substitution.
|
||||
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
|
||||
// FIXME This assumes that all parameters must be parameters of the current
|
||||
// call. Add the CallIndex to the LValue representation and use that to
|
||||
// check.
|
||||
if (Info.CurrentCall)
|
||||
return &Info.CurrentCall->Arguments[PVD->getFunctionScopeIndex()];
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Expr *Init = VD->getAnyInitializer();
|
||||
if (!Init)
|
||||
|
@ -341,22 +387,28 @@ bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
|
|||
if (D) {
|
||||
// In C++98, const, non-volatile integers initialized with ICEs are ICEs.
|
||||
// In C++11, constexpr, non-volatile variables initialized with constant
|
||||
// expressions are constant expressions too.
|
||||
// expressions are constant expressions too. Inside constexpr functions,
|
||||
// parameters are constant expressions even if they're non-const.
|
||||
// In C, such things can also be folded, although they are not ICEs.
|
||||
//
|
||||
// FIXME: Allow folding any const variable of literal type initialized with
|
||||
// a constant expression. For now, we only allow variables with integral and
|
||||
// floating types to be folded.
|
||||
// FIXME: volatile-qualified ParmVarDecls need special handling. A literal
|
||||
// interpretation of C++11 suggests that volatile parameters are OK if
|
||||
// they're never read (there's no prohibition against constructing volatile
|
||||
// objects in constant expressions), but lvalue-to-rvalue conversions on
|
||||
// them are not permitted.
|
||||
const VarDecl *VD = dyn_cast<VarDecl>(D);
|
||||
if (!VD || !IsConstNonVolatile(VD->getType()) ||
|
||||
(!Type->isIntegralOrEnumerationType() && !Type->isRealFloatingType()))
|
||||
if (!VD || !(IsConstNonVolatile(VD->getType()) || isa<ParmVarDecl>(VD)) ||
|
||||
!(Type->isIntegralOrEnumerationType() || Type->isRealFloatingType()))
|
||||
return false;
|
||||
|
||||
APValue *V = EvaluateVarDeclInit(Info, VD);
|
||||
const APValue *V = EvaluateVarDeclInit(Info, VD);
|
||||
if (!V || V->isUninit())
|
||||
return false;
|
||||
|
||||
if (!VD->getAnyInitializer()->isLValue()) {
|
||||
if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue()) {
|
||||
RVal = *V;
|
||||
return true;
|
||||
}
|
||||
|
@ -385,6 +437,64 @@ bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
|
|||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
enum EvalStmtResult {
|
||||
/// Evaluation failed.
|
||||
ESR_Failed,
|
||||
/// Hit a 'return' statement.
|
||||
ESR_Returned,
|
||||
/// Evaluation succeeded.
|
||||
ESR_Succeeded
|
||||
};
|
||||
}
|
||||
|
||||
// Evaluate a statement.
|
||||
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
|
||||
const Stmt *S) {
|
||||
switch (S->getStmtClass()) {
|
||||
default:
|
||||
return ESR_Failed;
|
||||
|
||||
case Stmt::NullStmtClass:
|
||||
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::CompoundStmtClass: {
|
||||
const CompoundStmt *CS = cast<CompoundStmt>(S);
|
||||
for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
|
||||
BE = CS->body_end(); BI != BE; ++BI) {
|
||||
EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
|
||||
if (ESR != ESR_Succeeded)
|
||||
return ESR;
|
||||
}
|
||||
return ESR_Succeeded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate a function call.
|
||||
static bool HandleFunctionCall(ArrayRef<const Expr*> Args, const Stmt *Body,
|
||||
EvalInfo &Info, APValue &Result) {
|
||||
// FIXME: Implement a proper call limit, along with a command-line flag.
|
||||
if (Info.NumCalls >= 1000000 || Info.CallStackDepth >= 512)
|
||||
return false;
|
||||
|
||||
SmallVector<APValue, 16> ArgValues(Args.size());
|
||||
// FIXME: Deal with default arguments and 'this'.
|
||||
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
|
||||
I != E; ++I)
|
||||
if (!Evaluate(ArgValues[I - Args.begin()], Info, *I))
|
||||
return false;
|
||||
|
||||
CallStackFrame Frame(Info, ArgValues.data());
|
||||
return EvaluateStmt(Result, Info, Body) == ESR_Returned;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class HasSideEffect
|
||||
: public ConstStmtVisitor<HasSideEffect, bool> {
|
||||
|
@ -568,6 +678,47 @@ public:
|
|||
return DerivedSuccess(*value, E);
|
||||
}
|
||||
|
||||
RetTy VisitCallExpr(const CallExpr *E) {
|
||||
const Expr *Callee = E->getCallee();
|
||||
QualType CalleeType = Callee->getType();
|
||||
|
||||
// FIXME: Handle the case where Callee is a (parenthesized) MemberExpr for a
|
||||
// non-static member function.
|
||||
if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember))
|
||||
return DerivedError(E);
|
||||
|
||||
if (!CalleeType->isFunctionType() && !CalleeType->isFunctionPointerType())
|
||||
return DerivedError(E);
|
||||
|
||||
APValue Call;
|
||||
if (!Evaluate(Call, Info, Callee) || !Call.isLValue() ||
|
||||
!Call.getLValueBase() || !Call.getLValueOffset().isZero())
|
||||
return DerivedError(Callee);
|
||||
|
||||
const FunctionDecl *FD = 0;
|
||||
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Call.getLValueBase()))
|
||||
FD = dyn_cast<FunctionDecl>(DRE->getDecl());
|
||||
else if (const MemberExpr *ME = dyn_cast<MemberExpr>(Call.getLValueBase()))
|
||||
FD = dyn_cast<FunctionDecl>(ME->getMemberDecl());
|
||||
if (!FD)
|
||||
return DerivedError(Callee);
|
||||
|
||||
// Don't call function pointers which have been cast to some other type.
|
||||
if (!Info.Ctx.hasSameType(CalleeType->getPointeeType(), FD->getType()))
|
||||
return DerivedError(E);
|
||||
|
||||
const FunctionDecl *Definition;
|
||||
Stmt *Body = FD->getBody(Definition);
|
||||
APValue Result;
|
||||
llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
|
||||
|
||||
if (Body && Definition->isConstexpr() && !Definition->isInvalidDecl() &&
|
||||
HandleFunctionCall(Args, Body, Info, Result))
|
||||
return DerivedSuccess(Result, E);
|
||||
|
||||
return DerivedError(E);
|
||||
}
|
||||
|
||||
RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
|
||||
return StmtVisitorTy::Visit(E->getInitializer());
|
||||
}
|
||||
|
@ -716,7 +867,7 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
|
|||
if (!VD->getType()->isReferenceType())
|
||||
return Success(E);
|
||||
|
||||
APValue *V = EvaluateVarDeclInit(Info, VD);
|
||||
const APValue *V = EvaluateVarDeclInit(Info, VD);
|
||||
if (V && !V->isUninit())
|
||||
return Success(*V, E);
|
||||
|
||||
|
@ -738,6 +889,14 @@ bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
|
|||
return VisitVarDecl(E, VD);
|
||||
}
|
||||
|
||||
// Handle static member functions.
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(E->getMemberDecl())) {
|
||||
if (MD->isStatic()) {
|
||||
VisitIgnoredValue(E->getBase());
|
||||
return Success(E);
|
||||
}
|
||||
}
|
||||
|
||||
QualType Ty;
|
||||
if (E->isArrow()) {
|
||||
if (!EvaluatePointer(E->getBase(), Result, Info))
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||
|
||||
template<typename T> constexpr T id(const T &t) { return t; }
|
||||
// FIXME: support const T& parameters here.
|
||||
//template<typename T> constexpr T id(const T &t) { return t; }
|
||||
template<typename T> constexpr T id(T t) { return t; }
|
||||
// FIXME: support templates here.
|
||||
//template<typename T> constexpr T min(const T &a, const T &b) {
|
||||
// return a < b ? a : b;
|
||||
//}
|
||||
//template<typename T> constexpr T max(const T &a, const T &b) {
|
||||
// return a < b ? b : a;
|
||||
//}
|
||||
constexpr int min(int a, int b) { return a < b ? a : b; }
|
||||
constexpr int max(int a, int b) { return a < b ? b : a; }
|
||||
|
||||
struct MemberZero {
|
||||
constexpr int zero() { return 0; }
|
||||
|
@ -40,3 +51,43 @@ namespace MemberEnum {
|
|||
constexpr bool b = wme.A == 42;
|
||||
int n[b];
|
||||
}
|
||||
|
||||
namespace Recursion {
|
||||
constexpr int fib(int n) { return n > 1 ? fib(n-1) + fib(n-2) : n; }
|
||||
// FIXME: this isn't an ICE yet.
|
||||
using check_fib = int[fib(11)];
|
||||
using check_fib = int[89];
|
||||
|
||||
constexpr int gcd_inner(int a, int b) {
|
||||
return b == 0 ? a : gcd_inner(b, a % b);
|
||||
}
|
||||
constexpr int gcd(int a, int b) {
|
||||
return gcd_inner(max(a, b), min(a, b));
|
||||
}
|
||||
|
||||
// FIXME: this isn't an ICE yet.
|
||||
using check_gcd = int[gcd(1749237, 5628959)];
|
||||
using check_gcd = int[7];
|
||||
}
|
||||
|
||||
namespace FunctionCast {
|
||||
// When folding, we allow functions to be cast to different types. Such
|
||||
// cast functions cannot be called, even if they're constexpr.
|
||||
constexpr int f() { return 1; }
|
||||
typedef double (*DoubleFn)();
|
||||
typedef int (*IntFn)();
|
||||
int a[(int)DoubleFn(f)()]; // expected-error {{variable length array}}
|
||||
int b[(int)IntFn(f)()]; // ok
|
||||
}
|
||||
|
||||
namespace StaticMemberFunction {
|
||||
struct S {
|
||||
static constexpr int k = 42;
|
||||
static constexpr int f(int n) { return n * k + 2; }
|
||||
} s;
|
||||
// FIXME: this isn't an ICE yet.
|
||||
using check_static_call = int[S::f(19)];
|
||||
constexpr int n = s.f(19);
|
||||
using check_static_call = int[s.f(19)];
|
||||
using check_static_call = int[800];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue