Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -1910,6 +1910,10 @@ /// \brief Return number of constant array elements. uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const; + /// \brief Determine whether the given type is an incomplete or zero-length + /// array type. + bool isIncompleteOrZeroLengthArrayType(QualType T) const; + /// \brief Perform adjustment on the parameter type of a function. /// /// This routine adjusts the given parameter type @p T to the actual Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -4323,6 +4323,20 @@ return ElementCount; } +bool ASTContext::isIncompleteOrZeroLengthArrayType(QualType T) const { + if (T->isIncompleteArrayType()) + return true; + + while (const ConstantArrayType *ArrayT = getAsConstantArrayType(T)) { + if (!ArrayT->getSize()) + return true; + + T = ArrayT->getElementType(); + } + + return false; +} + /// getFloatingRank - Return a relative rank for floating point types. /// This routine will assert if passed a built-in type that isn't a float. static FloatingRank getFloatingRank(QualType T) { Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -12618,7 +12618,7 @@ FieldDecl *FD = cast(*i); // Get the type for the field. - const Type *FDTy = FD->getType().getTypePtr(); + QualType FDTy = FD->getType(); if (!FD->isAnonymousStructOrUnion()) { // Remember all fields written by the user. @@ -12649,10 +12649,9 @@ FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (FDTy->isIncompleteArrayType() && Record && + } else if (Context.isIncompleteOrZeroLengthArrayType(FDTy) && Record && ((i + 1 == Fields.end() && !Record->isUnion()) || - ((getLangOpts().MicrosoftExt || - getLangOpts().CPlusPlus) && + ((getLangOpts().MicrosoftExt || getLangOpts().CPlusPlus) && (i + 1 == Fields.end() || Record->isUnion())))) { // Flexible array member. // Microsoft and g++ is more permissive regarding flexible array. @@ -12674,7 +12673,7 @@ ? diag::err_flexible_array_empty_aggregate : 0; - if (DiagID) + if (DiagID && FDTy->isIncompleteArrayType()) Diag(FD->getLocation(), DiagID) << FD->getDeclName() << Record->getTagKind(); // While the layout of types that contain virtual bases is not specified Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3526,22 +3526,6 @@ }; } -/// \brief Determine whether the given type is an incomplete or zero-lenfgth -/// array type. -static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) { - if (T->isIncompleteArrayType()) - return true; - - while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) { - if (!ArrayT->getSize()) - return true; - - T = ArrayT->getElementType(); - } - - return false; -} - static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, FieldDecl *Field, IndirectFieldDecl *Indirect = nullptr) { @@ -3586,7 +3570,7 @@ } // Don't initialize incomplete or zero-length arrays. - if (isIncompleteOrZeroLengthArrayType(SemaRef.Context, Field->getType())) + if (SemaRef.Context.isIncompleteOrZeroLengthArrayType(Field->getType())) return false; // Don't try to build an implicit initializer if there were semantic @@ -4071,7 +4055,7 @@ continue; // Don't destroy incomplete or zero-length arrays. - if (isIncompleteOrZeroLengthArrayType(Context, Field->getType())) + if (Context.isIncompleteOrZeroLengthArrayType(Field->getType())) continue; QualType FieldType = Context.getBaseElementType(Field->getType()); Index: test/Analysis/dtors-in-dtor-cfg-output.cpp =================================================================== --- test/Analysis/dtors-in-dtor-cfg-output.cpp +++ test/Analysis/dtors-in-dtor-cfg-output.cpp @@ -27,7 +27,6 @@ class TestArray { A a[2]; - A b[0]; public: ~TestArray(); }; Index: test/CodeGenObjC/arc-captured-32bit-block-var-layout.m =================================================================== --- test/CodeGenObjC/arc-captured-32bit-block-var-layout.m +++ test/CodeGenObjC/arc-captured-32bit-block-var-layout.m @@ -152,10 +152,10 @@ void arr3() { struct S { int a; - __unsafe_unretained id unsafe_unretained_var[0]; + __unsafe_unretained id unsafe_unretained_var[7]; } imported_s; -// CHECK: block variable layout: BL_OPERATOR:0 +// CHECK: block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINED:7, BL_OPERATOR:0 void (^c)() = ^{ int i = imported_s.a; }; Index: test/CodeGenObjC/arc-captured-block-var-layout.m =================================================================== --- test/CodeGenObjC/arc-captured-block-var-layout.m +++ test/CodeGenObjC/arc-captured-block-var-layout.m @@ -151,10 +151,10 @@ void arr3() { struct S { int a; - __unsafe_unretained id unsafe_unretained_var[0]; + __unsafe_unretained id unsafe_unretained_var[7]; } imported_s; -// CHECK-LP64: block variable layout: BL_OPERATOR:0 +// CHECK-LP64: block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINED:7, BL_OPERATOR:0 void (^c)() = ^{ int i = imported_s.a; }; Index: test/SemaCXX/flexible-array-test.cpp =================================================================== --- test/SemaCXX/flexible-array-test.cpp +++ test/SemaCXX/flexible-array-test.cpp @@ -94,3 +94,15 @@ ntd[i-1].~NonTrivDtor(); } }; + +namespace PR21040 { +struct A { + int a0[0]; +}; + +struct B : private A { // expected-error {{base class 'A' has a flexible array member}} + int b; +}; + +B bb; +} Index: test/SemaCXX/zero-length-arrays.cpp =================================================================== --- test/SemaCXX/zero-length-arrays.cpp +++ test/SemaCXX/zero-length-arrays.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics // class Foo { @@ -11,9 +10,7 @@ class Bar { int foo_count; - Foo foos[0]; - Foo foos2[0][2]; - Foo foos3[2][0]; + Foo foos[0]; // expected-error-re {{flexible array member {{.*}} with non-trivial destruction}} public: Bar(): foo_count(0) { }