]> granicus.if.org Git - clang/commitdiff
C++11 half of r147023: In C++11, additionally eagerly instantiate:
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 21 Dec 2011 02:55:12 +0000 (02:55 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 21 Dec 2011 02:55:12 +0000 (02:55 +0000)
 - constexpr function template instantiations
 - variables of reference type
 - constexpr variables

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

include/clang/AST/Decl.h
lib/AST/Decl.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
test/SemaCXX/constant-expression-cxx11.cpp

index 6b97a5775a6ebcd5f3d43c9f313643d8dc432e3a..52e09e664365c76271e562e6a60db916aa126cd7 100644 (file)
@@ -1025,6 +1025,12 @@ public:
   /// \endcode
   bool extendsLifetimeOfTemporary() const;
 
+  /// \brief Determine whether this variable's value can be used in a
+  /// constant expression, according to the relevant language standard.
+  /// This only checks properties of the declaration, and does not check
+  /// whether the initializer is in fact a constant expression.
+  bool isUsableInConstantExpressions() const;
+
   EvaluatedStmt *ensureEvaluatedStmt() const;
 
   /// \brief Attempt to evaluate the value of the initializer attached to this
index 9028a09bc39179abafd4fbb058acca4b8080529d..84a2a59ee23005ebb5621a621d5333870ed02280 100644 (file)
@@ -1339,6 +1339,26 @@ void VarDecl::setInit(Expr *I) {
   Init = I;
 }
 
+bool VarDecl::isUsableInConstantExpressions() const {
+  const LangOptions &Lang = getASTContext().getLangOptions();
+
+  // Only const variables 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())
+    return false;
+
+  // In C++, const, non-volatile variables of integral or enumeration types
+  // can be used in constant expressions.
+  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());
+}
+
 /// Convert the initializer for this declaration to the elaborated EvaluatedStmt
 /// form, which contains extra information on the evaluated value of the
 /// initializer.
index ebcdcf58d047dab2be230b552bbb08260cab7737..9ae39f1af38109deae7ffbdb8f7beeb3dd5aac83 100644 (file)
@@ -6544,8 +6544,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
         for (unsigned I = 0, N = Notes.size(); I != N; ++I)
           Diag(Notes[I].first, Notes[I].second);
       }
-    } else if (getLangOptions().CPlusPlus && !Type.isVolatileQualified() &&
-               Type.isConstQualified() && Type->isIntegralOrEnumerationType()) {
+    } else if (var->isUsableInConstantExpressions()) {
       // Check whether the initializer of a const variable of integral or
       // enumeration type is an ICE now, since we can't tell whether it was
       // initialized by a constant expression if we check later.
index 3a61fe50666aab564ac6e3c68ce7b87407a73df0..9d2298a704b9eb52fec27bf41e4c152af4a173e1 100644 (file)
@@ -9491,6 +9491,11 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
             cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
           PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
                                                                       Loc));
+        else if (Function->getTemplateInstantiationPattern()->isConstexpr())
+          // Do not defer instantiations of constexpr functions, to avoid the
+          // expression evaluator needing to call back into Sema if it sees a
+          // call to such a function.
+          InstantiateFunctionDefinition(Loc, Function);
         else
           PendingInstantiations.push_back(std::make_pair(Function, Loc));
       }
@@ -9526,9 +9531,9 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
         // This is a modification of an existing AST node. Notify listeners.
         if (ASTMutationListener *L = getASTMutationListener())
           L->StaticDataMemberInstantiated(Var);
-        QualType T = Var->getType();
-        if (T.isConstQualified() && !T.isVolatileQualified() &&
-            T->isIntegralOrEnumerationType())
+        if (Var->isUsableInConstantExpressions())
+          // Do not defer instantiations of variables which could be used in a
+          // constant expression.
           InstantiateStaticDataMemberDefinition(Loc, Var);
         else
           PendingInstantiations.push_back(std::make_pair(Var, Loc));
index 0fb6f7def00a0b64a1828807d54be75c4804e61e..809a0cb1763120efd9f3101122c34f3500a8426c 100644 (file)
@@ -68,7 +68,7 @@ struct ConstexprDtor {
 };
 
 // template stuff
