зеркало из https://github.com/microsoft/clang-1.git
When determining whether a reference to a static data member is an
integral constant expression, make sure to find where the initializer was provided---inside or outside the class definition---since that can affect whether we have an integral constant expression (and, we need to see the initializer itself). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85741 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
7a34314290
Коммит
cf3293eaeb
|
@ -22,6 +22,7 @@
|
||||||
#include "clang/AST/StmtVisitor.h"
|
#include "clang/AST/StmtVisitor.h"
|
||||||
#include "clang/Basic/Builtins.h"
|
#include "clang/Basic/Builtins.h"
|
||||||
#include "clang/Basic/TargetInfo.h"
|
#include "clang/Basic/TargetInfo.h"
|
||||||
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
@ -1538,16 +1539,35 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
|
||||||
// type initialized by an ICE can be used in ICEs.
|
// type initialized by an ICE can be used in ICEs.
|
||||||
if (const VarDecl *Dcl =
|
if (const VarDecl *Dcl =
|
||||||
dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
|
dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
|
||||||
if (Dcl->isInitKnownICE()) {
|
Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers();
|
||||||
// We have already checked whether this subexpression is an
|
if (Quals.hasVolatile() || !Quals.hasConst())
|
||||||
// integral constant expression.
|
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
|
||||||
if (Dcl->isInitICE())
|
|
||||||
return NoDiag();
|
// Look for the definition of this variable, which will actually have
|
||||||
else
|
// an initializer.
|
||||||
return ICEDiag(2, E->getLocStart());
|
const VarDecl *Def = 0;
|
||||||
}
|
const Expr *Init = Dcl->getDefinition(Def);
|
||||||
|
if (Init) {
|
||||||
|
if (Def->isInitKnownICE()) {
|
||||||
|
// We have already checked whether this subexpression is an
|
||||||
|
// integral constant expression.
|
||||||
|
if (Def->isInitICE())
|
||||||
|
return NoDiag();
|
||||||
|
else
|
||||||
|
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
if (const Expr *Init = Dcl->getInit()) {
|
// C++ [class.static.data]p4:
|
||||||
|
// If a static data member is of const integral or const
|
||||||
|
// enumeration type, its declaration in the class definition can
|
||||||
|
// specify a constant-initializer which shall be an integral
|
||||||
|
// constant expression (5.19). In that case, the member can appear
|
||||||
|
// in integral constant expressions.
|
||||||
|
if (Def->isOutOfLine()) {
|
||||||
|
Dcl->setInitKnownICE(Ctx, false);
|
||||||
|
return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
ICEDiag Result = CheckICE(Init, Ctx);
|
ICEDiag Result = CheckICE(Init, Ctx);
|
||||||
// Cache the result of the ICE test.
|
// Cache the result of the ICE test.
|
||||||
Dcl->setInitKnownICE(Ctx, Result.Val == 0);
|
Dcl->setInitKnownICE(Ctx, Result.Val == 0);
|
||||||
|
@ -1750,7 +1770,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
|
||||||
}
|
}
|
||||||
EvalResult EvalResult;
|
EvalResult EvalResult;
|
||||||
if (!Evaluate(EvalResult, Ctx))
|
if (!Evaluate(EvalResult, Ctx))
|
||||||
assert(0 && "ICE cannot be evaluated!");
|
llvm::llvm_unreachable("ICE cannot be evaluated!");
|
||||||
assert(!EvalResult.HasSideEffects && "ICE with side effects!");
|
assert(!EvalResult.HasSideEffects && "ICE with side effects!");
|
||||||
assert(EvalResult.Val.isInt() && "ICE that isn't integer!");
|
assert(EvalResult.Val.isInt() && "ICE that isn't integer!");
|
||||||
Result = EvalResult.Val.getInt();
|
Result = EvalResult.Val.getInt();
|
||||||
|
|
|
@ -270,8 +270,9 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
|
||||||
if (!VD->getType()->isReferenceType())
|
if (!VD->getType()->isReferenceType())
|
||||||
return APValue(E, 0);
|
return APValue(E, 0);
|
||||||
// FIXME: Check whether VD might be overridden!
|
// FIXME: Check whether VD might be overridden!
|
||||||
if (VD->getInit())
|
const VarDecl *Def = 0;
|
||||||
return Visit(VD->getInit());
|
if (const Expr *Init = VD->getDefinition(Def))
|
||||||
|
return Visit(const_cast<Expr *>(Init));
|
||||||
}
|
}
|
||||||
|
|
||||||
return APValue();
|
return APValue();
|
||||||
|
@ -855,11 +856,14 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
|
||||||
|
|
||||||
// In C++, const, non-volatile integers initialized with ICEs are ICEs.
|
// In C++, const, non-volatile integers initialized with ICEs are ICEs.
|
||||||
// In C, they can also be folded, although they are not ICEs.
|
// In C, they can also be folded, although they are not ICEs.
|
||||||
if (E->getType().getCVRQualifiers() == Qualifiers::Const) {
|
if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers()
|
||||||
|
== Qualifiers::Const) {
|
||||||
if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) {
|
if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) {
|
||||||
if (APValue *V = D->getEvaluatedValue())
|
const VarDecl *Def = 0;
|
||||||
return Success(V->getInt(), E);
|
if (const Expr *Init = D->getDefinition(Def)) {
|
||||||
if (const Expr *Init = D->getInit()) {
|
if (APValue *V = D->getEvaluatedValue())
|
||||||
|
return Success(V->getInt(), E);
|
||||||
|
|
||||||
if (Visit(const_cast<Expr*>(Init))) {
|
if (Visit(const_cast<Expr*>(Init))) {
|
||||||
// Cache the evaluated value in the variable declaration.
|
// Cache the evaluated value in the variable declaration.
|
||||||
D->setEvaluatedValue(Info.Ctx, Result);
|
D->setEvaluatedValue(Info.Ctx, Result);
|
||||||
|
|
|
@ -165,7 +165,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
||||||
// which they were instantiated.
|
// which they were instantiated.
|
||||||
if (Var->isStaticDataMember())
|
if (Var->isStaticDataMember())
|
||||||
SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
|
SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
|
||||||
TSK_ImplicitInstantiation);
|
TSK_ImplicitInstantiation);
|
||||||
|
|
||||||
if (D->getInit()) {
|
if (D->getInit()) {
|
||||||
OwningExprResult Init
|
OwningExprResult Init
|
||||||
|
|
|
@ -5,3 +5,33 @@ template<int i> struct x {
|
||||||
x<j>* y;
|
x<j>* y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<int i>
|
||||||
|
const int x<i>::j;
|
||||||
|
|
||||||
|
int array0[x<2>::j];
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct X0 {
|
||||||
|
static const unsigned value = sizeof(T);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const unsigned X0<T>::value;
|
||||||
|
|
||||||
|
int array1[X0<int>::value == sizeof(int)? 1 : -1];
|
||||||
|
|
||||||
|
const unsigned& testX0() { return X0<int>::value; }
|
||||||
|
|
||||||
|
int array2[X0<int>::value == sizeof(int)? 1 : -1];
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct X1 {
|
||||||
|
static const unsigned value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const unsigned X1<T>::value = sizeof(T);
|
||||||
|
|
||||||
|
int array3[X1<int>::value == sizeof(int)? 1 : -1]; // expected-error{{variable length arrays are not permitted in C++}} \
|
||||||
|
// expected-error{{variable length array declaration not allowed at file scope}}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче