diff options
-rw-r--r-- | lib/AST/Decl.cpp | 19 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 5 | ||||
-rw-r--r-- | test/CXX/expr/expr.const/p2-0x.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/lambda-expressions.cpp | 7 | ||||
-rw-r--r-- | test/SemaTemplate/constexpr-instantiate.cpp | 10 |
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, ""); +} |