-template <typename T> constexpr T ft(T t) { return t; } // unexpected-note {{here}}
+template <typename T> constexpr T ft(T t) { return t; }
 template <typename T> T gt(T t) { return t; }
 struct S {
   template<typename T> constexpr T f();
@@ -89,8 +89,7 @@ template <> int S::g() const; // desired-error {{non-constexpr declaration of 'g
 template <> char S::g() { return 0; } // expected-error {{no function template matches}}
 template <> double S::g() const { return 0; } // ok
 
-// FIXME: The initializer is a constant expression.
-constexpr int i3 = ft(1); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{undefined function 'ft<int>'}}
+constexpr int i3 = ft(1);
 
 void test() {
   // ignore constexpr when instantiating with non-literal
index 5798eb594852fbabc596942c9a5c3ce9772bf945..b470c80619dbcc561c979aa2168439afab5f7049 100644 (file)
@@ -8,16 +8,17 @@ static_assert(false, "test"); // expected-error {{test}}
 
 }
 
-template<typename T> constexpr T id(const T &t) { return t; } // expected-note {{here}}
-// FIXME: support templates here.
-//template<typename T> constexpr T min(const T &a, const T &b) {
-//  return a < b ? a : b;
-//}
-//template<typename T> constexpr T max(const T &a, const T &b) {
-//  return a < b ? b : a;
-//}
-constexpr int min(const int &a, const int &b) { return a < b ? a : b; }
-constexpr int max(const int &a, const int &b) { return a < b ? b : a; }
+typedef decltype(sizeof(char)) size_t;
+
+template<typename T> constexpr T id(const T &t) { return t; }
+template<typename T> constexpr T min(const T &a, const T &b) {
+  return a < b ? a : b;
+}
+template<typename T> constexpr T max(const T &a, const T &b) {
+  return a < b ? b : a;
+}
+template<typename T, size_t N> constexpr T *begin(T (&xs)[N]) { return xs; }
+template<typename T, size_t N> constexpr T *end(T (&xs)[N]) { return xs + N; }
 
 struct MemberZero {
   constexpr int zero() { return 0; }
@@ -84,8 +85,7 @@ namespace TemplateArgumentConversion {
   template<int n> struct IntParam {};
 
   using IntParam0 = IntParam<0>;
-  // FIXME: This should be accepted once we implement the new ICE rules.
-  using IntParam0 = IntParam<id(0)>; // expected-error {{not an integral constant expression}}
+  using IntParam0 = IntParam<id(0)>;
   using IntParam0 = IntParam<MemberZero().zero>; // expected-error {{did you mean to call it with no arguments?}} expected-error {{not an integral constant expression}}
 }
 
@@ -94,8 +94,7 @@ namespace CaseStatements {
     switch (n) {
     // FIXME: Produce the 'add ()' fixit for this.
     case MemberZero().zero: // desired-error {{did you mean to call it with no arguments?}} expected-error {{not an integer constant expression}} expected-note {{non-literal type '<bound member function type>'}}
-    // FIXME: This should be accepted once we implement the new ICE rules.
-    case id(1): // expected-error {{not an integer constant expression}} expected-note {{undefined function}}
+    case id(1):
       return;
     }
   }
@@ -352,14 +351,8 @@ constexpr int strcmp_ce(const char *p, const char *q) {
 
 namespace StringLiteral {
 
-// FIXME: Refactor this once we support constexpr templates.
-constexpr int MangleChars(const char *p) {
-  return *p + 3 * (*p ? MangleChars(p+1) : 0);
-}
-constexpr int MangleChars(const char16_t *p) {
-  return *p + 3 * (*p ? MangleChars(p+1) : 0);
-}
-constexpr int MangleChars(const char32_t *p) {
+template<typename Char>
+constexpr int MangleChars(const Char *p) {
   return *p + 3 * (*p ? MangleChars(p+1) : 0);
 }
 
@@ -383,9 +376,6 @@ constexpr const char *max_element(const char *a, const char *b) {
   return (a+1 >= b) ? a : max_iter(a, max_element(a+1, b));
 }
 
-constexpr const char *begin(const char (&arr)[45]) { return arr; }
-constexpr const char *end(const char (&arr)[45]) { return arr + 45; }
-
 constexpr char str[] = "the quick brown fox jumped over the lazy dog";
 constexpr const char *max = max_element(begin(str), end(str));
 static_assert(*max == 'z', "");
@@ -400,12 +390,10 @@ static_assert(strcmp_ce("", " ") < 0, "");
 
 namespace Array {
 
-// FIXME: Use templates for these once we support constexpr templates.
-constexpr int Sum(const int *begin, const int *end) {
+template<typename Iter>
+constexpr auto Sum(Iter begin, Iter end) -> decltype(+*begin) {
   return begin == end ? 0 : *begin + Sum(begin+1, end);
 }
-constexpr const int *begin(const int (&xs)[5]) { return xs; }
-constexpr const int *end(const int (&xs)[5]) { return xs + 5; }
 
 constexpr int xs[] = { 1, 2, 3, 4, 5 };
 constexpr int ys[] = { 5, 4, 3, 2, 1 };