aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/Expr.cpp40
-rw-r--r--lib/AST/ExprConstant.cpp16
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp2
-rw-r--r--test/SemaTemplate/instantiate-declref-ice.cpp30
4 files changed, 71 insertions, 17 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 50a875c3eb..265823e4eb 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
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.
if (const VarDecl *Dcl =
dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
- if (Dcl->isInitKnownICE()) {
- // We have already checked whether this subexpression is an
- // integral constant expression.
- if (Dcl->isInitICE())
- return NoDiag();
- else
- return ICEDiag(2, E->getLocStart());
- }
+ Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers();
+ if (Quals.hasVolatile() || !Quals.hasConst())
+ return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+
+ // Look for the definition of this variable, which will actually have
+ // an initializer.
+ 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);
// Cache the result of the ICE test.
Dcl->setInitKnownICE(Ctx, Result.Val == 0);
@@ -1750,7 +1770,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
}
EvalResult EvalResult;
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.Val.isInt() && "ICE that isn't integer!");
Result = EvalResult.Val.getInt();
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 6ddeba99a7..804684cc2b 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -270,8 +270,9 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
if (!VD->getType()->isReferenceType())
return APValue(E, 0);
// FIXME: Check whether VD might be overridden!
- if (VD->getInit())
- return Visit(VD->getInit());
+ const VarDecl *Def = 0;
+ if (const Expr *Init = VD->getDefinition(Def))
+ return Visit(const_cast<Expr *>(Init));
}
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, 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 (APValue *V = D->getEvaluatedValue())
- return Success(V->getInt(), E);
- if (const Expr *Init = D->getInit()) {
+ const VarDecl *Def = 0;
+ if (const Expr *Init = D->getDefinition(Def)) {
+ if (APValue *V = D->getEvaluatedValue())
+ return Success(V->getInt(), E);
+
if (Visit(const_cast<Expr*>(Init))) {
// Cache the evaluated value in the variable declaration.
D->setEvaluatedValue(Info.Ctx, Result);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 27275230f7..7288ae29a0 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -165,7 +165,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// which they were instantiated.
if (Var->isStaticDataMember())
SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
- TSK_ImplicitInstantiation);
+ TSK_ImplicitInstantiation);
if (D->getInit()) {
OwningExprResult Init
diff --git a/test/SemaTemplate/instantiate-declref-ice.cpp b/test/SemaTemplate/instantiate-declref-ice.cpp
index 21ee872027..ab12b90f6c 100644
--- a/test/SemaTemplate/instantiate-declref-ice.cpp
+++ b/test/SemaTemplate/instantiate-declref-ice.cpp
@@ -5,3 +5,33 @@ template<int i> struct x {
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}}