forked from OSchip/llvm-project
Allow the element type of arrays to be incomplete in C++.
This fixes PR5048. Also fix a bug where zero-sized arrays weren't warned about when the size was unsigned. llvm-svn: 86136
This commit is contained in:
parent
39c2a8bbbc
commit
2dfdb820ca
|
@ -1395,7 +1395,8 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
|
|||
const llvm::APInt &ArySizeIn,
|
||||
ArrayType::ArraySizeModifier ASM,
|
||||
unsigned EltTypeQuals) {
|
||||
assert((EltTy->isDependentType() || EltTy->isConstantSizeType()) &&
|
||||
assert((EltTy->isDependentType() ||
|
||||
EltTy->isIncompleteType() || EltTy->isConstantSizeType()) &&
|
||||
"Constant array of VLAs is illegal!");
|
||||
|
||||
// Convert the array size into a canonical width matching the pointer size for
|
||||
|
|
|
@ -550,6 +550,12 @@ bool Type::isIncompleteType() const {
|
|||
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
|
||||
// forward declaration, but not a full definition (C99 6.2.5p22).
|
||||
return !cast<TagType>(CanonicalType)->getDecl()->isDefinition();
|
||||
case ConstantArray:
|
||||
// An array is incomplete if its element type is incomplete
|
||||
// (C++ [dcl.array]p1).
|
||||
// We don't handle variable arrays (they're not allowed in C++) or
|
||||
// dependent-sized arrays (dependent types are never treated as incomplete).
|
||||
return cast<ArrayType>(CanonicalType)->getElementType()->isIncompleteType();
|
||||
case IncompleteArray:
|
||||
// An array of unknown size is an incomplete type (C99 6.2.5p22).
|
||||
return true;
|
||||
|
|
|
@ -563,9 +563,17 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
|
|||
SourceLocation Loc = Brackets.getBegin();
|
||||
// C99 6.7.5.2p1: If the element type is an incomplete or function type,
|
||||
// reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
|
||||
if (RequireCompleteType(Loc, T,
|
||||
diag::err_illegal_decl_array_incomplete_type))
|
||||
return QualType();
|
||||
// Not in C++, though. There we only dislike void.
|
||||
if (getLangOptions().CPlusPlus) {
|
||||
if (T->isVoidType()) {
|
||||
Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T;
|
||||
return QualType();
|
||||
}
|
||||
} else {
|
||||
if (RequireCompleteType(Loc, T,
|
||||
diag::err_illegal_decl_array_incomplete_type))
|
||||
return QualType();
|
||||
}
|
||||
|
||||
if (T->isFunctionType()) {
|
||||
Diag(Loc, diag::err_illegal_decl_array_of_functions)
|
||||
|
@ -613,24 +621,24 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
|
|||
} else if (ArraySize->isValueDependent()) {
|
||||
T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets);
|
||||
} else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
|
||||
(!T->isDependentType() && !T->isConstantSizeType())) {
|
||||
(!T->isDependentType() && !T->isIncompleteType() &&
|
||||
!T->isConstantSizeType())) {
|
||||
// Per C99, a variable array is an array with either a non-constant
|
||||
// size or an element type that has a non-constant-size
|
||||
T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets);
|
||||
} else {
|
||||
// C99 6.7.5.2p1: If the expression is a constant expression, it shall
|
||||
// have a value greater than zero.
|
||||
if (ConstVal.isSigned()) {
|
||||
if (ConstVal.isNegative()) {
|
||||
Diag(ArraySize->getLocStart(),
|
||||
diag::err_typecheck_negative_array_size)
|
||||
<< ArraySize->getSourceRange();
|
||||
return QualType();
|
||||
} else if (ConstVal == 0) {
|
||||
// GCC accepts zero sized static arrays.
|
||||
Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
|
||||
<< ArraySize->getSourceRange();
|
||||
}
|
||||
if (ConstVal.isSigned() && ConstVal.isNegative()) {
|
||||
Diag(ArraySize->getLocStart(),
|
||||
diag::err_typecheck_negative_array_size)
|
||||
<< ArraySize->getSourceRange();
|
||||
return QualType();
|
||||
}
|
||||
if (ConstVal == 0) {
|
||||
// GCC accepts zero sized static arrays.
|
||||
Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
|
||||
<< ArraySize->getSourceRange();
|
||||
}
|
||||
T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
|
||||
}
|
||||
|
@ -1692,8 +1700,12 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
|
|||
return false;
|
||||
|
||||
// If we have a class template specialization or a class member of a
|
||||
// class template specialization, try to instantiate it.
|
||||
if (const RecordType *Record = T->getAs<RecordType>()) {
|
||||
// class template specialization, or an array with known size of such,
|
||||
// try to instantiate it.
|
||||
QualType MaybeTemplate = T;
|
||||
if (const ConstantArrayType *Array = T->getAs<ConstantArrayType>())
|
||||
MaybeTemplate = Array->getElementType();
|
||||
if (const RecordType *Record = MaybeTemplate->getAs<RecordType>()) {
|
||||
if (ClassTemplateSpecializationDecl *ClassTemplateSpec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
|
||||
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared)
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// RUN: clang-cc -fsyntax-only -pedantic -verify %s
|
||||
|
||||
// Simple form
|
||||
int ar1[10];
|
||||
|
||||
// Element type cannot be:
|
||||
// - (cv) void
|
||||
volatile void ar2[10]; // expected-error {{incomplete element type 'void volatile'}}
|
||||
// - a reference
|
||||
int& ar3[10]; // expected-error {{array of references}}
|
||||
// - a function type
|
||||
typedef void Fn();
|
||||
Fn ar4[10]; // expected-error {{array of functions}}
|
||||
// - an abstract class
|
||||
struct Abstract { virtual void fn() = 0; }; // expected-note {{pure virtual}}
|
||||
Abstract ar5[10]; // expected-error {{abstract class}}
|
||||
|
||||
// If we have a size, it must be greater than zero.
|
||||
int ar6[-1]; // expected-error {{array size is negative}}
|
||||
int ar7[0u]; // expected-warning {{zero size arrays are an extension}}
|
||||
|
||||
// An array with unknown bound is incomplete.
|
||||
int ar8[]; // FIXME: This needs to fail!
|
||||
// So is an array with an incomplete element type.
|
||||
struct Incomplete; // expected-note {{forward declaration}}
|
||||
Incomplete ar9[10]; // expected-error {{incomplete type}}
|
||||
// Neither of which should be a problem in situations where no complete type
|
||||
// is required. (PR5048)
|
||||
void fun(int p1[], Incomplete p2[10]);
|
||||
extern int ear1[];
|
||||
extern Incomplete ear2[10];
|
||||
|
||||
// cv migrates to element type
|
||||
typedef const int cint;
|
||||
extern cint car1[10];
|
||||
typedef int intar[10];
|
||||
// thus this is a valid redeclaration
|
||||
extern const intar car1;
|
||||
|
||||
// Check that instantiation works properly when the element type is a template.
|
||||
template <typename T> struct S {
|
||||
typename T::type x; // expected-error {{has no members}}
|
||||
};
|
||||
S<int> ar10[10]; // expected-note {{requested here}}
|
Loading…
Reference in New Issue