From 2dfdb820ca550f75769f6850bc27f825f1dce4f7 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Thu, 5 Nov 2009 15:52:31 +0000 Subject: [PATCH] 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 --- clang/lib/AST/ASTContext.cpp | 3 +- clang/lib/AST/Type.cpp | 6 +++ clang/lib/Sema/SemaType.cpp | 46 ++++++++++++------- .../CXX/dcl.decl/dcl.meaning/dcl.array/p1.cpp | 44 ++++++++++++++++++ 4 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p1.cpp diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index d1b7a364d807..8562249479ca 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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 diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 3608d34c691d..779f6808b6c1 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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(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(CanonicalType)->getElementType()->isIncompleteType(); case IncompleteArray: // An array of unknown size is an incomplete type (C99 6.2.5p22). return true; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 1a8111c55106..f003127f149f 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -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()) { + // class template specialization, or an array with known size of such, + // try to instantiate it. + QualType MaybeTemplate = T; + if (const ConstantArrayType *Array = T->getAs()) + MaybeTemplate = Array->getElementType(); + if (const RecordType *Record = MaybeTemplate->getAs()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast(Record->getDecl())) { if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p1.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p1.cpp new file mode 100644 index 000000000000..93c955f736d9 --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p1.cpp @@ -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 struct S { + typename T::type x; // expected-error {{has no members}} +}; +S ar10[10]; // expected-note {{requested here}}