forked from OSchip/llvm-project
Revert "PR47805: Use a single object for a function parameter in the caller and"
Breaks a clangd unit test.
This reverts commit 8f8b9f2cca
.
This commit is contained in:
parent
d4b0404732
commit
69f7c006ff
|
@ -490,39 +490,6 @@ namespace {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A scope at the end of which an object can need to be destroyed.
|
|
||||||
enum class ScopeKind {
|
|
||||||
Block,
|
|
||||||
FullExpression,
|
|
||||||
Call
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A reference to a particular call and its arguments.
|
|
||||||
struct CallRef {
|
|
||||||
CallRef() : OrigCallee(), CallIndex(0), Version() {}
|
|
||||||
CallRef(const FunctionDecl *Callee, unsigned CallIndex, unsigned Version)
|
|
||||||
: OrigCallee(Callee), CallIndex(CallIndex), Version(Version) {}
|
|
||||||
|
|
||||||
explicit operator bool() const { return OrigCallee; }
|
|
||||||
|
|
||||||
/// Get the parameter that the caller initialized, corresponding to the
|
|
||||||
/// given parameter in the callee.
|
|
||||||
const ParmVarDecl *getOrigParam(const ParmVarDecl *PVD) const {
|
|
||||||
return OrigCallee ? OrigCallee->getParamDecl(PVD->getFunctionScopeIndex())
|
|
||||||
: PVD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The callee at the point where the arguments were evaluated. This might
|
|
||||||
/// be different from the actual callee (a different redeclaration, or a
|
|
||||||
/// virtual override), but this function's parameters are the ones that
|
|
||||||
/// appear in the parameter map.
|
|
||||||
const FunctionDecl *OrigCallee;
|
|
||||||
/// The call index of the frame that holds the argument values.
|
|
||||||
unsigned CallIndex;
|
|
||||||
/// The version of the parameters corresponding to this call.
|
|
||||||
unsigned Version;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A stack frame in the constexpr call stack.
|
/// A stack frame in the constexpr call stack.
|
||||||
class CallStackFrame : public interp::Frame {
|
class CallStackFrame : public interp::Frame {
|
||||||
public:
|
public:
|
||||||
|
@ -537,10 +504,9 @@ namespace {
|
||||||
/// This - The binding for the this pointer in this call, if any.
|
/// This - The binding for the this pointer in this call, if any.
|
||||||
const LValue *This;
|
const LValue *This;
|
||||||
|
|
||||||
/// Information on how to find the arguments to this call. Our arguments
|
/// Arguments - Parameter bindings for this function call, indexed by
|
||||||
/// are stored in our parent's CallStackFrame, using the ParmVarDecl* as a
|
/// parameters' function scope indices.
|
||||||
/// key and this value as the version.
|
APValue *Arguments;
|
||||||
CallRef Arguments;
|
|
||||||
|
|
||||||
/// Source location information about the default argument or default
|
/// Source location information about the default argument or default
|
||||||
/// initializer expression we're evaluating, if any.
|
/// initializer expression we're evaluating, if any.
|
||||||
|
@ -573,10 +539,6 @@ namespace {
|
||||||
TempVersionStack.pop_back();
|
TempVersionStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
CallRef createCall(const FunctionDecl *Callee) {
|
|
||||||
return {Callee, Index, ++CurTempVersion};
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
|
// FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
|
||||||
// on the overall stack usage of deeply-recursing constexpr evaluations.
|
// on the overall stack usage of deeply-recursing constexpr evaluations.
|
||||||
// (We should cache this map rather than recomputing it repeatedly.)
|
// (We should cache this map rather than recomputing it repeatedly.)
|
||||||
|
@ -590,7 +552,7 @@ namespace {
|
||||||
|
|
||||||
CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
|
CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
|
||||||
const FunctionDecl *Callee, const LValue *This,
|
const FunctionDecl *Callee, const LValue *This,
|
||||||
CallRef Arguments);
|
APValue *Arguments);
|
||||||
~CallStackFrame();
|
~CallStackFrame();
|
||||||
|
|
||||||
// Return the temporary for Key whose version number is Version.
|
// Return the temporary for Key whose version number is Version.
|
||||||
|
@ -629,10 +591,7 @@ namespace {
|
||||||
/// bumping the temporary version number.
|
/// bumping the temporary version number.
|
||||||
template<typename KeyT>
|
template<typename KeyT>
|
||||||
APValue &createTemporary(const KeyT *Key, QualType T,
|
APValue &createTemporary(const KeyT *Key, QualType T,
|
||||||
ScopeKind Scope, LValue &LV);
|
bool IsLifetimeExtended, LValue &LV);
|
||||||
|
|
||||||
/// Allocate storage for a parameter of a function call made in this frame.
|
|
||||||
APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
|
|
||||||
|
|
||||||
void describe(llvm::raw_ostream &OS) override;
|
void describe(llvm::raw_ostream &OS) override;
|
||||||
|
|
||||||
|
@ -646,10 +605,6 @@ namespace {
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
APValue &createLocal(APValue::LValueBase Base, const void *Key, QualType T,
|
|
||||||
ScopeKind Scope);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Temporarily override 'this'.
|
/// Temporarily override 'this'.
|
||||||
|
@ -678,20 +633,16 @@ static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
|
||||||
namespace {
|
namespace {
|
||||||
/// A cleanup, and a flag indicating whether it is lifetime-extended.
|
/// A cleanup, and a flag indicating whether it is lifetime-extended.
|
||||||
class Cleanup {
|
class Cleanup {
|
||||||
llvm::PointerIntPair<APValue*, 2, ScopeKind> Value;
|
llvm::PointerIntPair<APValue*, 1, bool> Value;
|
||||||
APValue::LValueBase Base;
|
APValue::LValueBase Base;
|
||||||
QualType T;
|
QualType T;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Cleanup(APValue *Val, APValue::LValueBase Base, QualType T,
|
Cleanup(APValue *Val, APValue::LValueBase Base, QualType T,
|
||||||
ScopeKind Scope)
|
bool IsLifetimeExtended)
|
||||||
: Value(Val, Scope), Base(Base), T(T) {}
|
: Value(Val, IsLifetimeExtended), Base(Base), T(T) {}
|
||||||
|
|
||||||
/// Determine whether this cleanup should be performed at the end of the
|
bool isLifetimeExtended() const { return Value.getInt(); }
|
||||||
/// given kind of scope.
|
|
||||||
bool isDestroyedAtEndOf(ScopeKind K) const {
|
|
||||||
return (int)Value.getInt() >= (int)K;
|
|
||||||
}
|
|
||||||
bool endLifetime(EvalInfo &Info, bool RunDestructors) {
|
bool endLifetime(EvalInfo &Info, bool RunDestructors) {
|
||||||
if (RunDestructors) {
|
if (RunDestructors) {
|
||||||
SourceLocation Loc;
|
SourceLocation Loc;
|
||||||
|
@ -977,7 +928,7 @@ namespace {
|
||||||
CallStackDepth(0), NextCallIndex(1),
|
CallStackDepth(0), NextCallIndex(1),
|
||||||
StepsLeft(C.getLangOpts().ConstexprStepLimit),
|
StepsLeft(C.getLangOpts().ConstexprStepLimit),
|
||||||
EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
|
EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
|
||||||
BottomFrame(*this, SourceLocation(), nullptr, nullptr, CallRef()),
|
BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
|
||||||
EvaluatingDecl((const ValueDecl *)nullptr),
|
EvaluatingDecl((const ValueDecl *)nullptr),
|
||||||
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
|
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
|
||||||
HasFoldFailureDiagnostic(false), InConstantContext(false),
|
HasFoldFailureDiagnostic(false), InConstantContext(false),
|
||||||
|
@ -1046,13 +997,6 @@ namespace {
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the allocated storage for the given parameter of the given call.
|
|
||||||
APValue *getParamSlot(CallRef Call, const ParmVarDecl *PVD) {
|
|
||||||
CallStackFrame *Frame = getCallFrameAndDepth(Call.CallIndex).first;
|
|
||||||
return Frame ? Frame->getTemporary(Call.getOrigParam(PVD), Call.Version)
|
|
||||||
: nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information about a stack frame for std::allocator<T>::[de]allocate.
|
/// Information about a stack frame for std::allocator<T>::[de]allocate.
|
||||||
struct StdAllocatorCaller {
|
struct StdAllocatorCaller {
|
||||||
unsigned FrameIndex;
|
unsigned FrameIndex;
|
||||||
|
@ -1088,12 +1032,9 @@ namespace {
|
||||||
|
|
||||||
void performLifetimeExtension() {
|
void performLifetimeExtension() {
|
||||||
// Disable the cleanups for lifetime-extended temporaries.
|
// Disable the cleanups for lifetime-extended temporaries.
|
||||||
CleanupStack.erase(std::remove_if(CleanupStack.begin(),
|
CleanupStack.erase(
|
||||||
CleanupStack.end(),
|
std::remove_if(CleanupStack.begin(), CleanupStack.end(),
|
||||||
[](Cleanup &C) {
|
[](Cleanup &C) { return C.isLifetimeExtended(); }),
|
||||||
return !C.isDestroyedAtEndOf(
|
|
||||||
ScopeKind::FullExpression);
|
|
||||||
}),
|
|
||||||
CleanupStack.end());
|
CleanupStack.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1343,7 +1284,7 @@ namespace {
|
||||||
|
|
||||||
/// RAII object wrapping a full-expression or block scope, and handling
|
/// RAII object wrapping a full-expression or block scope, and handling
|
||||||
/// the ending of the lifetime of temporaries created within it.
|
/// the ending of the lifetime of temporaries created within it.
|
||||||
template<ScopeKind Kind>
|
template<bool IsFullExpression>
|
||||||
class ScopeRAII {
|
class ScopeRAII {
|
||||||
EvalInfo &Info;
|
EvalInfo &Info;
|
||||||
unsigned OldStackSize;
|
unsigned OldStackSize;
|
||||||
|
@ -1376,7 +1317,8 @@ namespace {
|
||||||
// for a full-expression scope.
|
// for a full-expression scope.
|
||||||
bool Success = true;
|
bool Success = true;
|
||||||
for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
|
for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
|
||||||
if (Info.CleanupStack[I - 1].isDestroyedAtEndOf(Kind)) {
|
if (!(IsFullExpression &&
|
||||||
|
Info.CleanupStack[I - 1].isLifetimeExtended())) {
|
||||||
if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
|
if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
|
||||||
Success = false;
|
Success = false;
|
||||||
break;
|
break;
|
||||||
|
@ -1384,20 +1326,18 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compact any retained cleanups.
|
// Compact lifetime-extended cleanups.
|
||||||
auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
|
auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
|
||||||
if (Kind != ScopeKind::Block)
|
if (IsFullExpression)
|
||||||
NewEnd =
|
NewEnd =
|
||||||
std::remove_if(NewEnd, Info.CleanupStack.end(), [](Cleanup &C) {
|
std::remove_if(NewEnd, Info.CleanupStack.end(),
|
||||||
return C.isDestroyedAtEndOf(Kind);
|
[](Cleanup &C) { return !C.isLifetimeExtended(); });
|
||||||
});
|
|
||||||
Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
|
Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typedef ScopeRAII<ScopeKind::Block> BlockScopeRAII;
|
typedef ScopeRAII<false> BlockScopeRAII;
|
||||||
typedef ScopeRAII<ScopeKind::FullExpression> FullExpressionRAII;
|
typedef ScopeRAII<true> FullExpressionRAII;
|
||||||
typedef ScopeRAII<ScopeKind::Call> CallScopeRAII;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
|
bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
|
||||||
|
@ -1440,9 +1380,9 @@ void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
|
||||||
|
|
||||||
CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
|
CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
|
||||||
const FunctionDecl *Callee, const LValue *This,
|
const FunctionDecl *Callee, const LValue *This,
|
||||||
CallRef Call)
|
APValue *Arguments)
|
||||||
: Info(Info), Caller(Info.CurrentCall), Callee(Callee), This(This),
|
: Info(Info), Caller(Info.CurrentCall), Callee(Callee), This(This),
|
||||||
Arguments(Call), CallLoc(CallLoc), Index(Info.NextCallIndex++) {
|
Arguments(Arguments), CallLoc(CallLoc), Index(Info.NextCallIndex++) {
|
||||||
Info.CurrentCall = this;
|
Info.CurrentCall = this;
|
||||||
++Info.CallStackDepth;
|
++Info.CallStackDepth;
|
||||||
}
|
}
|
||||||
|
@ -1855,33 +1795,14 @@ static void negateAsSigned(APSInt &Int) {
|
||||||
|
|
||||||
template<typename KeyT>
|
template<typename KeyT>
|
||||||
APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
|
APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
|
||||||
ScopeKind Scope, LValue &LV) {
|
bool IsLifetimeExtended, LValue &LV) {
|
||||||
unsigned Version = getTempVersion();
|
unsigned Version = getTempVersion();
|
||||||
APValue::LValueBase Base(Key, Index, Version);
|
APValue::LValueBase Base(Key, Index, Version);
|
||||||
LV.set(Base);
|
LV.set(Base);
|
||||||
return createLocal(Base, Key, T, Scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocate storage for a parameter of a function call made in this frame.
|
|
||||||
APValue &CallStackFrame::createParam(CallRef Args, const ParmVarDecl *PVD,
|
|
||||||
LValue &LV) {
|
|
||||||
assert(Args.CallIndex == Index && "creating parameter in wrong frame");
|
|
||||||
APValue::LValueBase Base(PVD, Index, Args.Version);
|
|
||||||
LV.set(Base);
|
|
||||||
// We always destroy parameters at the end of the call, even if we'd allow
|
|
||||||
// them to live to the end of the full-expression at runtime, in order to
|
|
||||||
// give portable results and match other compilers.
|
|
||||||
return createLocal(Base, PVD, PVD->getType(), ScopeKind::Call);
|
|
||||||
}
|
|
||||||
|
|
||||||
APValue &CallStackFrame::createLocal(APValue::LValueBase Base, const void *Key,
|
|
||||||
QualType T, ScopeKind Scope) {
|
|
||||||
assert(Base.getCallIndex() == Index && "lvalue for wrong frame");
|
|
||||||
unsigned Version = Base.getVersion();
|
|
||||||
APValue &Result = Temporaries[MapKeyTy(Key, Version)];
|
APValue &Result = Temporaries[MapKeyTy(Key, Version)];
|
||||||
assert(Result.isAbsent() && "local created multiple times");
|
assert(Result.isAbsent() && "temporary created multiple times");
|
||||||
|
|
||||||
// If we're creating a local immediately in the operand of a speculative
|
// If we're creating a temporary immediately in the operand of a speculative
|
||||||
// evaluation, don't register a cleanup to be run outside the speculative
|
// evaluation, don't register a cleanup to be run outside the speculative
|
||||||
// evaluation context, since we won't actually be able to initialize this
|
// evaluation context, since we won't actually be able to initialize this
|
||||||
// object.
|
// object.
|
||||||
|
@ -1889,7 +1810,7 @@ APValue &CallStackFrame::createLocal(APValue::LValueBase Base, const void *Key,
|
||||||
if (T.isDestructedType())
|
if (T.isDestructedType())
|
||||||
Info.noteSideEffect();
|
Info.noteSideEffect();
|
||||||
} else {
|
} else {
|
||||||
Info.CleanupStack.push_back(Cleanup(&Result, Base, T, Scope));
|
Info.CleanupStack.push_back(Cleanup(&Result, Base, T, IsLifetimeExtended));
|
||||||
}
|
}
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
@ -1935,11 +1856,12 @@ void CallStackFrame::describe(raw_ostream &Out) {
|
||||||
Out << ", ";
|
Out << ", ";
|
||||||
|
|
||||||
const ParmVarDecl *Param = *I;
|
const ParmVarDecl *Param = *I;
|
||||||
APValue *V = Info.getParamSlot(Arguments, Param);
|
if (Arguments) {
|
||||||
if (V)
|
const APValue &Arg = Arguments[ArgIndex];
|
||||||
V->printPretty(Out, Info.Ctx, Param->getType());
|
Arg.printPretty(Out, Info.Ctx, Param->getType());
|
||||||
else
|
} else {
|
||||||
Out << "<...>";
|
Out << "<...>";
|
||||||
|
}
|
||||||
|
|
||||||
if (ArgIndex == 0 && IsMemberCall)
|
if (ArgIndex == 0 && IsMemberCall)
|
||||||
Out << "->" << *Callee << '(';
|
Out << "->" << *Callee << '(';
|
||||||
|
@ -2070,22 +1992,6 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
|
||||||
static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
|
static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
|
||||||
assert(Base && "no location for a null lvalue");
|
assert(Base && "no location for a null lvalue");
|
||||||
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
|
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
|
||||||
|
|
||||||
// For a parameter, find the corresponding call stack frame (if it still
|
|
||||||
// exists), and point at the parameter of the function definition we actually
|
|
||||||
// invoked.
|
|
||||||
if (auto *PVD = dyn_cast_or_null<ParmVarDecl>(VD)) {
|
|
||||||
unsigned Idx = PVD->getFunctionScopeIndex();
|
|
||||||
for (CallStackFrame *F = Info.CurrentCall; F; F = F->Caller) {
|
|
||||||
if (F->Arguments.CallIndex == Base.getCallIndex() &&
|
|
||||||
F->Arguments.Version == Base.getVersion() && F->Callee &&
|
|
||||||
Idx < F->Callee->getNumParams()) {
|
|
||||||
VD = F->Callee->getParamDecl(Idx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VD)
|
if (VD)
|
||||||
Info.Note(VD->getLocation(), diag::note_declared_at);
|
Info.Note(VD->getLocation(), diag::note_declared_at);
|
||||||
else if (const Expr *E = Base.dyn_cast<const Expr*>())
|
else if (const Expr *E = Base.dyn_cast<const Expr*>())
|
||||||
|
@ -3171,22 +3077,33 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
|
||||||
/// \param Info Information about the ongoing evaluation.
|
/// \param Info Information about the ongoing evaluation.
|
||||||
/// \param E An expression to be used when printing diagnostics.
|
/// \param E An expression to be used when printing diagnostics.
|
||||||
/// \param VD The variable whose initializer should be obtained.
|
/// \param VD The variable whose initializer should be obtained.
|
||||||
/// \param Version The version of the variable within the frame.
|
|
||||||
/// \param Frame The frame in which the variable was created. Must be null
|
/// \param Frame The frame in which the variable was created. Must be null
|
||||||
/// if this variable is not local to the evaluation.
|
/// if this variable is not local to the evaluation.
|
||||||
/// \param Result Filled in with a pointer to the value of the variable.
|
/// \param Result Filled in with a pointer to the value of the variable.
|
||||||
static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
|
static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
|
||||||
const VarDecl *VD, CallStackFrame *Frame,
|
const VarDecl *VD, CallStackFrame *Frame,
|
||||||
unsigned Version, APValue *&Result) {
|
APValue *&Result, const LValue *LVal) {
|
||||||
APValue::LValueBase Base(VD, Frame ? Frame->Index : 0, Version);
|
|
||||||
|
// If this is a parameter to an active constexpr function call, perform
|
||||||
|
// argument substitution.
|
||||||
|
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
|
||||||
|
// Assume arguments of a potential constant expression are unknown
|
||||||
|
// constant expressions.
|
||||||
|
if (Info.checkingPotentialConstantExpression())
|
||||||
|
return false;
|
||||||
|
if (!Frame || !Frame->Arguments) {
|
||||||
|
Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << VD;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Result = &Frame->Arguments[PVD->getFunctionScopeIndex()];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// If this is a local variable, dig out its value.
|
// If this is a local variable, dig out its value.
|
||||||
if (Frame) {
|
if (Frame) {
|
||||||
Result = Frame->getTemporary(VD, Version);
|
Result = LVal ? Frame->getTemporary(VD, LVal->getLValueVersion())
|
||||||
if (Result)
|
: Frame->getCurrentTemporary(VD);
|
||||||
return true;
|
if (!Result) {
|
||||||
|
|
||||||
if (!isa<ParmVarDecl>(VD)) {
|
|
||||||
// Assume variables referenced within a lambda's call operator that were
|
// Assume variables referenced within a lambda's call operator that were
|
||||||
// not declared within the call operator are captures and during checking
|
// not declared within the call operator are captures and during checking
|
||||||
// of a potential constant expression, assume they are unknown constant
|
// of a potential constant expression, assume they are unknown constant
|
||||||
|
@ -3196,30 +3113,13 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
|
||||||
"missing value for local variable");
|
"missing value for local variable");
|
||||||
if (Info.checkingPotentialConstantExpression())
|
if (Info.checkingPotentialConstantExpression())
|
||||||
return false;
|
return false;
|
||||||
// FIXME: This diagnostic is bogus; we do support captures. Is this code
|
// FIXME: implement capture evaluation during constant expr evaluation.
|
||||||
// still reachable at all?
|
|
||||||
Info.FFDiag(E->getBeginLoc(),
|
Info.FFDiag(E->getBeginLoc(),
|
||||||
diag::note_unimplemented_constexpr_lambda_feature_ast)
|
diag::note_unimplemented_constexpr_lambda_feature_ast)
|
||||||
<< "captures not currently allowed";
|
<< "captures not currently allowed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
|
|
||||||
if (isa<ParmVarDecl>(VD)) {
|
|
||||||
// Assume parameters of a potential constant expression are usable in
|
|
||||||
// constant expressions.
|
|
||||||
if (!Info.checkingPotentialConstantExpression() ||
|
|
||||||
!Info.CurrentCall->Callee ||
|
|
||||||
!Info.CurrentCall->Callee->Equals(VD->getDeclContext())) {
|
|
||||||
if (Info.getLangOpts().CPlusPlus11) {
|
|
||||||
Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown)
|
|
||||||
<< VD;
|
|
||||||
NoteLValueLocation(Info, Base);
|
|
||||||
} else {
|
|
||||||
Info.FFDiag(E);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dig out the initializer, and use the declaration which it's attached to.
|
// Dig out the initializer, and use the declaration which it's attached to.
|
||||||
|
@ -3232,7 +3132,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
|
||||||
if (!Info.checkingPotentialConstantExpression()) {
|
if (!Info.checkingPotentialConstantExpression()) {
|
||||||
Info.FFDiag(E, diag::note_constexpr_var_init_unknown, 1)
|
Info.FFDiag(E, diag::note_constexpr_var_init_unknown, 1)
|
||||||
<< VD;
|
<< VD;
|
||||||
NoteLValueLocation(Info, Base);
|
Info.Note(VD->getLocation(), diag::note_declared_at);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3249,7 +3149,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
|
||||||
? diag::note_constexpr_ltor_non_constexpr
|
? diag::note_constexpr_ltor_non_constexpr
|
||||||
: diag::note_constexpr_ltor_non_integral, 1)
|
: diag::note_constexpr_ltor_non_integral, 1)
|
||||||
<< VD << VD->getType();
|
<< VD << VD->getType();
|
||||||
NoteLValueLocation(Info, Base);
|
Info.Note(VD->getLocation(), diag::note_declared_at);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3268,7 +3168,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
|
||||||
if (!VD->evaluateValue(Notes)) {
|
if (!VD->evaluateValue(Notes)) {
|
||||||
Info.FFDiag(E, diag::note_constexpr_var_init_non_constant,
|
Info.FFDiag(E, diag::note_constexpr_var_init_non_constant,
|
||||||
Notes.size() + 1) << VD;
|
Notes.size() + 1) << VD;
|
||||||
NoteLValueLocation(Info, Base);
|
Info.Note(VD->getLocation(), diag::note_declared_at);
|
||||||
Info.addNotes(Notes);
|
Info.addNotes(Notes);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3277,7 +3177,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
|
||||||
if (!VD->checkInitIsICE()) {
|
if (!VD->checkInitIsICE()) {
|
||||||
Info.CCEDiag(E, diag::note_constexpr_var_init_non_constant,
|
Info.CCEDiag(E, diag::note_constexpr_var_init_non_constant,
|
||||||
Notes.size() + 1) << VD;
|
Notes.size() + 1) << VD;
|
||||||
NoteLValueLocation(Info, Base);
|
Info.Note(VD->getLocation(), diag::note_declared_at);
|
||||||
Info.addNotes(Notes);
|
Info.addNotes(Notes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3285,7 +3185,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
|
||||||
// folding. We can't be sure that this is the definition that will be used.
|
// folding. We can't be sure that this is the definition that will be used.
|
||||||
if (VD->isWeak()) {
|
if (VD->isWeak()) {
|
||||||
Info.FFDiag(E, diag::note_constexpr_var_init_weak) << VD;
|
Info.FFDiag(E, diag::note_constexpr_var_init_weak) << VD;
|
||||||
NoteLValueLocation(Info, Base);
|
Info.Note(VD->getLocation(), diag::note_declared_at);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3999,10 +3899,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
|
||||||
// Unless we're looking at a local variable or argument in a constexpr call,
|
// Unless we're looking at a local variable or argument in a constexpr call,
|
||||||
// the variable we're reading must be const.
|
// the variable we're reading must be const.
|
||||||
if (!Frame) {
|
if (!Frame) {
|
||||||
if (isa<ParmVarDecl>(VD)) {
|
if (Info.getLangOpts().CPlusPlus14 &&
|
||||||
// Allow evaluateVarDeclInit to diagnose this (or permit it during
|
|
||||||
// potential constant expression checking).
|
|
||||||
} else if (Info.getLangOpts().CPlusPlus14 &&
|
|
||||||
lifetimeStartedInEvaluation(Info, LVal.Base)) {
|
lifetimeStartedInEvaluation(Info, LVal.Base)) {
|
||||||
// OK, we can read and modify an object if we're in the process of
|
// OK, we can read and modify an object if we're in the process of
|
||||||
// evaluating its initializer, because its lifetime began in this
|
// evaluating its initializer, because its lifetime began in this
|
||||||
|
@ -4060,7 +3957,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
|
if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal, &LVal))
|
||||||
return CompleteObject();
|
return CompleteObject();
|
||||||
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
|
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
|
||||||
Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA);
|
Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA);
|
||||||
|
@ -4129,19 +4026,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
|
||||||
}
|
}
|
||||||
|
|
||||||
// In C++14, we can't safely access any mutable state when we might be
|
// In C++14, we can't safely access any mutable state when we might be
|
||||||
// evaluating after an unmodeled side effect. Parameters are modeled as state
|
// evaluating after an unmodeled side effect.
|
||||||
// in the caller, but aren't visible once the call returns, so they can be
|
|
||||||
// modified in a speculatively-evaluated call.
|
|
||||||
//
|
//
|
||||||
// FIXME: Not all local state is mutable. Allow local constant subobjects
|
// FIXME: Not all local state is mutable. Allow local constant subobjects
|
||||||
// to be read here (but take care with 'mutable' fields).
|
// to be read here (but take care with 'mutable' fields).
|
||||||
unsigned VisibleDepth = Depth;
|
|
||||||
if (llvm::isa_and_nonnull<ParmVarDecl>(
|
|
||||||
LVal.Base.dyn_cast<const ValueDecl *>()))
|
|
||||||
++VisibleDepth;
|
|
||||||
if ((Frame && Info.getLangOpts().CPlusPlus14 &&
|
if ((Frame && Info.getLangOpts().CPlusPlus14 &&
|
||||||
Info.EvalStatus.HasSideEffects) ||
|
Info.EvalStatus.HasSideEffects) ||
|
||||||
(isModification(AK) && VisibleDepth < Info.SpeculativeEvaluationDepth))
|
(isModification(AK) && Depth < Info.SpeculativeEvaluationDepth))
|
||||||
return CompleteObject();
|
return CompleteObject();
|
||||||
|
|
||||||
return CompleteObject(LVal.getLValueBase(), BaseVal, BaseType);
|
return CompleteObject(LVal.getLValueBase(), BaseVal, BaseType);
|
||||||
|
@ -4752,8 +4643,8 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
LValue Result;
|
LValue Result;
|
||||||
APValue &Val = Info.CurrentCall->createTemporary(VD, VD->getType(),
|
APValue &Val =
|
||||||
ScopeKind::Block, Result);
|
Info.CurrentCall->createTemporary(VD, VD->getType(), true, Result);
|
||||||
|
|
||||||
const Expr *InitE = VD->getInit();
|
const Expr *InitE = VD->getInit();
|
||||||
if (!InitE)
|
if (!InitE)
|
||||||
|
@ -5898,35 +5789,15 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool EvaluateCallArg(const ParmVarDecl *PVD, const Expr *Arg,
|
namespace {
|
||||||
CallRef Call, EvalInfo &Info,
|
typedef SmallVector<APValue, 8> ArgVector;
|
||||||
bool NonNull = false) {
|
|
||||||
LValue LV;
|
|
||||||
// Create the parameter slot and register its destruction. For a vararg
|
|
||||||
// argument, create a temporary.
|
|
||||||
// FIXME: For calling conventions that destroy parameters in the callee,
|
|
||||||
// should we consider performing destruction when the function returns
|
|
||||||
// instead?
|
|
||||||
APValue &V = PVD ? Info.CurrentCall->createParam(Call, PVD, LV)
|
|
||||||
: Info.CurrentCall->createTemporary(Arg, Arg->getType(),
|
|
||||||
ScopeKind::Call, LV);
|
|
||||||
if (!EvaluateInPlace(V, Info, LV, Arg))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Passing a null pointer to an __attribute__((nonnull)) parameter results in
|
|
||||||
// undefined behavior, so is non-constant.
|
|
||||||
if (NonNull && V.isLValue() && V.isNullPointer()) {
|
|
||||||
Info.CCEDiag(Arg, diag::note_non_null_attribute_failed);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
/// EvaluateArgs - Evaluate the arguments to a function call.
|
||||||
}
|
static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues,
|
||||||
|
EvalInfo &Info, const FunctionDecl *Callee) {
|
||||||
|
ArgValues.resize(Args.size());
|
||||||
|
|
||||||
/// Evaluate the arguments to a function call.
|
|
||||||
static bool EvaluateArgs(ArrayRef<const Expr *> Args, CallRef Call,
|
|
||||||
EvalInfo &Info, const FunctionDecl *Callee,
|
|
||||||
bool RightToLeft = false) {
|
|
||||||
bool Success = true;
|
bool Success = true;
|
||||||
llvm::SmallBitVector ForbiddenNullArgs;
|
llvm::SmallBitVector ForbiddenNullArgs;
|
||||||
if (Callee->hasAttr<NonNullAttr>()) {
|
if (Callee->hasAttr<NonNullAttr>()) {
|
||||||
|
@ -5944,53 +5815,36 @@ static bool EvaluateArgs(ArrayRef<const Expr *> Args, CallRef Call,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (unsigned I = 0; I < Args.size(); I++) {
|
for (unsigned Idx = 0; Idx < Args.size(); Idx++) {
|
||||||
unsigned Idx = RightToLeft ? Args.size() - I - 1 : I;
|
if (!Evaluate(ArgValues[Idx], Info, Args[Idx])) {
|
||||||
const ParmVarDecl *PVD =
|
|
||||||
Idx < Callee->getNumParams() ? Callee->getParamDecl(Idx) : nullptr;
|
|
||||||
bool NonNull = !ForbiddenNullArgs.empty() && ForbiddenNullArgs[Idx];
|
|
||||||
if (!EvaluateCallArg(PVD, Args[Idx], Call, Info, NonNull)) {
|
|
||||||
// If we're checking for a potential constant expression, evaluate all
|
// If we're checking for a potential constant expression, evaluate all
|
||||||
// initializers even if some of them fail.
|
// initializers even if some of them fail.
|
||||||
if (!Info.noteFailure())
|
if (!Info.noteFailure())
|
||||||
return false;
|
return false;
|
||||||
Success = false;
|
Success = false;
|
||||||
|
} else if (!ForbiddenNullArgs.empty() &&
|
||||||
|
ForbiddenNullArgs[Idx] &&
|
||||||
|
ArgValues[Idx].isLValue() &&
|
||||||
|
ArgValues[Idx].isNullPointer()) {
|
||||||
|
Info.CCEDiag(Args[Idx], diag::note_non_null_attribute_failed);
|
||||||
|
if (!Info.noteFailure())
|
||||||
|
return false;
|
||||||
|
Success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform a trivial copy from Param, which is the parameter of a copy or move
|
|
||||||
/// constructor or assignment operator.
|
|
||||||
static bool handleTrivialCopy(EvalInfo &Info, const ParmVarDecl *Param,
|
|
||||||
const Expr *E, APValue &Result,
|
|
||||||
bool CopyObjectRepresentation) {
|
|
||||||
// Find the reference argument.
|
|
||||||
CallStackFrame *Frame = Info.CurrentCall;
|
|
||||||
APValue *RefValue = Info.getParamSlot(Frame->Arguments, Param);
|
|
||||||
if (!RefValue) {
|
|
||||||
Info.FFDiag(E);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy out the contents of the RHS object.
|
|
||||||
LValue RefLValue;
|
|
||||||
RefLValue.setFrom(Info.Ctx, *RefValue);
|
|
||||||
return handleLValueToRValueConversion(
|
|
||||||
Info, E, Param->getType().getNonReferenceType(), RefLValue, Result,
|
|
||||||
CopyObjectRepresentation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluate a function call.
|
/// Evaluate a function call.
|
||||||
static bool HandleFunctionCall(SourceLocation CallLoc,
|
static bool HandleFunctionCall(SourceLocation CallLoc,
|
||||||
const FunctionDecl *Callee, const LValue *This,
|
const FunctionDecl *Callee, const LValue *This,
|
||||||
ArrayRef<const Expr *> Args, CallRef Call,
|
ArrayRef<const Expr *> Args, APValue *ArgValues,
|
||||||
const Stmt *Body, EvalInfo &Info,
|
const Stmt *Body, EvalInfo &Info,
|
||||||
APValue &Result, const LValue *ResultSlot) {
|
APValue &Result, const LValue *ResultSlot) {
|
||||||
if (!Info.CheckCallLimit(CallLoc))
|
if (!Info.CheckCallLimit(CallLoc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CallStackFrame Frame(Info, CallLoc, Callee, This, Call);
|
CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues);
|
||||||
|
|
||||||
// For a trivial copy or move assignment, perform an APValue copy. This is
|
// For a trivial copy or move assignment, perform an APValue copy. This is
|
||||||
// essential for unions, where the operations performed by the assignment
|
// essential for unions, where the operations performed by the assignment
|
||||||
|
@ -6005,9 +5859,11 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
|
||||||
isReadByLvalueToRvalueConversion(MD->getParent())))) {
|
isReadByLvalueToRvalueConversion(MD->getParent())))) {
|
||||||
assert(This &&
|
assert(This &&
|
||||||
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
|
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
|
||||||
|
LValue RHS;
|
||||||
|
RHS.setFrom(Info.Ctx, ArgValues[0]);
|
||||||
APValue RHSValue;
|
APValue RHSValue;
|
||||||
if (!handleTrivialCopy(Info, MD->getParamDecl(0), Args[0], RHSValue,
|
if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), RHS,
|
||||||
MD->getParent()->isUnion()))
|
RHSValue, MD->getParent()->isUnion()))
|
||||||
return false;
|
return false;
|
||||||
if (Info.getLangOpts().CPlusPlus20 && MD->isTrivial() &&
|
if (Info.getLangOpts().CPlusPlus20 && MD->isTrivial() &&
|
||||||
!HandleUnionActiveMemberChange(Info, Args[0], *This))
|
!HandleUnionActiveMemberChange(Info, Args[0], *This))
|
||||||
|
@ -6041,7 +5897,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
|
||||||
|
|
||||||
/// Evaluate a constructor call.
|
/// Evaluate a constructor call.
|
||||||
static bool HandleConstructorCall(const Expr *E, const LValue &This,
|
static bool HandleConstructorCall(const Expr *E, const LValue &This,
|
||||||
CallRef Call,
|
APValue *ArgValues,
|
||||||
const CXXConstructorDecl *Definition,
|
const CXXConstructorDecl *Definition,
|
||||||
EvalInfo &Info, APValue &Result) {
|
EvalInfo &Info, APValue &Result) {
|
||||||
SourceLocation CallLoc = E->getExprLoc();
|
SourceLocation CallLoc = E->getExprLoc();
|
||||||
|
@ -6058,7 +5914,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
|
||||||
Info,
|
Info,
|
||||||
ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries},
|
ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries},
|
||||||
RD->getNumBases());
|
RD->getNumBases());
|
||||||
CallStackFrame Frame(Info, CallLoc, Definition, &This, Call);
|
CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues);
|
||||||
|
|
||||||
// FIXME: Creating an APValue just to hold a nonexistent return value is
|
// FIXME: Creating an APValue just to hold a nonexistent return value is
|
||||||
// wasteful.
|
// wasteful.
|
||||||
|
@ -6089,8 +5945,11 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
|
||||||
(Definition->getParent()->isUnion() ||
|
(Definition->getParent()->isUnion() ||
|
||||||
(Definition->isTrivial() &&
|
(Definition->isTrivial() &&
|
||||||
isReadByLvalueToRvalueConversion(Definition->getParent())))) {
|
isReadByLvalueToRvalueConversion(Definition->getParent())))) {
|
||||||
return handleTrivialCopy(Info, Definition->getParamDecl(0), E, Result,
|
LValue RHS;
|
||||||
Definition->getParent()->isUnion());
|
RHS.setFrom(Info.Ctx, ArgValues[0]);
|
||||||
|
return handleLValueToRValueConversion(
|
||||||
|
Info, E, Definition->getParamDecl(0)->getType().getNonReferenceType(),
|
||||||
|
RHS, Result, Definition->getParent()->isUnion());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve space for the struct members.
|
// Reserve space for the struct members.
|
||||||
|
@ -6249,13 +6108,12 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
|
||||||
ArrayRef<const Expr*> Args,
|
ArrayRef<const Expr*> Args,
|
||||||
const CXXConstructorDecl *Definition,
|
const CXXConstructorDecl *Definition,
|
||||||
EvalInfo &Info, APValue &Result) {
|
EvalInfo &Info, APValue &Result) {
|
||||||
CallScopeRAII CallScope(Info);
|
ArgVector ArgValues(Args.size());
|
||||||
CallRef Call = Info.CurrentCall->createCall(Definition);
|
if (!EvaluateArgs(Args, ArgValues, Info, Definition))
|
||||||
if (!EvaluateArgs(Args, Call, Info, Definition))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return HandleConstructorCall(E, This, Call, Definition, Info, Result) &&
|
return HandleConstructorCall(E, This, ArgValues.data(), Definition,
|
||||||
CallScope.destroy();
|
Info, Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool HandleDestructionImpl(EvalInfo &Info, SourceLocation CallLoc,
|
static bool HandleDestructionImpl(EvalInfo &Info, SourceLocation CallLoc,
|
||||||
|
@ -6351,7 +6209,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceLocation CallLoc,
|
||||||
if (!CheckConstexprFunction(Info, CallLoc, DD, Definition, Body))
|
if (!CheckConstexprFunction(Info, CallLoc, DD, Definition, Body))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CallStackFrame Frame(Info, CallLoc, Definition, &This, CallRef());
|
CallStackFrame Frame(Info, CallLoc, Definition, &This, nullptr);
|
||||||
|
|
||||||
// We're now in the period of destruction of this object.
|
// We're now in the period of destruction of this object.
|
||||||
unsigned BasesLeft = RD->getNumBases();
|
unsigned BasesLeft = RD->getNumBases();
|
||||||
|
@ -7339,8 +7197,8 @@ public:
|
||||||
LValue CommonLV;
|
LValue CommonLV;
|
||||||
if (!Evaluate(Info.CurrentCall->createTemporary(
|
if (!Evaluate(Info.CurrentCall->createTemporary(
|
||||||
E->getOpaqueValue(),
|
E->getOpaqueValue(),
|
||||||
getStorageType(Info.Ctx, E->getOpaqueValue()),
|
getStorageType(Info.Ctx, E->getOpaqueValue()), false,
|
||||||
ScopeKind::FullExpression, CommonLV),
|
CommonLV),
|
||||||
Info, E->getCommon()))
|
Info, E->getCommon()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -7404,8 +7262,7 @@ public:
|
||||||
|
|
||||||
LValue LV;
|
LValue LV;
|
||||||
if (!Evaluate(Info.CurrentCall->createTemporary(
|
if (!Evaluate(Info.CurrentCall->createTemporary(
|
||||||
OVE, getStorageType(Info.Ctx, OVE),
|
OVE, getStorageType(Info.Ctx, OVE), false, LV),
|
||||||
ScopeKind::FullExpression, LV),
|
|
||||||
Info, OVE->getSourceExpr()))
|
Info, OVE->getSourceExpr()))
|
||||||
return false;
|
return false;
|
||||||
} else if (SemE == E->getResultExpr()) {
|
} else if (SemE == E->getResultExpr()) {
|
||||||
|
@ -7428,8 +7285,6 @@ public:
|
||||||
|
|
||||||
bool handleCallExpr(const CallExpr *E, APValue &Result,
|
bool handleCallExpr(const CallExpr *E, APValue &Result,
|
||||||
const LValue *ResultSlot) {
|
const LValue *ResultSlot) {
|
||||||
CallScopeRAII CallScope(Info);
|
|
||||||
|
|
||||||
const Expr *Callee = E->getCallee()->IgnoreParens();
|
const Expr *Callee = E->getCallee()->IgnoreParens();
|
||||||
QualType CalleeType = Callee->getType();
|
QualType CalleeType = Callee->getType();
|
||||||
|
|
||||||
|
@ -7438,8 +7293,7 @@ public:
|
||||||
auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
|
auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
|
||||||
bool HasQualifier = false;
|
bool HasQualifier = false;
|
||||||
|
|
||||||
CallRef Call;
|
ArgVector ArgValues;
|
||||||
bool EvaluatedArgs = false;
|
|
||||||
|
|
||||||
// Extract function decl and 'this' pointer from the callee.
|
// Extract function decl and 'this' pointer from the callee.
|
||||||
if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
|
if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
|
||||||
|
@ -7472,14 +7326,14 @@ public:
|
||||||
return Error(Callee);
|
return Error(Callee);
|
||||||
FD = Member;
|
FD = Member;
|
||||||
} else if (CalleeType->isFunctionPointerType()) {
|
} else if (CalleeType->isFunctionPointerType()) {
|
||||||
LValue CalleeLV;
|
LValue Call;
|
||||||
if (!EvaluatePointer(Callee, CalleeLV, Info))
|
if (!EvaluatePointer(Callee, Call, Info))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!CalleeLV.getLValueOffset().isZero())
|
if (!Call.getLValueOffset().isZero())
|
||||||
return Error(Callee);
|
return Error(Callee);
|
||||||
FD = dyn_cast_or_null<FunctionDecl>(
|
FD = dyn_cast_or_null<FunctionDecl>(
|
||||||
CalleeLV.getLValueBase().dyn_cast<const ValueDecl *>());
|
Call.getLValueBase().dyn_cast<const ValueDecl*>());
|
||||||
if (!FD)
|
if (!FD)
|
||||||
return Error(Callee);
|
return Error(Callee);
|
||||||
// Don't call function pointers which have been cast to some other type.
|
// Don't call function pointers which have been cast to some other type.
|
||||||
|
@ -7494,11 +7348,15 @@ public:
|
||||||
auto *OCE = dyn_cast<CXXOperatorCallExpr>(E);
|
auto *OCE = dyn_cast<CXXOperatorCallExpr>(E);
|
||||||
if (OCE && OCE->isAssignmentOp()) {
|
if (OCE && OCE->isAssignmentOp()) {
|
||||||
assert(Args.size() == 2 && "wrong number of arguments in assignment");
|
assert(Args.size() == 2 && "wrong number of arguments in assignment");
|
||||||
Call = Info.CurrentCall->createCall(FD);
|
if (isa<CXXMethodDecl>(FD)) {
|
||||||
if (!EvaluateArgs(isa<CXXMethodDecl>(FD) ? Args.slice(1) : Args, Call,
|
// Args[0] is the object argument.
|
||||||
Info, FD, /*RightToLeft=*/true))
|
if (!EvaluateArgs({Args[1]}, ArgValues, Info, FD))
|
||||||
return false;
|
return false;
|
||||||
EvaluatedArgs = true;
|
} else {
|
||||||
|
if (!EvaluateArgs({Args[1], Args[0]}, ArgValues, Info, FD))
|
||||||
|
return false;
|
||||||
|
std::swap(ArgValues[0], ArgValues[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overloaded operator calls to member functions are represented as normal
|
// Overloaded operator calls to member functions are represented as normal
|
||||||
|
@ -7555,20 +7413,18 @@ public:
|
||||||
if (!HandleOperatorNewCall(Info, E, Ptr))
|
if (!HandleOperatorNewCall(Info, E, Ptr))
|
||||||
return false;
|
return false;
|
||||||
Ptr.moveInto(Result);
|
Ptr.moveInto(Result);
|
||||||
return CallScope.destroy();
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return HandleOperatorDeleteCall(Info, E) && CallScope.destroy();
|
return HandleOperatorDeleteCall(Info, E);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
return Error(E);
|
return Error(E);
|
||||||
|
|
||||||
// Evaluate the arguments now if we've not already done so.
|
// Evaluate the arguments now if we've not already done so.
|
||||||
if (!Call) {
|
if (ArgValues.empty() && !Args.empty() &&
|
||||||
Call = Info.CurrentCall->createCall(FD);
|
!EvaluateArgs(Args, ArgValues, Info, FD))
|
||||||
if (!EvaluateArgs(Args, Call, Info, FD))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
SmallVector<QualType, 4> CovariantAdjustmentPath;
|
SmallVector<QualType, 4> CovariantAdjustmentPath;
|
||||||
if (This) {
|
if (This) {
|
||||||
|
@ -7591,17 +7447,17 @@ public:
|
||||||
// Destructor calls are different enough that they have their own codepath.
|
// Destructor calls are different enough that they have their own codepath.
|
||||||
if (auto *DD = dyn_cast<CXXDestructorDecl>(FD)) {
|
if (auto *DD = dyn_cast<CXXDestructorDecl>(FD)) {
|
||||||
assert(This && "no 'this' pointer for destructor call");
|
assert(This && "no 'this' pointer for destructor call");
|
||||||
|
assert(ArgValues.empty() && "unexpected destructor arguments");
|
||||||
return HandleDestruction(Info, E, *This,
|
return HandleDestruction(Info, E, *This,
|
||||||
Info.Ctx.getRecordType(DD->getParent())) &&
|
Info.Ctx.getRecordType(DD->getParent()));
|
||||||
CallScope.destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FunctionDecl *Definition = nullptr;
|
const FunctionDecl *Definition = nullptr;
|
||||||
Stmt *Body = FD->getBody(Definition);
|
Stmt *Body = FD->getBody(Definition);
|
||||||
|
|
||||||
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) ||
|
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) ||
|
||||||
!HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Call,
|
!HandleFunctionCall(E->getExprLoc(), Definition, This, Args,
|
||||||
Body, Info, Result, ResultSlot))
|
ArgValues.data(), Body, Info, Result, ResultSlot))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!CovariantAdjustmentPath.empty() &&
|
if (!CovariantAdjustmentPath.empty() &&
|
||||||
|
@ -7609,7 +7465,7 @@ public:
|
||||||
CovariantAdjustmentPath))
|
CovariantAdjustmentPath))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return CallScope.destroy();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
|
bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
|
||||||
|
@ -8073,45 +7929,31 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CallStackFrame *Frame = nullptr;
|
CallStackFrame *Frame = nullptr;
|
||||||
unsigned Version = 0;
|
if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) {
|
||||||
if (VD->hasLocalStorage()) {
|
|
||||||
// Only if a local variable was declared in the function currently being
|
// Only if a local variable was declared in the function currently being
|
||||||
// evaluated, do we expect to be able to find its value in the current
|
// evaluated, do we expect to be able to find its value in the current
|
||||||
// frame. (Otherwise it was likely declared in an enclosing context and
|
// frame. (Otherwise it was likely declared in an enclosing context and
|
||||||
// could either have a valid evaluatable value (for e.g. a constexpr
|
// could either have a valid evaluatable value (for e.g. a constexpr
|
||||||
// variable) or be ill-formed (and trigger an appropriate evaluation
|
// variable) or be ill-formed (and trigger an appropriate evaluation
|
||||||
// diagnostic)).
|
// diagnostic)).
|
||||||
CallStackFrame *CurrFrame = Info.CurrentCall;
|
if (Info.CurrentCall->Callee &&
|
||||||
if (CurrFrame->Callee && CurrFrame->Callee->Equals(VD->getDeclContext())) {
|
Info.CurrentCall->Callee->Equals(VD->getDeclContext())) {
|
||||||
// Function parameters are stored in some caller's frame. (Usually the
|
Frame = Info.CurrentCall;
|
||||||
// immediate caller, but for an inherited constructor they may be more
|
|
||||||
// distant.)
|
|
||||||
if (auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
|
|
||||||
if (CurrFrame->Arguments) {
|
|
||||||
VD = CurrFrame->Arguments.getOrigParam(PVD);
|
|
||||||
Frame =
|
|
||||||
Info.getCallFrameAndDepth(CurrFrame->Arguments.CallIndex).first;
|
|
||||||
Version = CurrFrame->Arguments.Version;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Frame = CurrFrame;
|
|
||||||
Version = CurrFrame->getCurrentTemporaryVersion(VD);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!VD->getType()->isReferenceType()) {
|
if (!VD->getType()->isReferenceType()) {
|
||||||
if (Frame) {
|
if (Frame) {
|
||||||
Result.set({VD, Frame->Index, Version});
|
Result.set({VD, Frame->Index,
|
||||||
|
Info.CurrentCall->getCurrentTemporaryVersion(VD)});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return Success(VD);
|
return Success(VD);
|
||||||
}
|
}
|
||||||
|
|
||||||
APValue *V;
|
APValue *V;
|
||||||
if (!evaluateVarDeclInit(Info, E, VD, Frame, Version, V))
|
if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr))
|
||||||
return false;
|
return false;
|
||||||
if (!V->hasValue()) {
|
if (!V->hasValue()) {
|
||||||
// FIXME: Is it possible for V to be indeterminate here? If so, we should
|
// FIXME: Is it possible for V to be indeterminate here? If so, we should
|
||||||
|
@ -8141,16 +7983,12 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
|
||||||
// value for use outside this evaluation.
|
// value for use outside this evaluation.
|
||||||
APValue *Value;
|
APValue *Value;
|
||||||
if (E->getStorageDuration() == SD_Static) {
|
if (E->getStorageDuration() == SD_Static) {
|
||||||
// FIXME: What about SD_Thread?
|
|
||||||
Value = E->getOrCreateValue(true);
|
Value = E->getOrCreateValue(true);
|
||||||
*Value = APValue();
|
*Value = APValue();
|
||||||
Result.set(E);
|
Result.set(E);
|
||||||
} else {
|
} else {
|
||||||
Value = &Info.CurrentCall->createTemporary(
|
Value = &Info.CurrentCall->createTemporary(
|
||||||
E, E->getType(),
|
E, E->getType(), E->getStorageDuration() == SD_Automatic, Result);
|
||||||
E->getStorageDuration() == SD_FullExpression ? ScopeKind::FullExpression
|
|
||||||
: ScopeKind::Block,
|
|
||||||
Result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType Type = Inner->getType();
|
QualType Type = Inner->getType();
|
||||||
|
@ -8704,7 +8542,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
APValue &Value = Info.CurrentCall->createTemporary(
|
APValue &Value = Info.CurrentCall->createTemporary(
|
||||||
SubExpr, SubExpr->getType(), ScopeKind::FullExpression, Result);
|
SubExpr, SubExpr->getType(), false, Result);
|
||||||
if (!EvaluateInPlace(Value, Info, Result, SubExpr))
|
if (!EvaluateInPlace(Value, Info, Result, SubExpr))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -9957,8 +9795,8 @@ public:
|
||||||
|
|
||||||
/// Visit an expression which constructs the value of this temporary.
|
/// Visit an expression which constructs the value of this temporary.
|
||||||
bool VisitConstructExpr(const Expr *E) {
|
bool VisitConstructExpr(const Expr *E) {
|
||||||
APValue &Value = Info.CurrentCall->createTemporary(
|
APValue &Value =
|
||||||
E, E->getType(), ScopeKind::FullExpression, Result);
|
Info.CurrentCall->createTemporary(E, E->getType(), false, Result);
|
||||||
return EvaluateInPlace(Value, Info, Result, E);
|
return EvaluateInPlace(Value, Info, Result, E);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10395,8 +10233,8 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
|
||||||
if (E->getCommonExpr() &&
|
if (E->getCommonExpr() &&
|
||||||
!Evaluate(Info.CurrentCall->createTemporary(
|
!Evaluate(Info.CurrentCall->createTemporary(
|
||||||
E->getCommonExpr(),
|
E->getCommonExpr(),
|
||||||
getStorageType(Info.Ctx, E->getCommonExpr()),
|
getStorageType(Info.Ctx, E->getCommonExpr()), false,
|
||||||
ScopeKind::FullExpression, CommonLV),
|
CommonLV),
|
||||||
Info, E->getCommonExpr()->getSourceExpr()))
|
Info, E->getCommonExpr()->getSourceExpr()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -14388,14 +14226,13 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
|
||||||
} else if (T->isArrayType()) {
|
} else if (T->isArrayType()) {
|
||||||
LValue LV;
|
LValue LV;
|
||||||
APValue &Value =
|
APValue &Value =
|
||||||
Info.CurrentCall->createTemporary(E, T, ScopeKind::FullExpression, LV);
|
Info.CurrentCall->createTemporary(E, T, false, LV);
|
||||||
if (!EvaluateArray(E, LV, Value, Info))
|
if (!EvaluateArray(E, LV, Value, Info))
|
||||||
return false;
|
return false;
|
||||||
Result = Value;
|
Result = Value;
|
||||||
} else if (T->isRecordType()) {
|
} else if (T->isRecordType()) {
|
||||||
LValue LV;
|
LValue LV;
|
||||||
APValue &Value =
|
APValue &Value = Info.CurrentCall->createTemporary(E, T, false, LV);
|
||||||
Info.CurrentCall->createTemporary(E, T, ScopeKind::FullExpression, LV);
|
|
||||||
if (!EvaluateRecord(E, LV, Value, Info))
|
if (!EvaluateRecord(E, LV, Value, Info))
|
||||||
return false;
|
return false;
|
||||||
Result = Value;
|
Result = Value;
|
||||||
|
@ -14409,8 +14246,7 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
|
||||||
QualType Unqual = T.getAtomicUnqualifiedType();
|
QualType Unqual = T.getAtomicUnqualifiedType();
|
||||||
if (Unqual->isArrayType() || Unqual->isRecordType()) {
|
if (Unqual->isArrayType() || Unqual->isRecordType()) {
|
||||||
LValue LV;
|
LValue LV;
|
||||||
APValue &Value = Info.CurrentCall->createTemporary(
|
APValue &Value = Info.CurrentCall->createTemporary(E, Unqual, false, LV);
|
||||||
E, Unqual, ScopeKind::FullExpression, LV);
|
|
||||||
if (!EvaluateAtomic(E, &LV, Value, Info))
|
if (!EvaluateAtomic(E, &LV, Value, Info))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -15419,20 +15255,14 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
|
||||||
Info.EvalStatus.HasSideEffects = false;
|
Info.EvalStatus.HasSideEffects = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallRef Call = Info.CurrentCall->createCall(Callee);
|
ArgVector ArgValues(Args.size());
|
||||||
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
|
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
unsigned Idx = I - Args.begin();
|
|
||||||
if (Idx >= Callee->getNumParams())
|
|
||||||
break;
|
|
||||||
const ParmVarDecl *PVD = Callee->getParamDecl(Idx);
|
|
||||||
if ((*I)->isValueDependent() ||
|
if ((*I)->isValueDependent() ||
|
||||||
!EvaluateCallArg(PVD, *I, Call, Info) ||
|
!Evaluate(ArgValues[I - Args.begin()], Info, *I) ||
|
||||||
Info.EvalStatus.HasSideEffects) {
|
Info.EvalStatus.HasSideEffects)
|
||||||
// If evaluation fails, throw away the argument entirely.
|
// If evaluation fails, throw away the argument entirely.
|
||||||
if (APValue *Slot = Info.getParamSlot(Call, PVD))
|
ArgValues[I - Args.begin()] = APValue();
|
||||||
*Slot = APValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore any side-effects from a failed evaluation. This is safe because
|
// Ignore any side-effects from a failed evaluation. This is safe because
|
||||||
// they can't interfere with any other argument evaluation.
|
// they can't interfere with any other argument evaluation.
|
||||||
|
@ -15445,7 +15275,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
|
||||||
Info.EvalStatus.HasSideEffects = false;
|
Info.EvalStatus.HasSideEffects = false;
|
||||||
|
|
||||||
// Build fake call to Callee.
|
// Build fake call to Callee.
|
||||||
CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr, Call);
|
CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr,
|
||||||
|
ArgValues.data());
|
||||||
// FIXME: Missing ExprWithCleanups in enable_if conditions?
|
// FIXME: Missing ExprWithCleanups in enable_if conditions?
|
||||||
FullExpressionRAII Scope(Info);
|
FullExpressionRAII Scope(Info);
|
||||||
return Evaluate(Value, Info, this) && Scope.destroy() &&
|
return Evaluate(Value, Info, this) && Scope.destroy() &&
|
||||||
|
@ -15503,7 +15334,8 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
|
||||||
} else {
|
} else {
|
||||||
SourceLocation Loc = FD->getLocation();
|
SourceLocation Loc = FD->getLocation();
|
||||||
HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr,
|
HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr,
|
||||||
Args, CallRef(), FD->getBody(), Info, Scratch, nullptr);
|
Args, /*ArgValues*/ nullptr, FD->getBody(), Info,
|
||||||
|
Scratch, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Diags.empty();
|
return Diags.empty();
|
||||||
|
@ -15525,7 +15357,8 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
|
||||||
Info.CheckingPotentialConstantExpression = true;
|
Info.CheckingPotentialConstantExpression = true;
|
||||||
|
|
||||||
// Fabricate a call stack frame to give the arguments a plausible cover story.
|
// Fabricate a call stack frame to give the arguments a plausible cover story.
|
||||||
CallStackFrame Frame(Info, SourceLocation(), FD, /*This*/ nullptr, CallRef());
|
CallStackFrame Frame(Info, SourceLocation(), FD, /*This*/ nullptr,
|
||||||
|
/*ArgValues*/ nullptr);
|
||||||
|
|
||||||
APValue ResultScratch;
|
APValue ResultScratch;
|
||||||
Evaluate(ResultScratch, Info, E);
|
Evaluate(ResultScratch, Info, E);
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace M {
|
||||||
|
|
||||||
struct NonLiteral {
|
struct NonLiteral {
|
||||||
NonLiteral() {}
|
NonLiteral() {}
|
||||||
NonLiteral(int) {}
|
NonLiteral(int) {} // expected-note 2{{here}}
|
||||||
operator int() const { return 0; }
|
operator int() const { return 0; }
|
||||||
};
|
};
|
||||||
struct Literal {
|
struct Literal {
|
||||||
|
@ -42,8 +42,8 @@ template<typename ...P> struct ConstexprCtor {
|
||||||
};
|
};
|
||||||
constexpr ConstexprCtor<> f1() { return {}; } // ok
|
constexpr ConstexprCtor<> f1() { return {}; } // ok
|
||||||
constexpr ConstexprCtor<int> f2() { return 0; } // ok
|
constexpr ConstexprCtor<int> f2() { return 0; } // ok
|
||||||
constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-literal type 'NonLiteral}}
|
constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
|
||||||
constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-literal type 'NonLiteral}}
|
constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
|
||||||
|
|
||||||
struct VirtBase : virtual S {}; // expected-note {{here}}
|
struct VirtBase : virtual S {}; // expected-note {{here}}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace noex {
|
||||||
struct A {};
|
struct A {};
|
||||||
|
|
||||||
void g1() noexcept(A()); // expected-error {{not contextually convertible}}
|
void g1() noexcept(A()); // expected-error {{not contextually convertible}}
|
||||||
void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}} expected-note {{function parameter 'b' with unknown value}} expected-note {{here}}
|
void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}} expected-note {{read of non-const variable 'b'}} expected-note {{here}}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,11 +62,11 @@ namespace NonConstExprReturn {
|
||||||
constexpr const int *address_of(const int &a) {
|
constexpr const int *address_of(const int &a) {
|
||||||
return &a;
|
return &a;
|
||||||
}
|
}
|
||||||
constexpr const int *return_param(int n) {
|
constexpr const int *return_param(int n) { // expected-note {{declared here}}
|
||||||
return address_of(n);
|
return address_of(n);
|
||||||
}
|
}
|
||||||
struct S {
|
struct S {
|
||||||
int n : *return_param(0); // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}}
|
int n : *return_param(0); // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,12 +427,13 @@ namespace PseudoDtor {
|
||||||
int n : (k.~I(), 1); // expected-error {{constant expression}} expected-note {{visible outside that expression}}
|
int n : (k.~I(), 1); // expected-error {{constant expression}} expected-note {{visible outside that expression}}
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr int f(int a = 1) { // cxx11-error {{constant expression}} expected-note {{destroying object 'a' whose lifetime has already ended}}
|
// FIXME: It's unclear whether this should be accepted in C++20 mode. The parameter is destroyed twice here.
|
||||||
|
constexpr int f(int a = 1) { // cxx11-error {{constant expression}}
|
||||||
return (
|
return (
|
||||||
a.~I(), // cxx11-note {{pseudo-destructor}}
|
a.~I(), // cxx11-note 2{{pseudo-destructor}}
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
static_assert(f() == 0, ""); // expected-error {{constant expression}}
|
static_assert(f() == 0, ""); // cxx11-error {{constant expression}} cxx11-note {{in call}}
|
||||||
|
|
||||||
// This is OK in C++20: the union has no active member after the
|
// This is OK in C++20: the union has no active member after the
|
||||||
// pseudo-destructor call, so the union destructor has no effect.
|
// pseudo-destructor call, so the union destructor has no effect.
|
||||||
|
|
|
@ -65,7 +65,7 @@ int tmain(int argc, char **argv) { // expected-note {{declared here}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp critical (name2) hint(+ // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
#pragma omp critical (name2) hint(+ // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp critical (name2) hint(argc) // expected-error {{integral constant expression}} expected-note 0+{{constant expression}}
|
#pragma omp critical (name2) hint(argc) // expected-error {{integral constant expression}} expected-note {{read of non-const variable 'argc' is not allowed in a constant expression}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp critical (name) hint(N) // expected-error {{argument to 'hint' clause must be a strictly positive integer value}} expected-error {{constructs with the same name must have a 'hint' clause with the same value}} expected-note {{'hint' clause with value '4'}}
|
#pragma omp critical (name) hint(N) // expected-error {{argument to 'hint' clause must be a strictly positive integer value}} expected-error {{constructs with the same name must have a 'hint' clause with the same value}} expected-note {{'hint' clause with value '4'}}
|
||||||
foo();
|
foo();
|
||||||
|
@ -128,7 +128,7 @@ int main(int argc, char **argv) { // expected-note {{declared here}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp critical (name2) hint(+ // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
#pragma omp critical (name2) hint(+ // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp critical (name2) hint(argc) // expected-error {{integral constant expression}} expected-note 0+{{constant expression}}
|
#pragma omp critical (name2) hint(argc) // expected-error {{integral constant expression}} expected-note {{read of non-const variable 'argc' is not allowed in a constant expression}}
|
||||||
foo();
|
foo();
|
||||||
#pragma omp critical (name) hint(23) // expected-note {{previous 'hint' clause with value '23'}}
|
#pragma omp critical (name) hint(23) // expected-note {{previous 'hint' clause with value '23'}}
|
||||||
foo();
|
foo();
|
||||||
|
|
|
@ -39,7 +39,7 @@ T tmain(T argc, S **argv) {
|
||||||
|
|
||||||
#pragma omp target
|
#pragma omp target
|
||||||
#pragma omp teams
|
#pragma omp teams
|
||||||
#pragma omp distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ T tmain(T argc, S **argv) {
|
||||||
|
|
||||||
#pragma omp target
|
#pragma omp target
|
||||||
#pragma omp teams
|
#pragma omp teams
|
||||||
#pragma omp distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ T tmain(T argc, S **argv) {
|
||||||
|
|
||||||
#pragma omp target
|
#pragma omp target
|
||||||
#pragma omp teams
|
#pragma omp teams
|
||||||
#pragma omp distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ T tmain(T argc, S **argv) {
|
||||||
#pragma omp target teams distribute parallel for simd safelen () // expected-error {{expected expression}}
|
#pragma omp target teams distribute parallel for simd safelen () // expected-error {{expected expression}}
|
||||||
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
#pragma omp target teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp target teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ T tmain(T argc, S **argv) {
|
||||||
#pragma omp target teams distribute parallel for simd safelen () // expected-error {{expected expression}}
|
#pragma omp target teams distribute parallel for simd safelen () // expected-error {{expected expression}}
|
||||||
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
#pragma omp target teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp target teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ T tmain(T argc, S **argv) {
|
||||||
#pragma omp target teams distribute simd safelen () // expected-error {{expected expression}}
|
#pragma omp target teams distribute simd safelen () // expected-error {{expected expression}}
|
||||||
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
#pragma omp target teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp target teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ T tmain(T argc, S **argv) {
|
||||||
#pragma omp target teams distribute simd safelen () // expected-error {{expected expression}}
|
#pragma omp target teams distribute simd safelen () // expected-error {{expected expression}}
|
||||||
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
#pragma omp target teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp target teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ T tmain(T argc, S **argv) {
|
||||||
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
#pragma omp target
|
#pragma omp target
|
||||||
#pragma omp teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ T tmain(T argc, S **argv) {
|
||||||
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
#pragma omp target
|
#pragma omp target
|
||||||
#pragma omp teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ T tmain(T argc, S **argv) {
|
||||||
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
#pragma omp target
|
#pragma omp target
|
||||||
#pragma omp teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ T tmain(T argc, S **argv) {
|
||||||
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
#pragma omp target
|
#pragma omp target
|
||||||
#pragma omp teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
#pragma omp teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
|
||||||
for (int i = ST; i < N; i++)
|
for (int i = ST; i < N; i++)
|
||||||
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
argv[0][i] = argv[0][i] - argv[0][i-ST];
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ void test(int x, double p) { // expected-note {{declared here}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, 0.9);
|
dummy = __builtin_expect_with_probability(x > 0, 1, 0.9);
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, 1.1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, 1.1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, -1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, -1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, p); // expected-error {{probability argument to __builtin_expect_with_probability must be constant floating-point expression}} expected-note {{function parameter 'p' with unknown value}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, p); // expected-error {{probability argument to __builtin_expect_with_probability must be constant floating-point expression}} expected-note {{read of non-constexpr variable 'p' is not allowed in a constant expression}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, "aa"); // expected-error {{cannot initialize a parameter of type 'double' with an lvalue of type 'const char [3]'}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, "aa"); // expected-error {{cannot initialize a parameter of type 'double' with an lvalue of type 'const char [3]'}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_nan("")); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_nan("")); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_inf()); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_inf()); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
||||||
|
|
|
@ -43,7 +43,7 @@ void test(int x, double p) { // expected-note {{declared here}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, 0.9);
|
dummy = __builtin_expect_with_probability(x > 0, 1, 0.9);
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, 1.1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, 1.1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, -1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, -1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, p); // expected-error {{probability argument to __builtin_expect_with_probability must be constant floating-point expression}} expected-note {{function parameter 'p'}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, p); // expected-error {{probability argument to __builtin_expect_with_probability must be constant floating-point expression}} expected-note {{read of non-constexpr variable 'p' is not allowed in a constant expression}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, "aa"); // expected-error {{cannot initialize a parameter of type 'double' with an lvalue of type 'const char [3]'}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, "aa"); // expected-error {{cannot initialize a parameter of type 'double' with an lvalue of type 'const char [3]'}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_nan("")); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_nan("")); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
||||||
dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_inf()); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_inf()); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
|
||||||
|
|
|
@ -65,7 +65,7 @@ void test10 (int x[*]); /* expected-warning {{variable length arrays are a C99 f
|
||||||
void test11 (int x[static 4]); /* expected-warning {{static array size is a C99 feature}} */
|
void test11 (int x[static 4]); /* expected-warning {{static array size is a C99 feature}} */
|
||||||
|
|
||||||
void test12 (int x[const 4]) { /* expected-warning {{qualifier in array size is a C99 feature}} */
|
void test12 (int x[const 4]) { /* expected-warning {{qualifier in array size is a C99 feature}} */
|
||||||
int Y[x[1]]; /* expected-warning {{variable length arrays are a C99 feature}} */
|
int Y[x[1]]; /* expected-warning {{variable length arrays are a C99 feature}} expected-note {{parameter 'x'}} */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PR4074 */
|
/* PR4074 */
|
||||||
|
|
|
@ -17,7 +17,7 @@ __host__ __device__ void foo(const T **a) {
|
||||||
constexpr T e = sizeof(a);
|
constexpr T e = sizeof(a);
|
||||||
constexpr T f = **a;
|
constexpr T f = **a;
|
||||||
// expected-error@-1 {{constexpr variable 'f' must be initialized by a constant expression}}
|
// expected-error@-1 {{constexpr variable 'f' must be initialized by a constant expression}}
|
||||||
// expected-note@-2 {{}}
|
// expected-note@-2 {{read of non-constexpr variable 'a' is not allowed in a constant expression}}
|
||||||
a[0] = &b;
|
a[0] = &b;
|
||||||
a[1] = &c;
|
a[1] = &c;
|
||||||
a[2] = &d;
|
a[2] = &d;
|
||||||
|
@ -30,7 +30,7 @@ __device__ void device_fun(const int **a) {
|
||||||
static constexpr int c = sizeof(a);
|
static constexpr int c = sizeof(a);
|
||||||
constexpr int d = **a;
|
constexpr int d = **a;
|
||||||
// expected-error@-1 {{constexpr variable 'd' must be initialized by a constant expression}}
|
// expected-error@-1 {{constexpr variable 'd' must be initialized by a constant expression}}
|
||||||
// expected-note@-2 {{}}
|
// expected-note@-2 {{read of non-constexpr variable 'a' is not allowed in a constant expression}}
|
||||||
a[0] = &b;
|
a[0] = &b;
|
||||||
a[1] = &c;
|
a[1] = &c;
|
||||||
foo(a);
|
foo(a);
|
||||||
|
@ -43,7 +43,7 @@ void host_fun(const int **a) {
|
||||||
static constexpr int c = sizeof(a);
|
static constexpr int c = sizeof(a);
|
||||||
constexpr int d = **a;
|
constexpr int d = **a;
|
||||||
// expected-error@-1 {{constexpr variable 'd' must be initialized by a constant expression}}
|
// expected-error@-1 {{constexpr variable 'd' must be initialized by a constant expression}}
|
||||||
// expected-note@-2 {{}}
|
// expected-note@-2 {{read of non-constexpr variable 'a' is not allowed in a constant expression}}
|
||||||
a[0] = &b;
|
a[0] = &b;
|
||||||
a[1] = &c;
|
a[1] = &c;
|
||||||
foo(a);
|
foo(a);
|
||||||
|
@ -55,7 +55,7 @@ __host__ __device__ void host_device_fun(const int **a) {
|
||||||
static constexpr int c = sizeof(a);
|
static constexpr int c = sizeof(a);
|
||||||
constexpr int d = **a;
|
constexpr int d = **a;
|
||||||
// expected-error@-1 {{constexpr variable 'd' must be initialized by a constant expression}}
|
// expected-error@-1 {{constexpr variable 'd' must be initialized by a constant expression}}
|
||||||
// expected-note@-2 {{}}
|
// expected-note@-2 {{read of non-constexpr variable 'a' is not allowed in a constant expression}}
|
||||||
a[0] = &b;
|
a[0] = &b;
|
||||||
a[1] = &c;
|
a[1] = &c;
|
||||||
foo(a);
|
foo(a);
|
||||||
|
|
|
@ -18,12 +18,12 @@ struct POD {
|
||||||
|
|
||||||
// We allow VLAs of POD types, only.
|
// We allow VLAs of POD types, only.
|
||||||
void vla(int N) { // expected-note 5{{here}}
|
void vla(int N) { // expected-note 5{{here}}
|
||||||
int array1[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{parameter 'N'}}
|
int array1[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{variable 'N'}}
|
||||||
POD array2[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{parameter 'N'}}
|
POD array2[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{variable 'N'}}
|
||||||
StillPOD array3[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{parameter 'N'}}
|
StillPOD array3[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{variable 'N'}}
|
||||||
StillPOD2 array4[N][3]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{parameter 'N'}}
|
StillPOD2 array4[N][3]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{variable 'N'}}
|
||||||
NonPOD array5[N]; // expected-error{{no matching constructor for initialization of 'NonPOD [N]'}}
|
NonPOD array5[N]; // expected-error{{no matching constructor for initialization of 'NonPOD [N]'}}
|
||||||
// expected-warning@-1{{variable length arrays are a C99 feature}} expected-note@-1 {{parameter 'N'}}
|
// expected-warning@-1{{variable length arrays are a C99 feature}} expected-note@-1 {{variable 'N'}}
|
||||||
// expected-note@-16{{candidate constructor not viable}}
|
// expected-note@-16{{candidate constructor not viable}}
|
||||||
// expected-note@-18{{candidate constructor (the implicit copy constructor) not viable}}
|
// expected-note@-18{{candidate constructor (the implicit copy constructor) not viable}}
|
||||||
// expected-note@-19{{candidate constructor (the implicit move constructor) not viable}}
|
// expected-note@-19{{candidate constructor (the implicit move constructor) not viable}}
|
||||||
|
|
|
@ -13,7 +13,6 @@ struct POD {
|
||||||
};
|
};
|
||||||
|
|
||||||
// expected-note@* 1+{{read of non-const variable}}
|
// expected-note@* 1+{{read of non-const variable}}
|
||||||
// expected-note@* 1+{{function parameter}}
|
|
||||||
// expected-note@* 1+{{declared here}}
|
// expected-note@* 1+{{declared here}}
|
||||||
|
|
||||||
// We allow VLAs of POD types, only.
|
// We allow VLAs of POD types, only.
|
||||||
|
|
|
@ -217,11 +217,11 @@ namespace ParameterScopes {
|
||||||
|
|
||||||
const int k = 42;
|
const int k = 42;
|
||||||
constexpr const int &ObscureTheTruth(const int &a) { return a; }
|
constexpr const int &ObscureTheTruth(const int &a) { return a; }
|
||||||
constexpr const int &MaybeReturnJunk(bool b, const int a) {
|
constexpr const int &MaybeReturnJunk(bool b, const int a) { // expected-note 2{{declared here}}
|
||||||
return ObscureTheTruth(b ? a : k);
|
return ObscureTheTruth(b ? a : k);
|
||||||
}
|
}
|
||||||
static_assert(MaybeReturnJunk(false, 0) == 42, ""); // ok
|
static_assert(MaybeReturnJunk(false, 0) == 42, ""); // ok
|
||||||
constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}}
|
constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}}
|
||||||
|
|
||||||
constexpr const int MaybeReturnNonstaticRef(bool b, const int a) {
|
constexpr const int MaybeReturnNonstaticRef(bool b, const int a) {
|
||||||
return ObscureTheTruth(b ? a : k);
|
return ObscureTheTruth(b ? a : k);
|
||||||
|
@ -230,7 +230,7 @@ namespace ParameterScopes {
|
||||||
constexpr int b = MaybeReturnNonstaticRef(true, 0); // ok
|
constexpr int b = MaybeReturnNonstaticRef(true, 0); // ok
|
||||||
|
|
||||||
constexpr int InternalReturnJunk(int n) {
|
constexpr int InternalReturnJunk(int n) {
|
||||||
return MaybeReturnJunk(true, n); // expected-note {{read of object outside its lifetime}}
|
return MaybeReturnJunk(true, n); // expected-note {{read of variable whose lifetime has ended}}
|
||||||
}
|
}
|
||||||
constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'InternalReturnJunk(0)'}}
|
constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'InternalReturnJunk(0)'}}
|
||||||
|
|
||||||
|
@ -1568,7 +1568,7 @@ namespace RecursiveOpaqueExpr {
|
||||||
namespace VLASizeof {
|
namespace VLASizeof {
|
||||||
|
|
||||||
void f(int k) { // expected-note {{here}}
|
void f(int k) { // expected-note {{here}}
|
||||||
int arr[k]; // expected-warning {{C99}} expected-note {{function parameter 'k'}}
|
int arr[k]; // expected-warning {{C99}} expected-note {{non-const variable 'k'}}
|
||||||
constexpr int n = 1 +
|
constexpr int n = 1 +
|
||||||
sizeof(arr) // expected-error {{constant expression}}
|
sizeof(arr) // expected-error {{constant expression}}
|
||||||
* 3;
|
* 3;
|
||||||
|
@ -1928,9 +1928,9 @@ namespace Lifetime {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
constexpr int f() const { return 0; }
|
constexpr int f() const { return 0; }
|
||||||
};
|
};
|
||||||
constexpr Q *out_of_lifetime(Q q) { return &q; } // expected-warning {{address of stack}}
|
constexpr Q *out_of_lifetime(Q q) { return &q; } // expected-warning {{address of stack}} expected-note 2{{declared here}}
|
||||||
constexpr int k3 = out_of_lifetime({})->n; // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}}
|
constexpr int k3 = out_of_lifetime({})->n; // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}}
|
||||||
constexpr int k4 = out_of_lifetime({})->f(); // expected-error {{constant expression}} expected-note {{member call on object outside its lifetime}}
|
constexpr int k4 = out_of_lifetime({})->f(); // expected-error {{constant expression}} expected-note {{member call on variable whose lifetime has ended}}
|
||||||
|
|
||||||
constexpr int null = ((Q*)nullptr)->f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced null pointer}}
|
constexpr int null = ((Q*)nullptr)->f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced null pointer}}
|
||||||
|
|
||||||
|
@ -2252,7 +2252,7 @@ namespace ns1 {
|
||||||
void f(char c) { //expected-note2{{declared here}}
|
void f(char c) { //expected-note2{{declared here}}
|
||||||
struct X {
|
struct X {
|
||||||
static constexpr char f() { //expected-error{{never produces a constant expression}}
|
static constexpr char f() { //expected-error{{never produces a constant expression}}
|
||||||
return c; //expected-error{{reference to local}} expected-note{{function parameter}}
|
return c; //expected-error{{reference to local}} expected-note{{non-const variable}}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
int I = X::f();
|
int I = X::f();
|
||||||
|
@ -2312,7 +2312,7 @@ namespace array_size {
|
||||||
template<typename T> void f1(T t) {
|
template<typename T> void f1(T t) {
|
||||||
constexpr int k = t.size();
|
constexpr int k = t.size();
|
||||||
}
|
}
|
||||||
template<typename T> void f2(const T &t) { // expected-note {{declared here}}
|
template<typename T> void f2(const T &t) {
|
||||||
constexpr int k = t.size(); // expected-error {{constant}} expected-note {{function parameter 't' with unknown value cannot be used in a constant expression}}
|
constexpr int k = t.size(); // expected-error {{constant}} expected-note {{function parameter 't' with unknown value cannot be used in a constant expression}}
|
||||||
}
|
}
|
||||||
template<typename T> void f3(const T &t) {
|
template<typename T> void f3(const T &t) {
|
||||||
|
|
|
@ -1415,16 +1415,3 @@ namespace PR45350 {
|
||||||
// decreasing address
|
// decreasing address
|
||||||
static_assert(f(6) == 543210);
|
static_assert(f(6) == 543210);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace PR47805 {
|
|
||||||
struct A {
|
|
||||||
bool bad = true;
|
|
||||||
constexpr ~A() { if (bad) throw; }
|
|
||||||
};
|
|
||||||
constexpr bool f(A a) { a.bad = false; return true; }
|
|
||||||
constexpr bool b = f(A());
|
|
||||||
|
|
||||||
struct B { B *p = this; };
|
|
||||||
constexpr bool g(B b) { return &b == b.p; }
|
|
||||||
static_assert(g({}));
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace std {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> constexpr bool has_type(...) { return false; }
|
template<typename T> constexpr bool has_type(...) { return false; }
|
||||||
template<typename T> constexpr bool has_type(T&) { return true; }
|
template<typename T> constexpr bool has_type(T) { return true; }
|
||||||
|
|
||||||
std::initializer_list il = {1, 2, 3, 4, 5};
|
std::initializer_list il = {1, 2, 3, 4, 5};
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,7 @@ constexpr int f_c(int i) {
|
||||||
// expected-note@-1 {{declared here}}
|
// expected-note@-1 {{declared here}}
|
||||||
int t = f(i);
|
int t = f(i);
|
||||||
// expected-error@-1 {{is not a constant expression}}
|
// expected-error@-1 {{is not a constant expression}}
|
||||||
// expected-note@-2 {{function parameter}}
|
// expected-note@-2 {{read of non-const variable}}
|
||||||
return f(0);
|
return f(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ auto l1 = [](int i) constexpr {
|
||||||
// expected-note@-1 {{declared here}}
|
// expected-note@-1 {{declared here}}
|
||||||
int t = f(i);
|
int t = f(i);
|
||||||
// expected-error@-1 {{is not a constant expression}}
|
// expected-error@-1 {{is not a constant expression}}
|
||||||
// expected-note@-2 {{function parameter}}
|
// expected-note@-2 {{read of non-const variable}}
|
||||||
return f(0);
|
return f(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,8 @@ uint64_t check_integer_overflows(int i) { //expected-note 0+{{declared here}}
|
||||||
// expected-warning@+1 {{overflow in expression; result is 537919488 with type 'int'}}
|
// expected-warning@+1 {{overflow in expression; result is 537919488 with type 'int'}}
|
||||||
case 1 + static_cast<uint64_t>(4609 * 1024 * 1024):
|
case 1 + static_cast<uint64_t>(4609 * 1024 * 1024):
|
||||||
return 7;
|
return 7;
|
||||||
// expected-error@+1 {{expression is not an integral constant expression}}
|
// expected-error@+2 {{expression is not an integral constant expression}}
|
||||||
|
// expected-note@+1 {{read of non-const variable 'i' is not allowed in a constant expression}}
|
||||||
case ((uint64_t)(4608 * 1024 * 1024 * i)):
|
case ((uint64_t)(4608 * 1024 * 1024 * i)):
|
||||||
return 8;
|
return 8;
|
||||||
// expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}}
|
// expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}}
|
||||||
|
|
|
@ -23,8 +23,8 @@ void print(int n, int a, int b, int c, int d) {
|
||||||
void test(int n) {
|
void test(int n) {
|
||||||
S array_t[n][n+1];
|
S array_t[n][n+1];
|
||||||
# ifdef PE
|
# ifdef PE
|
||||||
// expected-error@-2 {{variable length arrays are a C99 feature}} expected-note@-2 {{parameter}} expected-note@-3 {{here}}
|
// expected-error@-2 {{variable length arrays are a C99 feature}} expected-note@-2 {{read of non-const}} expected-note@-3 {{here}}
|
||||||
// expected-error@-3 {{variable length arrays are a C99 feature}} expected-note@-3 {{parameter}} expected-note@-4 {{here}}
|
// expected-error@-3 {{variable length arrays are a C99 feature}} expected-note@-3 {{read of non-const}} expected-note@-4 {{here}}
|
||||||
# endif
|
# endif
|
||||||
int sizeof_S = sizeof(S);
|
int sizeof_S = sizeof(S);
|
||||||
int sizeof_array_t_0_0 = sizeof(array_t[0][0]);
|
int sizeof_array_t_0_0 = sizeof(array_t[0][0]);
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify -Wvla %s
|
// RUN: %clang_cc1 -fsyntax-only -verify -Wvla %s
|
||||||
|
|
||||||
void test1(int n) { // expected-note {{here}}
|
void test1(int n) { // expected-note {{here}}
|
||||||
int v[n]; // expected-warning {{variable length array}} expected-note {{parameter 'n'}}
|
int v[n]; // expected-warning {{variable length array}} expected-note {{variable 'n'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void test2(int n, int v[n]) { // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
|
void test2(int n, int v[n]) { // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
|
||||||
}
|
}
|
||||||
|
|
||||||
void test3(int n, int v[n]); // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
|
void test3(int n, int v[n]); // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void test4(int n) { // expected-note {{here}}
|
void test4(int n) { // expected-note {{here}}
|
||||||
int v[n]; // expected-warning {{variable length array}} expected-note {{parameter 'n'}}
|
int v[n]; // expected-warning {{variable length array}} expected-note {{variable 'n'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void test5(int n, int v[n]) { // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
|
void test5(int n, int v[n]) { // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void test6(int n, int v[n]); // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
|
void test6(int n, int v[n]); // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void test7(int n, T v[n]) { // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
|
void test7(int n, T v[n]) { // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,12 @@ struct Y {
|
||||||
struct Inner : Y { // expected-note {{declared here}}
|
struct Inner : Y { // expected-note {{declared here}}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool f(T other) { // expected-note {{declared here}}
|
bool f(T other) {
|
||||||
// We can determine that 'inner' does not exist at parse time, so can
|
// We can determine that 'inner' does not exist at parse time, so can
|
||||||
// perform typo correction in this case.
|
// perform typo correction in this case.
|
||||||
return this->inner<other>::z; // expected-error {{no template named 'inner' in 'Y<T>'; did you mean 'Inner'?}}
|
return this->inner<other>::z; // expected-error {{no template named 'inner' in 'Y<T>'; did you mean 'Inner'?}}
|
||||||
// expected-error@-1 {{constant expression}} expected-note@-1 {{function parameter 'other'}}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Q { constexpr operator int() { return 0; } };
|
struct Q { constexpr operator int() { return 0; } };
|
||||||
void use_y(Y<Q> x) { x.f(Q()); } // expected-note {{instantiation of}}
|
void use_y(Y<Q> x) { x.f(Q()); }
|
||||||
|
|
Loading…
Reference in New Issue