aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/Decl.cpp19
-rw-r--r--lib/Sema/SemaExpr.cpp5
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp4
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp4
-rw-r--r--test/SemaCXX/lambda-expressions.cpp7
-rw-r--r--test/SemaTemplate/constexpr-instantiate.cpp10
6 files changed, 37 insertions, 12 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index bd7579996f..03b2794c0e 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1372,11 +1372,18 @@ void VarDecl::setInit(Expr *I) {
bool VarDecl::isUsableInConstantExpressions() const {
const LangOptions &Lang = getASTContext().getLangOptions();
- // Only const variables can be used in constant expressions in C++. C++98 does
+ if (!Lang.CPlusPlus)
+ return false;
+
+ // In C++11, any variable of reference type can be used in a constant
+ // expression if it is initialized by a constant expression.
+ if (Lang.CPlusPlus0x && getType()->isReferenceType())
+ return true;
+
+ // Only const objects can be used in constant expressions in C++. C++98 does
// not require the variable to be non-volatile, but we consider this to be a
// defect.
- if (!Lang.CPlusPlus ||
- !getType().isConstQualified() || getType().isVolatileQualified())
+ if (!getType().isConstQualified() || getType().isVolatileQualified())
return false;
// In C++, const, non-volatile variables of integral or enumeration types
@@ -1384,9 +1391,9 @@ bool VarDecl::isUsableInConstantExpressions() const {
if (getType()->isIntegralOrEnumerationType())
return true;
- // Additionally, in C++11, non-volatile constexpr variables and references can
- // be used in constant expressions.
- return Lang.CPlusPlus0x && (isConstexpr() || getType()->isReferenceType());
+ // Additionally, in C++11, non-volatile constexpr variables can be used in
+ // constant expressions.
+ return Lang.CPlusPlus0x && isConstexpr();
}
/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 6deffa2abd..ece16e8850 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -10108,9 +10108,10 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// is immediately applied." We check the first part here, and
// Sema::UpdateMarkingForLValueToRValue deals with the second part.
// Note that we use the C++11 definition everywhere because nothing in
- // C++03 depends on whether we get the C++03 version correct.
+ // C++03 depends on whether we get the C++03 version correct. This does not
+ // apply to references, since they are not objects.
const VarDecl *DefVD;
- if (E && !isa<ParmVarDecl>(Var) &&
+ if (E && !isa<ParmVarDecl>(Var) && !Var->getType()->isReferenceType() &&
Var->isUsableInConstantExpressions() &&
Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE())
SemaRef.MaybeODRUseExprs.insert(E);
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 8d3638ffc6..054669ef78 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -362,8 +362,8 @@ namespace References {
constexpr int e = 42;
int &f = const_cast<int&>(e);
extern int &g;
- constexpr int &h(); // expected-note 2{{here}}
- int &i = h(); // expected-note {{here}} expected-note {{undefined function 'h' cannot be used in a constant expression}}
+ constexpr int &h(); // expected-note {{here}}
+ int &i = h(); // expected-note {{here}}
constexpr int &j() { return b; }
int &k = j();
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 78be5d292d..dcc437aed0 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -100,8 +100,8 @@ namespace CaseStatements {
}
extern int &Recurse1;
-int &Recurse2 = Recurse1; // expected-note 2{{declared here}} expected-note {{initializer of 'Recurse1' is not a constant expression}}
-int &Recurse1 = Recurse2; // expected-note {{declared here}} expected-note {{initializer of 'Recurse2' is not a constant expression}}
+int &Recurse2 = Recurse1; // expected-note {{declared here}}
+int &Recurse1 = Recurse2;
constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}} expected-note {{initializer of 'Recurse2' is not a constant expression}}
extern const int RecurseA;
diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp
index 7e53754a52..9d3f9b857f 100644
--- a/test/SemaCXX/lambda-expressions.cpp
+++ b/test/SemaCXX/lambda-expressions.cpp
@@ -85,6 +85,13 @@ namespace ImplicitCapture {
const int h = a; // expected-note {{declared}}
[]() { return h; }; // expected-error {{variable 'h' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
+
+ // The exemption for variables which can appear in constant expressions
+ // applies only to objects (and not to references).
+ // FIXME: This might be a bug in the standard.
+ static int i;
+ constexpr int &ref_i = i; // expected-note {{declared}}
+ [] { return ref_i; }; // expected-error {{variable 'ref_i' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
}
}
diff --git a/test/SemaTemplate/constexpr-instantiate.cpp b/test/SemaTemplate/constexpr-instantiate.cpp
index 316b088566..2f9fe0e485 100644
--- a/test/SemaTemplate/constexpr-instantiate.cpp
+++ b/test/SemaTemplate/constexpr-instantiate.cpp
@@ -65,3 +65,13 @@ namespace DataMember {
constexpr int m = S<int>::k; // ok
constexpr int o = n; // expected-error {{constant expression}} expected-note {{initializer of 'n'}}
}
+
+namespace Reference {
+ const int k = 5;
+ template<typename T> struct S {
+ static volatile int &r;
+ };
+ template<typename T> volatile int &S<T>::r = const_cast<volatile int&>(k);
+ constexpr int n = const_cast<int&>(S<int>::r);
+ static_assert(n == 5, "");
+}