]> granicus.if.org Git - clang/commitdiff
Cope with an amusingly little anomaly with dependent types and
authorDouglas Gregor <dgregor@apple.com>
Thu, 19 Nov 2009 18:03:26 +0000 (18:03 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 19 Nov 2009 18:03:26 +0000 (18:03 +0000)
incomplete array initialization, where we have the following in a
template:

  int a[] = { 1, 2, something-value-dependent };
  // ...
  sizeof(a);

The type of "a" appears to be a non-dependent IncompleteArrayType, but
treating it as such makes the sizeof(a) fail at template definition
time. We now correctly handle this by morphing the IncompleteArrayType
into a DependentSizedArrayType with a NULL expression, indicating that
its size has no corresponding expression (and, therefore, the type is
distinct from others).

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

include/clang/AST/Type.h
lib/AST/ASTContext.cpp
lib/Sema/SemaInit.cpp
test/SemaTemplate/dependent-sized_array.cpp [new file with mode: 0644]

index c28bafe9a30f1915e467fd8d06730ec0ade47a42..2284b3871ed41c1350b3d1b45e0dfe8a02673e42 100644 (file)
@@ -1457,21 +1457,27 @@ public:
 
 /// DependentSizedArrayType - This type represents an array type in
 /// C++ whose size is a value-dependent expression. For example:
-/// @code
+///
+/// \code
 /// template<typename T, int Size>
 /// class array {
 ///   T data[Size];
 /// };
-/// @endcode
+/// \endcode
+///
 /// For these types, we won't actually know what the array bound is
 /// until template instantiation occurs, at which point this will
 /// become either a ConstantArrayType or a VariableArrayType.
 class DependentSizedArrayType : public ArrayType {
   ASTContext &Context;
 
-  /// SizeExpr - An assignment expression that will instantiate to the
+  /// \brief An assignment expression that will instantiate to the
   /// size of the array.
+  ///
+  /// The expression itself might be NULL, in which case the array
+  /// type will have its size deduced from an initializer.
   Stmt *SizeExpr;
+
   /// Brackets - The left and right array brackets.
   SourceRange Brackets;
 
index dc13e7f4688cc9c3aef5b0ef1237fbf4c124b1a7..aced8c7623f6c1ef815e9d6c1d5c00ccb0763df5 100644 (file)
@@ -1460,16 +1460,24 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
                                                 ArrayType::ArraySizeModifier ASM,
                                                 unsigned EltTypeQuals,
                                                 SourceRange Brackets) {
-  assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) &&
+  assert((!NumElts || NumElts->isTypeDependent() || 
+          NumElts->isValueDependent()) &&
          "Size must be type- or value-dependent!");
 
-  llvm::FoldingSetNodeID ID;
-  DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
-                                   EltTypeQuals, NumElts);
-
   void *InsertPos = 0;
-  DependentSizedArrayType *Canon
-    = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+  DependentSizedArrayType *Canon = 0;
+
+  if (NumElts) {
+    // Dependently-sized array types that do not have a specified
+    // number of elements will have their sizes deduced from an
+    // initializer.
+    llvm::FoldingSetNodeID ID;
+    DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
+                                     EltTypeQuals, NumElts);
+
+    Canon = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+  }
+
   DependentSizedArrayType *New;
   if (Canon) {
     // We already have a canonical version of this array type; use it as
@@ -1483,7 +1491,9 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
       New = new (*this, TypeAlignment)
         DependentSizedArrayType(*this, EltTy, QualType(),
                                 NumElts, ASM, EltTypeQuals, Brackets);
-      DependentSizedArrayTypes.InsertNode(New, InsertPos);
+
+      if (NumElts)
+        DependentSizedArrayTypes.InsertNode(New, InsertPos);
     } else {
       QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts,
                                                   ASM, EltTypeQuals,
index 0f973d6d9ba3bf6eb6edcd1f5b859689d3893545..fbc4680f8f2f071ae7fa522d6f0e64bf985f1a1f 100644 (file)
@@ -136,8 +136,29 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
                                  SourceLocation InitLoc,
                                  DeclarationName InitEntity, bool DirectInit) {
   if (DeclType->isDependentType() ||
-      Init->isTypeDependent() || Init->isValueDependent())
+      Init->isTypeDependent() || Init->isValueDependent()) {
+    // We have either a dependent type or a type- or value-dependent
+    // initializer, so we don't perform any additional checking at
+    // this point.
+
+    // If the declaration is a non-dependent, incomplete array type
+    // that has an initializer, then its type will be completed once
+    // the initializer is instantiated, meaning that the type is
+    // dependent. Morph the declaration's type into a
+    // dependently-sized array type.
+    if (!DeclType->isDependentType()) {
+      if (const IncompleteArrayType *ArrayT
+                           = Context.getAsIncompleteArrayType(DeclType)) {
+        DeclType = Context.getDependentSizedArrayType(ArrayT->getElementType(),
+                                                      /*NumElts=*/0,
+                                                     ArrayT->getSizeModifier(),
+                                           ArrayT->getIndexTypeCVRQualifiers(),
+                                                      SourceRange());
+      }
+    }
+
     return false;
+  }
 
   // C++ [dcl.init.ref]p1:
   //   A variable declared to be a T& or T&&, that is "reference to type T"
diff --git a/test/SemaTemplate/dependent-sized_array.cpp b/test/SemaTemplate/dependent-sized_array.cpp
new file mode 100644 (file)
index 0000000..77b2bdc
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<int N>
+void f() {
+  int a[] = { 1, 2, 3, N };
+  unsigned numAs = sizeof(a) / sizeof(int);
+}
+
+template void f<17>();
+