]> granicus.if.org Git - clang/commitdiff
Ensure that we instantiate static reference data members of class templates
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 2 Mar 2012 04:14:40 +0000 (04:14 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 2 Mar 2012 04:14:40 +0000 (04:14 +0000)
early, since their values can be used in constant expressions in C++11. For
odr-use checking, the opposite change is required, since references are
odr-used whether or not they satisfy the requirements for appearing in a
constant expression.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151881 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/Decl.cpp
lib/Sema/SemaExpr.cpp
test/CXX/expr/expr.const/p2-0x.cpp
test/SemaCXX/constant-expression-cxx11.cpp
test/SemaCXX/lambda-expressions.cpp
test/SemaTemplate/constexpr-instantiate.cpp

index bd7579996f4a1916c76a054d1df25aa15f84c1fe..03b2794c0eb42de7e2013dabc0156420fab63458 100644 (file)
@@ -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
index 6deffa2abd37d8289af3866708882b08268ce303..ece16e88504f4e01158a83f21a4cd4bde39e0628 100644 (file)
@@ -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);
index 8d3638ffc6b73fc709715f3fc8f22d534a8039bf..054669ef788d687bc5253560859d39b774d095d3 100644 (file)
@@ -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();
 
index 78be5d292d46e65b12a896659e086a874357b446..dcc437aed02af2c28ecf208b23d05eaa1f91c665 100644 (file)
@@ -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;
index 7e53754a52708ff4a41057afa0e1b0c6c29d0c72..9d3f9b857f322c2b9ee92c5da27cda708d5acece 100644 (file)
@@ -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}}
   }
 }
 
index 316b0885664180e10f110157a13a30cc138b1eba..2f9fe0e4855bc851141ecc1ef130eb361de71d5a 100644 (file)
@@ -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, "");
+}