diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-10-03 20:36:00 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-10-03 20:36:00 +0000 |
commit | 283e2076f6a6f23629475a25c64173843e72cf61 (patch) | |
tree | bd89ce68e591932aa9361e034111d3c9959879c9 /clang/lib/Sema | |
parent | 389b7cedc311c785d9060d83197b555d227b4d7d (diff) | |
download | bcm5719-llvm-283e2076f6a6f23629475a25c64173843e72cf61.tar.gz bcm5719-llvm-283e2076f6a6f23629475a25c64173843e72cf61.zip |
Suppress -Wmissing-braces warning when aggregate-initializing a struct with a single field that is itself an aggregate.
In C++, such initialization of std::array<T, N> types is guaranteed to work by
the standard, is completely idiomatic, and the "suggested" alternative from
Clang was technically invalid.
llvm-svn: 314838
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 341e7120fe8..dc7fe1d92b0 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -826,6 +826,34 @@ int InitListChecker::numStructUnionElements(QualType DeclType) { return InitializableMembers - structDecl->hasFlexibleArrayMember(); } +/// Determine whether Entity is an entity for which it is idiomatic to elide +/// the braces in aggregate initialization. +static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) { + // Recursive initialization of the one and only field within an aggregate + // class is considered idiomatic. This case arises in particular for + // initialization of std::array, where the C++ standard suggests the idiom of + // + // std::array<T, N> arr = {1, 2, 3}; + // + // (where std::array is an aggregate struct containing a single array field. + + // FIXME: Should aggregate initialization of a struct with a single + // base class and no members also suppress the warning? + if (Entity.getKind() != InitializedEntity::EK_Member || !Entity.getParent()) + return false; + + auto *ParentRD = + Entity.getParent()->getType()->castAs<RecordType>()->getDecl(); + if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) + if (CXXRD->getNumBases()) + return false; + + auto FieldIt = ParentRD->field_begin(); + assert(FieldIt != ParentRD->field_end() && + "no fields but have initializer for member?"); + return ++FieldIt == ParentRD->field_end(); +} + /// Check whether the range of the initializer \p ParentIList from element /// \p Index onwards can be used to initialize an object of type \p T. Update /// \p Index to indicate how many elements of the list were consumed. @@ -887,7 +915,8 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, // Complain about missing braces. if ((T->isArrayType() || T->isRecordType()) && - !ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts())) { + !ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && + !isIdiomaticBraceElisionEntity(Entity)) { SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), diag::warn_missing_braces) << StructuredSubobjectInitList->getSourceRange() |