diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index c28bafe9a30f..2284b3871ed4 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -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 /// 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; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index dc13e7f4688c..aced8c7623f6 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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, diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 0f973d6d9ba3..fbc4680f8f2f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -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/clang/test/SemaTemplate/dependent-sized_array.cpp b/clang/test/SemaTemplate/dependent-sized_array.cpp new file mode 100644 index 000000000000..77b2bdce30f0 --- /dev/null +++ b/clang/test/SemaTemplate/dependent-sized_array.cpp @@ -0,0 +1,10 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template +void f() { + int a[] = { 1, 2, 3, N }; + unsigned numAs = sizeof(a) / sizeof(int); +} + +template void f<17>(); +