forked from OSchip/llvm-project
Cope with an amusingly little anomaly with dependent types and
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). llvm-svn: 89366
This commit is contained in:
parent
1d9f1fe7cc
commit
ad2956c25d
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>();
|
||||
|
Loading…
Reference in New Issue