r210091 - Implement DR990 and DR1070. Aggregate initialization initializes uninitialized

Nico Weber thakis at chromium.org
Mon Jun 30 11:22:04 PDT 2014


On Fri, Jun 27, 2014 at 12:56 PM, Richard Smith <richard at metafoo.co.uk>
wrote:

> On Fri, Jun 27, 2014 at 12:33 PM, Nico Weber <thakis at chromium.org> wrote:
>
>> I played with this some. The simplest thing is to use the C++03 logic in
>> system headers, but then system headers will always stay broken. Then I
>> tried only falling back to C++03 for known containers like you suggest –
>> this turned out to be fairly ugly, since libstdc++ put them in
>> std::__debug, stlport in std:: (but it doesn't really have a predictable
>> namespace; depending on defines it uses one out of several possible names
>> for its namespace), and there's a bunch of containers.
>>
>> I've now arrived at falling back to 03 logic only for the constructor
>> failure, but with a warning (which is suppressed in system headers by
>> default, but is visible when building with -Wsystem-headers), this seems
>> like the least bad approach to me. The attached patch implements this. Do
>> you think this is ok?
>>
>
> The standard library has classes with explicit default constructors that
> are not covered by LWG2193 (throughout iostreams and in regex's
> match_result). This workaround shouldn't apply to them, or else this could
> do the wrong thing in a SFINAE context or send overload resolution the
> wrong way. So that brings us back to having a list.
>

Great point, as usual, thanks.


> Is this std::__debug an inline namespace? (Even if not, it shouldn't be
> difficult to walk out of it and find if we're in 'std'.)
>
> Please add a note to the diagnostic indicating where the constructor was
> used.
>

Done.

Updated patch attached, as promised it's uglier :-) I added a few more
changes to limit this more: It now checks if the ctor has 0 required
arguments, and that it's explicit. (Is isExplicitSpecified() or
isExplicit() the right call for this?)


>
> On Thu, Jun 26, 2014 at 2:13 PM, Richard Smith <richard at metafoo.co.uk>
> wrote:
>
>>  Either that, or detect an explicit default constructor for standard
>>> library containers and pretend they're not explicit.
>>>  On 26 Jun 2014 21:25, "Nico Weber" <thakis at chromium.org> wrote:
>>>
>>>> On Mon, Jun 23, 2014 at 6:08 PM, Nico Weber <thakis at chromium.org>
>>>> wrote:
>>>>
>>>>> On Thu, Jun 5, 2014 at 9:23 AM, Nico Weber <thakis at chromium.org>
>>>>> wrote:
>>>>>
>>>>>> On Thu, Jun 5, 2014 at 1:49 AM, Richard Smith <richard at metafoo.co.uk>
>>>>>> wrote:
>>>>>>
>>>>>>> On Wed, Jun 4, 2014 at 9:54 AM, Evgeniy Stepanov <
>>>>>>> eugeni.stepanov at gmail.com> wrote:
>>>>>>>
>>>>>>>> In fact, it may be some other commit that caused this.
>>>>>>>>
>>>>>>>> The actual problem is with stlport, which defines constructors for
>>>>>>>> all
>>>>>>>> containers this way. (i.e. no real default constructor).
>>>>>>>>
>>>>>>>
>>>>>>> That's ultimately a (fixed) bug in the C++ standard. See
>>>>>>>
>>>>>>>   http://cplusplus.github.io/LWG/lwg-defects.html#2193
>>>>>>>
>>>>>>>
>>>>>>>> This, in turn, breaks declarations like
>>>>>>>> class A { int x; int y; string z; } a = {{1, 1}, {2, 2}};
>>>>>>>>
>>>>>>>> Regression window is 209387 - 201180.
>>>>>>>
>>>>>>>
>>>>>>> OK, that behavioral difference is due to this change, and the new
>>>>>>> behavior is correct per the (C++11 plus DRs and C++14) standard.
>>>>>>>
>>>>>>>  stlport git trunk appears to still have the bug. Is it important
>>>>>>> for us to be able to support stlport? It seems unmaintained (no commits
>>>>>>> since 2012).
>>>>>>>
>>>>>>
>>>>>> It's a C++ standard library that's available in the Android NDK. The
>>>>>> other two standard libraries in there are libstdc++ (which some people
>>>>>> don't like using due to license reasons) and libc++ (which is great, but
>>>>>> we've only got all tests to pass this week, so it's not really usable in a
>>>>>> released NDK). So it's reasonably popular for NDK apps – chromium/android
>>>>>> uses it for example. So it'd be nice to have some short-term workaround.
>>>>>>
>>>>>
>>>>> Apparently, this also breaks our linux builds with libstdc++4.6.
>>>>>
>>>>
>>>> In particular, this doesn't build after this patch:
>>>>
>>>> $ cat test.cc
>>>> #include <vector>
>>>> struct { int a, b; std::vector<int> c; } e[] = { {1, 1}, {2, 2} };
>>>> $ ~/src/llvm-cmake/bin/clang -c test.cc -std=c++11  -D_GLIBCXX_DEBUG=1
>>>> test.cc:3:55: error: chosen constructor is explicit in
>>>> copy-initialization
>>>> struct { int a, b; std::vector<int> c; } e[] = { {1, 1}, {2, 2} };
>>>>                                                       ^
>>>> /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/debug/vector:77:7:
>>>> note: constructor declared here
>>>>       vector(const _Allocator& __a = _Allocator())
>>>>       ^
>>>> test.cc:3:37: note: in implicit initialization of field 'c' with
>>>> omitted initializer
>>>> struct { int a, b; std::vector<int> c; } e[] = { {1, 1}, {2, 2} };
>>>>                                     ^
>>>>
>>>> It builds fine with gcc, clang before this revision, or clang
>>>> without -D_GLIBCXX_DEBUG=1. Allowing this in system headers might be an
>>>> acceptable workaround?
>>>>
>>>>
>>>>>
>>>>>
>>>>>>  (https://code.google.com/p/chromium/issues/detail?id=381053>>>>>> sounds like there are no great client-side workarounds.)
>>>>>>
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>>  On Wed, Jun 4, 2014 at 8:47 PM, Richard Smith <
>>>>>>>> richard at metafoo.co.uk> wrote:
>>>>>>>> > On 4 Jun 2014 05:07, "Evgeniy Stepanov" <
>>>>>>>> eugeni.stepanov at gmail.com> wrote:
>>>>>>>> >>
>>>>>>>> >> Hi,
>>>>>>>> >>
>>>>>>>> >> This change is causing this to fail with -std=c++11:
>>>>>>>> >> struct A { explicit A(int x = 0) {(void)x;}; };
>>>>>>>> >> A a = {};
>>>>>>>> >> with error: chosen constructor is explicit in copy-initialization
>>>>>>>> >>
>>>>>>>> >> but this passes:
>>>>>>>> >> struct A { explicit A(int x = 0) {(void)x;}; };
>>>>>>>> >> A a{};
>>>>>>>> >>
>>>>>>>> >> Is it correct?
>>>>>>>> >
>>>>>>>> > It looks correct (but I need to double check, because the empty
>>>>>>>> list / class
>>>>>>>> > with default constructor case is a special case in the standard).
>>>>>>>> I'm
>>>>>>>> > surprised that code was affected by this change, though, since it
>>>>>>>> contains
>>>>>>>> > no aggregate initialization.
>>>>>>>> >
>>>>>>>> >> On Tue, Jun 3, 2014 at 12:26 PM, Richard Smith
>>>>>>>> >> <richard-llvm at metafoo.co.uk> wrote:
>>>>>>>> >> > Author: rsmith
>>>>>>>> >> > Date: Tue Jun  3 03:26:00 2014
>>>>>>>> >> > New Revision: 210091
>>>>>>>> >> >
>>>>>>>> >> > URL: http://llvm.org/viewvc/llvm-project?rev=210091&view=rev
>>>>>>>> >> > Log:
>>>>>>>> >> > Implement DR990 and DR1070. Aggregate initialization
>>>>>>>> initializes
>>>>>>>> >> > uninitialized
>>>>>>>> >> > elements from {}, rather than value-initializing them. This
>>>>>>>> permits
>>>>>>>> >> > calling an
>>>>>>>> >> > initializer-list constructor or constructing a
>>>>>>>> std::initializer_list
>>>>>>>> >> > object.
>>>>>>>> >> > (It would also permit initializing a const reference or rvalue
>>>>>>>> reference
>>>>>>>> >> > if
>>>>>>>> >> > that weren't explicitly prohibited by other rules.)
>>>>>>>> >> >
>>>>>>>> >> > Added:
>>>>>>>> >> >     cfe/trunk/test/CXX/drs/dr10xx.cpp
>>>>>>>> >> >     cfe/trunk/test/CXX/drs/dr9xx.cpp
>>>>>>>> >> > Modified:
>>>>>>>> >> >     cfe/trunk/include/clang/AST/Expr.h
>>>>>>>> >> >     cfe/trunk/include/clang/Sema/Initialization.h
>>>>>>>> >> >     cfe/trunk/lib/CodeGen/CGExprCXX.cpp
>>>>>>>> >> >     cfe/trunk/lib/Sema/SemaInit.cpp
>>>>>>>> >> >
>>>>>>>> cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
>>>>>>>> >> >     cfe/trunk/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
>>>>>>>> >> >     cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
>>>>>>>> >> >
>>>>>>>> cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
>>>>>>>> >> >     cfe/trunk/www/cxx_dr_status.html
>>>>>>>> >> >
>>>>>>>> >> > Modified: cfe/trunk/include/clang/AST/Expr.h
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=210091&r1=210090&r2=210091&view=diff
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > --- cfe/trunk/include/clang/AST/Expr.h (original)
>>>>>>>> >> > +++ cfe/trunk/include/clang/AST/Expr.h Tue Jun  3 03:26:00 2014
>>>>>>>> >> > @@ -3909,6 +3909,7 @@ public:
>>>>>>>> >> >
>>>>>>>> >> >    // Iterators
>>>>>>>> >> >    child_range children() {
>>>>>>>> >> > +    // FIXME: This does not include the array filler
>>>>>>>> expression.
>>>>>>>> >> >      if (InitExprs.empty()) return child_range();
>>>>>>>> >> >      return child_range(&InitExprs[0], &InitExprs[0] +
>>>>>>>> >> > InitExprs.size());
>>>>>>>> >> >    }
>>>>>>>> >> >
>>>>>>>> >> > Modified: cfe/trunk/include/clang/Sema/Initialization.h
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=210091&r1=210090&r2=210091&view=diff
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > --- cfe/trunk/include/clang/Sema/Initialization.h (original)
>>>>>>>> >> > +++ cfe/trunk/include/clang/Sema/Initialization.h Tue Jun  3
>>>>>>>> 03:26:00
>>>>>>>> >> > 2014
>>>>>>>> >> > @@ -401,6 +401,13 @@ public:
>>>>>>>> >> >      return
>>>>>>>> SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
>>>>>>>> >> >    }
>>>>>>>> >> >
>>>>>>>> >> > +  /// \brief If this is an array, vector, or complex number
>>>>>>>> element,
>>>>>>>> >> > get the
>>>>>>>> >> > +  /// element's index.
>>>>>>>> >> > +  unsigned getElementIndex() const {
>>>>>>>> >> > +    assert(getKind() == EK_ArrayElement || getKind() ==
>>>>>>>> >> > EK_VectorElement ||
>>>>>>>> >> > +           getKind() == EK_ComplexElement);
>>>>>>>> >> > +    return Index;
>>>>>>>> >> > +  }
>>>>>>>> >> >    /// \brief If this is already the initializer for an array
>>>>>>>> or vector
>>>>>>>> >> >    /// element, sets the element index.
>>>>>>>> >> >    void setElementIndex(unsigned Index) {
>>>>>>>> >> > @@ -851,17 +858,17 @@ public:
>>>>>>>> >> >    ///
>>>>>>>> >> >    /// \param Args the argument(s) provided for initialization.
>>>>>>>> >> >    ///
>>>>>>>> >> > -  /// \param InInitList true if we are initializing from an
>>>>>>>> expression
>>>>>>>> >> > within
>>>>>>>> >> > -  ///        an initializer list. This disallows narrowing
>>>>>>>> conversions
>>>>>>>> >> > in C++11
>>>>>>>> >> > -  ///        onwards.
>>>>>>>> >> > +  /// \param TopLevelOfInitList true if we are initializing
>>>>>>>> from an
>>>>>>>> >> > expression
>>>>>>>> >> > +  ///        at the top level inside an initializer list. This
>>>>>>>> >> > disallows
>>>>>>>> >> > +  ///        narrowing conversions in C++11 onwards.
>>>>>>>> >> >    InitializationSequence(Sema &S,
>>>>>>>> >> >                           const InitializedEntity &Entity,
>>>>>>>> >> >                           const InitializationKind &Kind,
>>>>>>>> >> >                           MultiExprArg Args,
>>>>>>>> >> > -                         bool InInitList = false);
>>>>>>>> >> > +                         bool TopLevelOfInitList = false);
>>>>>>>> >> >    void InitializeFrom(Sema &S, const InitializedEntity
>>>>>>>> &Entity,
>>>>>>>> >> >                        const InitializationKind &Kind,
>>>>>>>> MultiExprArg
>>>>>>>> >> > Args,
>>>>>>>> >> > -                      bool InInitList);
>>>>>>>> >> > +                      bool TopLevelOfInitList);
>>>>>>>> >> >
>>>>>>>> >> >    ~InitializationSequence();
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> >> > Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=210091&r1=210090&r2=210091&view=diff
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
>>>>>>>> >> > +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Tue Jun  3 03:26:00
>>>>>>>> 2014
>>>>>>>> >> > @@ -858,9 +858,21 @@ CodeGenFunction::EmitNewArrayInitializer
>>>>>>>> >> >      return true;
>>>>>>>> >> >    };
>>>>>>>> >> >
>>>>>>>> >> > +  // If all elements have already been initialized, skip any
>>>>>>>> further
>>>>>>>> >> > +  // initialization.
>>>>>>>> >> > +  llvm::ConstantInt *ConstNum =
>>>>>>>> >> > dyn_cast<llvm::ConstantInt>(NumElements);
>>>>>>>> >> > +  if (ConstNum && ConstNum->getZExtValue() <=
>>>>>>>> InitListElements) {
>>>>>>>> >> > +    // If there was a Cleanup, deactivate it.
>>>>>>>> >> > +    if (CleanupDominator)
>>>>>>>> >> > +      DeactivateCleanupBlock(Cleanup, CleanupDominator);
>>>>>>>> >> > +    return;
>>>>>>>> >> > +  }
>>>>>>>> >> > +
>>>>>>>> >> > +  assert(Init && "have trailing elements to initialize but no
>>>>>>>> >> > initializer");
>>>>>>>> >> > +
>>>>>>>> >> >    // If this is a constructor call, try to optimize it out,
>>>>>>>> and failing
>>>>>>>> >> > that
>>>>>>>> >> >    // emit a single loop to initialize all remaining elements.
>>>>>>>> >> > -  if (const CXXConstructExpr *CCE =
>>>>>>>> >> > dyn_cast_or_null<CXXConstructExpr>(Init)){
>>>>>>>> >> > +  if (const CXXConstructExpr *CCE =
>>>>>>>> dyn_cast<CXXConstructExpr>(Init)) {
>>>>>>>> >> >      CXXConstructorDecl *Ctor = CCE->getConstructor();
>>>>>>>> >> >      if (Ctor->isTrivial()) {
>>>>>>>> >> >        // If new expression did not specify
>>>>>>>> value-initialization, then
>>>>>>>> >> > there
>>>>>>>> >> > @@ -891,7 +903,7 @@ CodeGenFunction::EmitNewArrayInitializer
>>>>>>>> >> >
>>>>>>>> >> >    // If this is value-initialization, we can usually use
>>>>>>>> memset.
>>>>>>>> >> >    ImplicitValueInitExpr IVIE(ElementType);
>>>>>>>> >> > -  if (Init && isa<ImplicitValueInitExpr>(Init)) {
>>>>>>>> >> > +  if (isa<ImplicitValueInitExpr>(Init)) {
>>>>>>>> >> >      if (TryMemsetInitialization())
>>>>>>>> >> >        return;
>>>>>>>> >> >
>>>>>>>> >> > @@ -906,15 +918,10 @@ CodeGenFunction::EmitNewArrayInitializer
>>>>>>>> >> >    assert(getContext().hasSameUnqualifiedType(ElementType,
>>>>>>>> >> > Init->getType()) &&
>>>>>>>> >> >           "got wrong type of element to initialize");
>>>>>>>> >> >
>>>>>>>> >> > -  llvm::ConstantInt *ConstNum =
>>>>>>>> >> > dyn_cast<llvm::ConstantInt>(NumElements);
>>>>>>>> >> > -
>>>>>>>> >> > -  // If all elements have already been initialized, skip the
>>>>>>>> whole
>>>>>>>> >> > loop.
>>>>>>>> >> > -  if (ConstNum && ConstNum->getZExtValue() <=
>>>>>>>> InitListElements) {
>>>>>>>> >> > -    // If there was a Cleanup, deactivate it.
>>>>>>>> >> > -    if (CleanupDominator)
>>>>>>>> >> > -      DeactivateCleanupBlock(Cleanup, CleanupDominator);
>>>>>>>> >> > -    return;
>>>>>>>> >> > -  }
>>>>>>>> >> > +  // If we have an empty initializer list, we can usually use
>>>>>>>> memset.
>>>>>>>> >> > +  if (auto *ILE = dyn_cast<InitListExpr>(Init))
>>>>>>>> >> > +    if (ILE->getNumInits() == 0 && TryMemsetInitialization())
>>>>>>>> >> > +      return;
>>>>>>>> >> >
>>>>>>>> >> >    // Create the loop blocks.
>>>>>>>> >> >    llvm::BasicBlock *EntryBB = Builder.GetInsertBlock();
>>>>>>>> >> >
>>>>>>>> >> > Modified: cfe/trunk/lib/Sema/SemaInit.cpp
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=210091&r1=210090&r2=210091&view=diff
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > --- cfe/trunk/lib/Sema/SemaInit.cpp (original)
>>>>>>>> >> > +++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Jun  3 03:26:00 2014
>>>>>>>> >> > @@ -312,15 +312,20 @@ class InitListChecker {
>>>>>>>> >> >    int numArrayElements(QualType DeclType);
>>>>>>>> >> >    int numStructUnionElements(QualType DeclType);
>>>>>>>> >> >
>>>>>>>> >> > -  void FillInValueInitForField(unsigned Init, FieldDecl
>>>>>>>> *Field,
>>>>>>>> >> > +  static ExprResult PerformEmptyInit(Sema &SemaRef,
>>>>>>>> >> > +                                     SourceLocation Loc,
>>>>>>>> >> > +                                     const InitializedEntity
>>>>>>>> &Entity,
>>>>>>>> >> > +                                     bool VerifyOnly);
>>>>>>>> >> > +  void FillInEmptyInitForField(unsigned Init, FieldDecl
>>>>>>>> *Field,
>>>>>>>> >> >                                 const InitializedEntity
>>>>>>>> &ParentEntity,
>>>>>>>> >> >                                 InitListExpr *ILE, bool
>>>>>>>> >> > &RequiresSecondPass);
>>>>>>>> >> > -  void FillInValueInitializations(const InitializedEntity
>>>>>>>> &Entity,
>>>>>>>> >> > +  void FillInEmptyInitializations(const InitializedEntity
>>>>>>>> &Entity,
>>>>>>>> >> >                                    InitListExpr *ILE, bool
>>>>>>>> >> > &RequiresSecondPass);
>>>>>>>> >> >    bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
>>>>>>>> >> >                                Expr *InitExpr, FieldDecl
>>>>>>>> *Field,
>>>>>>>> >> >                                bool TopLevelObject);
>>>>>>>> >> > -  void CheckValueInitializable(const InitializedEntity
>>>>>>>> &Entity);
>>>>>>>> >> > +  void CheckEmptyInitializable(const InitializedEntity
>>>>>>>> &Entity,
>>>>>>>> >> > +                               SourceLocation Loc);
>>>>>>>> >> >
>>>>>>>> >> >  public:
>>>>>>>> >> >    InitListChecker(Sema &S, const InitializedEntity &Entity,
>>>>>>>> >> > @@ -333,33 +338,84 @@ public:
>>>>>>>> >> >  };
>>>>>>>> >> >  } // end anonymous namespace
>>>>>>>> >> >
>>>>>>>> >> > -void InitListChecker::CheckValueInitializable(const
>>>>>>>> InitializedEntity
>>>>>>>> >> > &Entity) {
>>>>>>>> >> > -  assert(VerifyOnly &&
>>>>>>>> >> > -         "CheckValueInitializable is only inteded for
>>>>>>>> verification
>>>>>>>> >> > mode.");
>>>>>>>> >> > -
>>>>>>>> >> > -  SourceLocation Loc;
>>>>>>>> >> > +ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
>>>>>>>> >> > +                                             SourceLocation
>>>>>>>> Loc,
>>>>>>>> >> > +                                             const
>>>>>>>> InitializedEntity
>>>>>>>> >> > &Entity,
>>>>>>>> >> > +                                             bool VerifyOnly)
>>>>>>>> {
>>>>>>>> >> >    InitializationKind Kind =
>>>>>>>> InitializationKind::CreateValue(Loc, Loc,
>>>>>>>> >> > Loc,
>>>>>>>> >> >
>>>>>>>>  true);
>>>>>>>> >> > -  InitializationSequence InitSeq(SemaRef, Entity, Kind, None);
>>>>>>>> >> > -  if (InitSeq.Failed())
>>>>>>>> >> > +  MultiExprArg SubInit;
>>>>>>>> >> > +  Expr *InitExpr;
>>>>>>>> >> > +  InitListExpr DummyInitList(SemaRef.Context, Loc, None, Loc);
>>>>>>>> >> > +
>>>>>>>> >> > +  // C++ [dcl.init.aggr]p7:
>>>>>>>> >> > +  //   If there are fewer initializer-clauses in the list
>>>>>>>> than there
>>>>>>>> >> > are
>>>>>>>> >> > +  //   members in the aggregate, then each member not
>>>>>>>> explicitly
>>>>>>>> >> > initialized
>>>>>>>> >> > +  //   ...
>>>>>>>> >> > +  if (SemaRef.getLangOpts().CPlusPlus11 &&
>>>>>>>> >> > +
>>>>>>>>  Entity.getType()->getBaseElementTypeUnsafe()->isRecordType()) {
>>>>>>>> >> > +    // C++1y / DR1070:
>>>>>>>> >> > +    //   shall be initialized [...] from an empty initializer
>>>>>>>> list.
>>>>>>>> >> > +    //
>>>>>>>> >> > +    // We apply the resolution of this DR to C++11 but not
>>>>>>>> C++98, since
>>>>>>>> >> > C++98
>>>>>>>> >> > +    // does not have useful semantics for initialization from
>>>>>>>> an init
>>>>>>>> >> > list.
>>>>>>>> >> > +    // We treat this as copy-initialization, because aggregate
>>>>>>>> >> > initialization
>>>>>>>> >> > +    // always performs copy-initialization on its elements.
>>>>>>>> >> > +    //
>>>>>>>> >> > +    // Only do this if we're initializing a class type, to
>>>>>>>> avoid
>>>>>>>> >> > filling in
>>>>>>>> >> > +    // the initializer list where possible.
>>>>>>>> >> > +    InitExpr = VerifyOnly ? &DummyInitList : new
>>>>>>>> (SemaRef.Context)
>>>>>>>> >> > +                   InitListExpr(SemaRef.Context, Loc, None,
>>>>>>>> Loc);
>>>>>>>> >> > +    InitExpr->setType(SemaRef.Context.VoidTy);
>>>>>>>> >> > +    SubInit = InitExpr;
>>>>>>>> >> > +    Kind = InitializationKind::CreateCopy(Loc, Loc);
>>>>>>>> >> > +  } else {
>>>>>>>> >> > +    // C++03:
>>>>>>>> >> > +    //   shall be value-initialized.
>>>>>>>> >> > +  }
>>>>>>>> >> > +
>>>>>>>> >> > +  InitializationSequence InitSeq(SemaRef, Entity, Kind,
>>>>>>>> SubInit);
>>>>>>>> >> > +  if (!InitSeq) {
>>>>>>>> >> > +    if (!VerifyOnly) {
>>>>>>>> >> > +      InitSeq.Diagnose(SemaRef, Entity, Kind, SubInit);
>>>>>>>> >> > +      if (Entity.getKind() == InitializedEntity::EK_Member)
>>>>>>>> >> > +        SemaRef.Diag(Entity.getDecl()->getLocation(),
>>>>>>>> >> > +
>>>>>>>> diag::note_in_omitted_aggregate_initializer)
>>>>>>>> >> > +          << /*field*/1 << Entity.getDecl();
>>>>>>>> >> > +      else if (Entity.getKind() ==
>>>>>>>> InitializedEntity::EK_ArrayElement)
>>>>>>>> >> > +        SemaRef.Diag(Loc,
>>>>>>>> diag::note_in_omitted_aggregate_initializer)
>>>>>>>> >> > +          << /*array element*/0 << Entity.getElementIndex();
>>>>>>>> >> > +    }
>>>>>>>> >> > +    return ExprError();
>>>>>>>> >> > +  }
>>>>>>>> >> > +
>>>>>>>> >> > +  return VerifyOnly ? ExprResult(static_cast<Expr *>(nullptr))
>>>>>>>> >> > +                    : InitSeq.Perform(SemaRef, Entity, Kind,
>>>>>>>> SubInit);
>>>>>>>> >> > +}
>>>>>>>> >> > +
>>>>>>>> >> > +void InitListChecker::CheckEmptyInitializable(const
>>>>>>>> InitializedEntity
>>>>>>>> >> > &Entity,
>>>>>>>> >> > +                                              SourceLocation
>>>>>>>> Loc) {
>>>>>>>> >> > +  assert(VerifyOnly &&
>>>>>>>> >> > +         "CheckEmptyInitializable is only inteded for
>>>>>>>> verification
>>>>>>>> >> > mode.");
>>>>>>>> >> > +  if (PerformEmptyInit(SemaRef, Loc, Entity,
>>>>>>>> >> > /*VerifyOnly*/true).isInvalid())
>>>>>>>> >> >      hadError = true;
>>>>>>>> >> >  }
>>>>>>>> >> >
>>>>>>>> >> > -void InitListChecker::FillInValueInitForField(unsigned Init,
>>>>>>>> FieldDecl
>>>>>>>> >> > *Field,
>>>>>>>> >> > +void InitListChecker::FillInEmptyInitForField(unsigned Init,
>>>>>>>> FieldDecl
>>>>>>>> >> > *Field,
>>>>>>>> >> >                                          const
>>>>>>>> InitializedEntity
>>>>>>>> >> > &ParentEntity,
>>>>>>>> >> >                                                InitListExpr
>>>>>>>> *ILE,
>>>>>>>> >> >                                                bool
>>>>>>>> &RequiresSecondPass)
>>>>>>>> >> > {
>>>>>>>> >> > -  SourceLocation Loc = ILE->getLocStart();
>>>>>>>> >> > +  SourceLocation Loc = ILE->getLocEnd();
>>>>>>>> >> >    unsigned NumInits = ILE->getNumInits();
>>>>>>>> >> >    InitializedEntity MemberEntity
>>>>>>>> >> >      = InitializedEntity::InitializeMember(Field,
>>>>>>>> &ParentEntity);
>>>>>>>> >> >    if (Init >= NumInits || !ILE->getInit(Init)) {
>>>>>>>> >> > -    // If there's no explicit initializer but we have a
>>>>>>>> default
>>>>>>>> >> > initializer, use
>>>>>>>> >> > -    // that. This only happens in C++1y, since classes with
>>>>>>>> default
>>>>>>>> >> > -    // initializers are not aggregates in C++11.
>>>>>>>> >> > +    // C++1y [dcl.init.aggr]p7:
>>>>>>>> >> > +    //   If there are fewer initializer-clauses in the list
>>>>>>>> than there
>>>>>>>> >> > are
>>>>>>>> >> > +    //   members in the aggregate, then each member not
>>>>>>>> explicitly
>>>>>>>> >> > initialized
>>>>>>>> >> > +    //   shall be initialized from its
>>>>>>>> brace-or-equal-initializer [...]
>>>>>>>> >> >      if (Field->hasInClassInitializer()) {
>>>>>>>> >> > -      Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context,
>>>>>>>> >> > -
>>>>>>>> ILE->getRBraceLoc(),
>>>>>>>> >> > Field);
>>>>>>>> >> > +      Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context,
>>>>>>>> Loc,
>>>>>>>> >> > Field);
>>>>>>>> >> >        if (Init < NumInits)
>>>>>>>> >> >          ILE->setInit(Init, DIE);
>>>>>>>> >> >        else {
>>>>>>>> >> > @@ -369,9 +425,6 @@ void InitListChecker::FillInValueInitFor
>>>>>>>> >> >        return;
>>>>>>>> >> >      }
>>>>>>>> >> >
>>>>>>>> >> > -    // FIXME: We probably don't need to handle references
>>>>>>>> >> > -    // specially here, since value-initialization of
>>>>>>>> references is
>>>>>>>> >> > -    // handled in InitializationSequence.
>>>>>>>> >> >      if (Field->getType()->isReferenceType()) {
>>>>>>>> >> >        // C++ [dcl.init.aggr]p9:
>>>>>>>> >> >        //   If an incomplete or empty initializer-list leaves a
>>>>>>>> >> > @@ -386,20 +439,8 @@ void InitListChecker::FillInValueInitFor
>>>>>>>> >> >        return;
>>>>>>>> >> >      }
>>>>>>>> >> >
>>>>>>>> >> > -    InitializationKind Kind =
>>>>>>>> InitializationKind::CreateValue(Loc, Loc,
>>>>>>>> >> > Loc,
>>>>>>>> >> > -
>>>>>>>>  true);
>>>>>>>> >> > -    InitializationSequence InitSeq(SemaRef, MemberEntity,
>>>>>>>> Kind, None);
>>>>>>>> >> > -    if (!InitSeq) {
>>>>>>>> >> > -      InitSeq.Diagnose(SemaRef, MemberEntity, Kind, None);
>>>>>>>> >> > -      SemaRef.Diag(Field->getLocation(),
>>>>>>>> >> > -
>>>>>>>> diag::note_in_omitted_aggregate_initializer)
>>>>>>>> >> > -        << /*field*/1 << Field;
>>>>>>>> >> > -      hadError = true;
>>>>>>>> >> > -      return;
>>>>>>>> >> > -    }
>>>>>>>> >> > -
>>>>>>>> >> > -    ExprResult MemberInit
>>>>>>>> >> > -      = InitSeq.Perform(SemaRef, MemberEntity, Kind, None);
>>>>>>>> >> > +    ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc,
>>>>>>>> >> > MemberEntity,
>>>>>>>> >> > +
>>>>>>>> /*VerifyOnly*/false);
>>>>>>>> >> >      if (MemberInit.isInvalid()) {
>>>>>>>> >> >        hadError = true;
>>>>>>>> >> >        return;
>>>>>>>> >> > @@ -409,8 +450,8 @@ void InitListChecker::FillInValueInitFor
>>>>>>>> >> >        // Do nothing
>>>>>>>> >> >      } else if (Init < NumInits) {
>>>>>>>> >> >        ILE->setInit(Init, MemberInit.getAs<Expr>());
>>>>>>>> >> > -    } else if (InitSeq.isConstructorInitialization()) {
>>>>>>>> >> > -      // Value-initialization requires a constructor call, so
>>>>>>>> >> > +    } else if (!isa<ImplicitValueInitExpr>(MemberInit.get()))
>>>>>>>> {
>>>>>>>> >> > +      // Empty initialization requires a constructor call, so
>>>>>>>> >> >        // extend the initializer list to include the
>>>>>>>> constructor
>>>>>>>> >> >        // call and make a note that we'll need to take another
>>>>>>>> pass
>>>>>>>> >> >        // through the initializer list.
>>>>>>>> >> > @@ -419,7 +460,7 @@ void InitListChecker::FillInValueInitFor
>>>>>>>> >> >      }
>>>>>>>> >> >    } else if (InitListExpr *InnerILE
>>>>>>>> >> >                 = dyn_cast<InitListExpr>(ILE->getInit(Init)))
>>>>>>>> >> > -    FillInValueInitializations(MemberEntity, InnerILE,
>>>>>>>> >> > +    FillInEmptyInitializations(MemberEntity, InnerILE,
>>>>>>>> >> >                                 RequiresSecondPass);
>>>>>>>> >> >  }
>>>>>>>> >> >
>>>>>>>> >> > @@ -427,7 +468,7 @@ void InitListChecker::FillInValueInitFor
>>>>>>>> >> >  /// with expressions that perform value-initialization of the
>>>>>>>> >> >  /// appropriate type.
>>>>>>>> >> >  void
>>>>>>>> >> > -InitListChecker::FillInValueInitializations(const
>>>>>>>> InitializedEntity
>>>>>>>> >> > &Entity,
>>>>>>>> >> > +InitListChecker::FillInEmptyInitializations(const
>>>>>>>> InitializedEntity
>>>>>>>> >> > &Entity,
>>>>>>>> >> >                                              InitListExpr *ILE,
>>>>>>>> >> >                                              bool
>>>>>>>> &RequiresSecondPass) {
>>>>>>>> >> >    assert((ILE->getType() != SemaRef.Context.VoidTy) &&
>>>>>>>> >> > @@ -436,13 +477,13 @@ InitListChecker::FillInValueInitializati
>>>>>>>> >> >    if (const RecordType *RType =
>>>>>>>> ILE->getType()->getAs<RecordType>()) {
>>>>>>>> >> >      const RecordDecl *RDecl = RType->getDecl();
>>>>>>>> >> >      if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
>>>>>>>> >> > -      FillInValueInitForField(0,
>>>>>>>> ILE->getInitializedFieldInUnion(),
>>>>>>>> >> > +      FillInEmptyInitForField(0,
>>>>>>>> ILE->getInitializedFieldInUnion(),
>>>>>>>> >> >                                Entity, ILE,
>>>>>>>> RequiresSecondPass);
>>>>>>>> >> >      else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) &&
>>>>>>>> >> >
>>>>>>>> cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) {
>>>>>>>> >> >        for (auto *Field : RDecl->fields()) {
>>>>>>>> >> >          if (Field->hasInClassInitializer()) {
>>>>>>>> >> > -          FillInValueInitForField(0, Field, Entity, ILE,
>>>>>>>> >> > RequiresSecondPass);
>>>>>>>> >> > +          FillInEmptyInitForField(0, Field, Entity, ILE,
>>>>>>>> >> > RequiresSecondPass);
>>>>>>>> >> >            break;
>>>>>>>> >> >          }
>>>>>>>> >> >        }
>>>>>>>> >> > @@ -455,7 +496,7 @@ InitListChecker::FillInValueInitializati
>>>>>>>> >> >          if (hadError)
>>>>>>>> >> >            return;
>>>>>>>> >> >
>>>>>>>> >> > -        FillInValueInitForField(Init, Field, Entity, ILE,
>>>>>>>> >> > RequiresSecondPass);
>>>>>>>> >> > +        FillInEmptyInitForField(Init, Field, Entity, ILE,
>>>>>>>> >> > RequiresSecondPass);
>>>>>>>> >> >          if (hadError)
>>>>>>>> >> >            return;
>>>>>>>> >> >
>>>>>>>> >> > @@ -489,10 +530,6 @@ InitListChecker::FillInValueInitializati
>>>>>>>> >> >    } else
>>>>>>>> >> >      ElementType = ILE->getType();
>>>>>>>> >> >
>>>>>>>> >> > -  SourceLocation Loc = ILE->getLocEnd();
>>>>>>>> >> > -  if (ILE->getSyntacticForm())
>>>>>>>> >> > -    Loc = ILE->getSyntacticForm()->getLocEnd();
>>>>>>>> >> > -
>>>>>>>> >> >    for (unsigned Init = 0; Init != NumElements; ++Init) {
>>>>>>>> >> >      if (hadError)
>>>>>>>> >> >        return;
>>>>>>>> >> > @@ -503,19 +540,9 @@ InitListChecker::FillInValueInitializati
>>>>>>>> >> >
>>>>>>>> >> >      Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) :
>>>>>>>> nullptr);
>>>>>>>> >> >      if (!InitExpr && !ILE->hasArrayFiller()) {
>>>>>>>> >> > -      InitializationKind Kind =
>>>>>>>> InitializationKind::CreateValue(Loc,
>>>>>>>> >> > Loc, Loc,
>>>>>>>> >> > -
>>>>>>>>    true);
>>>>>>>> >> > -      InitializationSequence InitSeq(SemaRef, ElementEntity,
>>>>>>>> Kind,
>>>>>>>> >> > None);
>>>>>>>> >> > -      if (!InitSeq) {
>>>>>>>> >> > -        InitSeq.Diagnose(SemaRef, ElementEntity, Kind, None);
>>>>>>>> >> > -        SemaRef.Diag(Loc,
>>>>>>>> diag::note_in_omitted_aggregate_initializer)
>>>>>>>> >> > -          << /*array element*/0 << Init;
>>>>>>>> >> > -        hadError = true;
>>>>>>>> >> > -        return;
>>>>>>>> >> > -      }
>>>>>>>> >> > -
>>>>>>>> >> > -      ExprResult ElementInit
>>>>>>>> >> > -        = InitSeq.Perform(SemaRef, ElementEntity, Kind, None);
>>>>>>>> >> > +      ExprResult ElementInit = PerformEmptyInit(SemaRef,
>>>>>>>> >> > ILE->getLocEnd(),
>>>>>>>> >> > +                                                ElementEntity,
>>>>>>>> >> > +
>>>>>>>>  /*VerifyOnly*/false);
>>>>>>>> >> >        if (ElementInit.isInvalid()) {
>>>>>>>> >> >          hadError = true;
>>>>>>>> >> >          return;
>>>>>>>> >> > @@ -538,8 +565,8 @@ InitListChecker::FillInValueInitializati
>>>>>>>> >> >            return;
>>>>>>>> >> >          }
>>>>>>>> >> >
>>>>>>>> >> > -        if (InitSeq.isConstructorInitialization()) {
>>>>>>>> >> > -          // Value-initialization requires a constructor
>>>>>>>> call, so
>>>>>>>> >> > +        if (!isa<ImplicitValueInitExpr>(ElementInit.get())) {
>>>>>>>> >> > +          // Empty initialization requires a constructor
>>>>>>>> call, so
>>>>>>>> >> >            // extend the initializer list to include the
>>>>>>>> constructor
>>>>>>>> >> >            // call and make a note that we'll need to take
>>>>>>>> another pass
>>>>>>>> >> >            // through the initializer list.
>>>>>>>> >> > @@ -549,7 +576,7 @@ InitListChecker::FillInValueInitializati
>>>>>>>> >> >        }
>>>>>>>> >> >      } else if (InitListExpr *InnerILE
>>>>>>>> >> >                   = dyn_cast_or_null<InitListExpr>(InitExpr))
>>>>>>>> >> > -      FillInValueInitializations(ElementEntity, InnerILE,
>>>>>>>> >> > RequiresSecondPass);
>>>>>>>> >> > +      FillInEmptyInitializations(ElementEntity, InnerILE,
>>>>>>>> >> > RequiresSecondPass);
>>>>>>>> >> >    }
>>>>>>>> >> >  }
>>>>>>>> >> >
>>>>>>>> >> > @@ -567,9 +594,9 @@ InitListChecker::InitListChecker(Sema &S
>>>>>>>> >> >
>>>>>>>> >> >    if (!hadError && !VerifyOnly) {
>>>>>>>> >> >      bool RequiresSecondPass = false;
>>>>>>>> >> > -    FillInValueInitializations(Entity, FullyStructuredList,
>>>>>>>> >> > RequiresSecondPass);
>>>>>>>> >> > +    FillInEmptyInitializations(Entity, FullyStructuredList,
>>>>>>>> >> > RequiresSecondPass);
>>>>>>>> >> >      if (RequiresSecondPass && !hadError)
>>>>>>>> >> > -      FillInValueInitializations(Entity, FullyStructuredList,
>>>>>>>> >> > +      FillInEmptyInitializations(Entity, FullyStructuredList,
>>>>>>>> >> >                                   RequiresSecondPass);
>>>>>>>> >> >    }
>>>>>>>> >> >  }
>>>>>>>> >> > @@ -678,7 +705,6 @@ void InitListChecker::CheckExplicitInitL
>>>>>>>> >> >                                              InitListExpr
>>>>>>>> *IList,
>>>>>>>> >> > QualType &T,
>>>>>>>> >> >                                              InitListExpr
>>>>>>>> >> > *StructuredList,
>>>>>>>> >> >                                              bool
>>>>>>>> TopLevelObject) {
>>>>>>>> >> > -  assert(IList->isExplicit() && "Illegal Implicit
>>>>>>>> InitListExpr");
>>>>>>>> >> >    if (!VerifyOnly) {
>>>>>>>> >> >      SyntacticToSemantic[IList] = StructuredList;
>>>>>>>> >> >      StructuredList->setSyntacticForm(IList);
>>>>>>>> >> > @@ -1121,8 +1147,9 @@ void InitListChecker::CheckVectorType(co
>>>>>>>> >> >    if (Index >= IList->getNumInits()) {
>>>>>>>> >> >      // Make sure the element type can be value-initialized.
>>>>>>>> >> >      if (VerifyOnly)
>>>>>>>> >> > -      CheckValueInitializable(
>>>>>>>> >> > -
>>>>>>>>  InitializedEntity::InitializeElement(SemaRef.Context, 0,
>>>>>>>> >> > Entity));
>>>>>>>> >> > +      CheckEmptyInitializable(
>>>>>>>> >> > +
>>>>>>>>  InitializedEntity::InitializeElement(SemaRef.Context, 0,
>>>>>>>> >> > Entity),
>>>>>>>> >> > +          IList->getLocEnd());
>>>>>>>> >> >      return;
>>>>>>>> >> >    }
>>>>>>>> >> >
>>>>>>>> >> > @@ -1169,7 +1196,7 @@ void InitListChecker::CheckVectorType(co
>>>>>>>> >> >        // Don't attempt to go past the end of the init list
>>>>>>>> >> >        if (Index >= IList->getNumInits()) {
>>>>>>>> >> >          if (VerifyOnly)
>>>>>>>> >> > -          CheckValueInitializable(ElementEntity);
>>>>>>>> >> > +          CheckEmptyInitializable(ElementEntity,
>>>>>>>> IList->getLocEnd());
>>>>>>>> >> >          break;
>>>>>>>> >> >        }
>>>>>>>> >> >
>>>>>>>> >> > @@ -1346,8 +1373,9 @@ void InitListChecker::CheckArrayType(con
>>>>>>>> >> >      // If so, check if doing that is possible.
>>>>>>>> >> >      // FIXME: This needs to detect holes left by designated
>>>>>>>> >> > initializers too.
>>>>>>>> >> >      if (maxElementsKnown && elementIndex < maxElements)
>>>>>>>> >> > -
>>>>>>>>  CheckValueInitializable(InitializedEntity::InitializeElement(
>>>>>>>> >> > -
>>>>>>>>  SemaRef.Context, 0,
>>>>>>>> >> > Entity));
>>>>>>>> >> > +
>>>>>>>>  CheckEmptyInitializable(InitializedEntity::InitializeElement(
>>>>>>>> >> > +
>>>>>>>>  SemaRef.Context, 0,
>>>>>>>> >> > Entity),
>>>>>>>> >> > +                              IList->getLocEnd());
>>>>>>>> >> >    }
>>>>>>>> >> >  }
>>>>>>>> >> >
>>>>>>>> >> > @@ -1432,8 +1460,9 @@ void InitListChecker::CheckStructUnionTy
>>>>>>>> >> >           Field != FieldEnd; ++Field) {
>>>>>>>> >> >        if (Field->getDeclName()) {
>>>>>>>> >> >          if (VerifyOnly)
>>>>>>>> >> > -          CheckValueInitializable(
>>>>>>>> >> > -              InitializedEntity::InitializeMember(*Field,
>>>>>>>> &Entity));
>>>>>>>> >> > +          CheckEmptyInitializable(
>>>>>>>> >> > +              InitializedEntity::InitializeMember(*Field,
>>>>>>>> &Entity),
>>>>>>>> >> > +              IList->getLocEnd());
>>>>>>>> >> >          else
>>>>>>>> >> >            StructuredList->setInitializedFieldInUnion(*Field);
>>>>>>>> >> >          break;
>>>>>>>> >> > @@ -1545,8 +1574,9 @@ void InitListChecker::CheckStructUnionTy
>>>>>>>> >> >      // FIXME: Should check for holes left by designated
>>>>>>>> initializers
>>>>>>>> >> > too.
>>>>>>>> >> >      for (; Field != FieldEnd && !hadError; ++Field) {
>>>>>>>> >> >        if (!Field->isUnnamedBitfield() &&
>>>>>>>> >> > !Field->hasInClassInitializer())
>>>>>>>> >> > -        CheckValueInitializable(
>>>>>>>> >> > -            InitializedEntity::InitializeMember(*Field,
>>>>>>>> &Entity));
>>>>>>>> >> > +        CheckEmptyInitializable(
>>>>>>>> >> > +            InitializedEntity::InitializeMember(*Field,
>>>>>>>> &Entity),
>>>>>>>> >> > +            IList->getLocEnd());
>>>>>>>> >> >      }
>>>>>>>> >> >    }
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> >> > Added: cfe/trunk/test/CXX/drs/dr10xx.cpp
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr10xx.cpp?rev=210091&view=auto
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > --- cfe/trunk/test/CXX/drs/dr10xx.cpp (added)
>>>>>>>> >> > +++ cfe/trunk/test/CXX/drs/dr10xx.cpp Tue Jun  3 03:26:00 2014
>>>>>>>> >> > @@ -0,0 +1,33 @@
>>>>>>>> >> > +// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions
>>>>>>>> -fcxx-exceptions
>>>>>>>> >> > -pedantic-errors
>>>>>>>> >> > +// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions
>>>>>>>> -fcxx-exceptions
>>>>>>>> >> > -pedantic-errors
>>>>>>>> >> > +// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions
>>>>>>>> -fcxx-exceptions
>>>>>>>> >> > -pedantic-errors
>>>>>>>> >> > +
>>>>>>>> >> > +// expected-no-diagnostics
>>>>>>>> >> > +
>>>>>>>> >> > +namespace std {
>>>>>>>> >> > +  __extension__ typedef __SIZE_TYPE__ size_t;
>>>>>>>> >> > +
>>>>>>>> >> > +  template<typename T> struct initializer_list {
>>>>>>>> >> > +    const T *p; size_t n;
>>>>>>>> >> > +    initializer_list(const T *p, size_t n);
>>>>>>>> >> > +  };
>>>>>>>> >> > +}
>>>>>>>> >> > +
>>>>>>>> >> > +namespace dr1070 { // dr1070: 3.5
>>>>>>>> >> > +#if __cplusplus >= 201103L
>>>>>>>> >> > +  struct A {
>>>>>>>> >> > +    A(std::initializer_list<int>);
>>>>>>>> >> > +  };
>>>>>>>> >> > +  struct B {
>>>>>>>> >> > +    int i;
>>>>>>>> >> > +    A a;
>>>>>>>> >> > +  };
>>>>>>>> >> > +  B b = {1};
>>>>>>>> >> > +  struct C {
>>>>>>>> >> > +    std::initializer_list<int> a;
>>>>>>>> >> > +    B b;
>>>>>>>> >> > +    std::initializer_list<double> c;
>>>>>>>> >> > +  };
>>>>>>>> >> > +  C c = {};
>>>>>>>> >> > +#endif
>>>>>>>> >> > +}
>>>>>>>> >> >
>>>>>>>> >> > Added: cfe/trunk/test/CXX/drs/dr9xx.cpp
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr9xx.cpp?rev=210091&view=auto
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > --- cfe/trunk/test/CXX/drs/dr9xx.cpp (added)
>>>>>>>> >> > +++ cfe/trunk/test/CXX/drs/dr9xx.cpp Tue Jun  3 03:26:00 2014
>>>>>>>> >> > @@ -0,0 +1,45 @@
>>>>>>>> >> > +// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions
>>>>>>>> -fcxx-exceptions
>>>>>>>> >> > -pedantic-errors
>>>>>>>> >> > +// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions
>>>>>>>> -fcxx-exceptions
>>>>>>>> >> > -pedantic-errors
>>>>>>>> >> > +// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions
>>>>>>>> -fcxx-exceptions
>>>>>>>> >> > -pedantic-errors
>>>>>>>> >> > +
>>>>>>>> >> > +#if __cplusplus < 201103L
>>>>>>>> >> > +// expected-no-diagnostics
>>>>>>>> >> > +#endif
>>>>>>>> >> > +
>>>>>>>> >> > +namespace std {
>>>>>>>> >> > +  __extension__ typedef __SIZE_TYPE__ size_t;
>>>>>>>> >> > +
>>>>>>>> >> > +  template<typename T> struct initializer_list {
>>>>>>>> >> > +    const T *p; size_t n;
>>>>>>>> >> > +    initializer_list(const T *p, size_t n);
>>>>>>>> >> > +  };
>>>>>>>> >> > +}
>>>>>>>> >> > +
>>>>>>>> >> > +namespace dr990 { // dr990: 3.5
>>>>>>>> >> > +#if __cplusplus >= 201103L
>>>>>>>> >> > +  struct A { // expected-note 2{{candidate}}
>>>>>>>> >> > +    A(std::initializer_list<int>); // expected-note
>>>>>>>> {{candidate}}
>>>>>>>> >> > +  };
>>>>>>>> >> > +  struct B {
>>>>>>>> >> > +    A a;
>>>>>>>> >> > +  };
>>>>>>>> >> > +  B b1 { };
>>>>>>>> >> > +  B b2 { 1 }; // expected-error {{no viable conversion from
>>>>>>>> 'int' to
>>>>>>>> >> > 'dr990::A'}}
>>>>>>>> >> > +  B b3 { { 1 } };
>>>>>>>> >> > +
>>>>>>>> >> > +  struct C {
>>>>>>>> >> > +    C();
>>>>>>>> >> > +    C(int);
>>>>>>>> >> > +    C(std::initializer_list<int>) = delete; // expected-note
>>>>>>>> {{here}}
>>>>>>>> >> > +  };
>>>>>>>> >> > +  C c1[3] { 1 }; // ok
>>>>>>>> >> > +  C c2[3] { 1, {2} }; // expected-error {{call to deleted}}
>>>>>>>> >> > +
>>>>>>>> >> > +  struct D {
>>>>>>>> >> > +    D();
>>>>>>>> >> > +    D(std::initializer_list<int>);
>>>>>>>> >> > +    D(std::initializer_list<double>);
>>>>>>>> >> > +  };
>>>>>>>> >> > +  D d{};
>>>>>>>> >> > +#endif
>>>>>>>> >> > +}
>>>>>>>> >> >
>>>>>>>> >> > Modified:
>>>>>>>> >> >
>>>>>>>> cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=210091&r1=210090&r2=210091&view=diff
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > ---
>>>>>>>> cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
>>>>>>>> >> > (original)
>>>>>>>> >> > +++
>>>>>>>> cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
>>>>>>>> >> > Tue Jun  3 03:26:00 2014
>>>>>>>> >> > @@ -1,4 +1,4 @@
>>>>>>>> >> > -// RUN: %clang_cc1 -std=c++11 -S -triple x86_64-none-linux-gnu
>>>>>>>> >> > -emit-llvm -o - %s | FileCheck %s
>>>>>>>> >> > +// RUN: %clang_cc1 -std=c++11 -triple x86_64-none-linux-gnu
>>>>>>>> -emit-llvm
>>>>>>>> >> > -o - %s | FileCheck %s
>>>>>>>> >> >
>>>>>>>> >> >  namespace std {
>>>>>>>> >> >    typedef decltype(sizeof(int)) size_t;
>>>>>>>> >> > @@ -431,3 +431,20 @@ namespace nested {
>>>>>>>> >> >      // CHECK: }
>>>>>>>> >> >    }
>>>>>>>> >> >  }
>>>>>>>> >> > +
>>>>>>>> >> > +namespace DR1070 {
>>>>>>>> >> > +  struct A {
>>>>>>>> >> > +    A(std::initializer_list<int>);
>>>>>>>> >> > +  };
>>>>>>>> >> > +  struct B {
>>>>>>>> >> > +    int i;
>>>>>>>> >> > +    A a;
>>>>>>>> >> > +  };
>>>>>>>> >> > +  B b = {1};
>>>>>>>> >> > +  struct C {
>>>>>>>> >> > +    std::initializer_list<int> a;
>>>>>>>> >> > +    B b;
>>>>>>>> >> > +    std::initializer_list<double> c;
>>>>>>>> >> > +  };
>>>>>>>> >> > +  C c = {};
>>>>>>>> >> > +}
>>>>>>>> >> >
>>>>>>>> >> > Modified:
>>>>>>>> cfe/trunk/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp?rev=210091&r1=210090&r2=210091&view=diff
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > --- cfe/trunk/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
>>>>>>>> (original)
>>>>>>>> >> > +++ cfe/trunk/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
>>>>>>>> Tue Jun  3
>>>>>>>> >> > 03:26:00 2014
>>>>>>>> >> > @@ -46,7 +46,7 @@ B z { 1 };
>>>>>>>> >> >  // CHECK: store i8 %{{.*}}, i8* getelementptr inbounds
>>>>>>>> ({{.*}} @a, i32
>>>>>>>> >> > 0, i32 2)
>>>>>>>> >> >  // CHECK: call i32 @_ZN1A1fEv({{.*}} @a)
>>>>>>>> >> >  // CHECK: store i32 %{{.*}}, i32* getelementptr inbounds
>>>>>>>> ({{.*}}* @a,
>>>>>>>> >> > i32 0, i32 3)
>>>>>>>> >> > -// CHECK: call void @{{.*}}C1Ev({{.*}} getelementptr inbounds
>>>>>>>> >> > (%struct.A* @a, i32 0, i32 4))
>>>>>>>> >> > +// CHECK: store double 1.000000e+00, double* getelementptr
>>>>>>>> inbounds
>>>>>>>> >> > ({{.*}} @a, i32 0, i32 4, i32 0)
>>>>>>>> >> >
>>>>>>>> >> >  // No dynamic initialization of 'b':
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> >> > Modified:
>>>>>>>> cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp?rev=210091&r1=210090&r2=210091&view=diff
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > --- cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
>>>>>>>> (original)
>>>>>>>> >> > +++ cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
>>>>>>>> Tue Jun  3
>>>>>>>> >> > 03:26:00 2014
>>>>>>>> >> > @@ -389,8 +389,8 @@ namespace PR11410 {
>>>>>>>> >> >
>>>>>>>> >> >    struct B {
>>>>>>>> >> >      A a; // expected-note {{in implicit initialization of
>>>>>>>> field 'a'}}
>>>>>>>> >> > -  } b = { // expected-error {{call to deleted constructor}}
>>>>>>>> >> > -  };
>>>>>>>> >> > +  } b = {
>>>>>>>> >> > +  }; // expected-error {{call to deleted constructor}}
>>>>>>>> >> >
>>>>>>>> >> >    struct C {
>>>>>>>> >> >      C(int = 0); // expected-note 2{{candidate}}
>>>>>>>> >> >
>>>>>>>> >> > Modified:
>>>>>>>> >> > cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=210091&r1=210090&r2=210091&view=diff
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > ---
>>>>>>>> cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
>>>>>>>> >> > (original)
>>>>>>>> >> > +++
>>>>>>>> cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp Tue
>>>>>>>> >> > Jun  3 03:26:00 2014
>>>>>>>> >> > @@ -230,3 +230,11 @@ namespace PR18013 {
>>>>>>>> >> >    int f();
>>>>>>>> >> >    std::initializer_list<long (*)()> x = {f}; //
>>>>>>>> expected-error {{cannot
>>>>>>>> >> > initialize an array element of type 'long (*const)()' with an
>>>>>>>> lvalue of type
>>>>>>>> >> > 'int ()': different return type ('long' vs 'int')}}
>>>>>>>> >> >  }
>>>>>>>> >> > +
>>>>>>>> >> > +namespace DR1070 {
>>>>>>>> >> > +  struct S {
>>>>>>>> >> > +    S(std::initializer_list<int>);
>>>>>>>> >> > +  };
>>>>>>>> >> > +  S s[3] = { {1, 2, 3}, {4, 5} }; // ok
>>>>>>>> >> > +  S *p = new S[3] { {1, 2, 3}, {4, 5} }; // ok
>>>>>>>> >> > +}
>>>>>>>> >> >
>>>>>>>> >> > Modified: cfe/trunk/www/cxx_dr_status.html
>>>>>>>> >> > URL:
>>>>>>>> >> >
>>>>>>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=210091&r1=210090&r2=210091&view=diff
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> ==============================================================================
>>>>>>>> >> > --- cfe/trunk/www/cxx_dr_status.html (original)
>>>>>>>> >> > +++ cfe/trunk/www/cxx_dr_status.html Tue Jun  3 03:26:00 2014
>>>>>>>> >> > @@ -3233,7 +3233,7 @@ of class templates</td>
>>>>>>>> >> >      <td><a
>>>>>>>> >> > href="
>>>>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#532
>>>>>>>> ">532</a></td>
>>>>>>>> >> >      <td>C++11</td>
>>>>>>>> >> >      <td>Member/nonmember operator template partial
>>>>>>>> ordering</td>
>>>>>>>> >> > -    <td class="none" align="center">Unknown</td>
>>>>>>>> >> > +    <td class="svn" align="center">SVN</td>
>>>>>>>> >> >    </tr>
>>>>>>>> >> >    <tr id="533">
>>>>>>>> >> >      <td><a
>>>>>>>> >> > href="
>>>>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#533
>>>>>>>> ">533</a></td>
>>>>>>>> >> > @@ -5755,7 +5755,7 @@ and <I>POD class</I></td>
>>>>>>>> >> >      <td><a
>>>>>>>> >> > href="
>>>>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#990
>>>>>>>> ">990</a></td>
>>>>>>>> >> >      <td>CD2</td>
>>>>>>>> >> >      <td>Value initialization with multiple initializer-list
>>>>>>>> >> > constructors</td>
>>>>>>>> >> > -    <td class="none" align="center">Unknown</td>
>>>>>>>> >> > +    <td class="svn" align="center">SVN</td>
>>>>>>>> >> >    </tr>
>>>>>>>> >> >    <tr id="991">
>>>>>>>> >> >      <td><a
>>>>>>>> >> > href="
>>>>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#991
>>>>>>>> ">991</a></td>
>>>>>>>> >> > @@ -6235,7 +6235,7 @@ and <I>POD class</I></td>
>>>>>>>> >> >      <td><a
>>>>>>>> >> > href="
>>>>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1070
>>>>>>>> ">1070</a></td>
>>>>>>>> >> >      <td>C++11</td>
>>>>>>>> >> >      <td>Missing initializer clauses in aggregate
>>>>>>>> initialization</td>
>>>>>>>> >> > -    <td class="none" align="center">Unknown</td>
>>>>>>>> >> > +    <td class="svn" align="center">SVN</td>
>>>>>>>> >> >    </tr>
>>>>>>>> >> >    <tr id="1071">
>>>>>>>> >> >      <td><a
>>>>>>>> >> > href="
>>>>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1071
>>>>>>>> ">1071</a></td>
>>>>>>>> >> >
>>>>>>>> >> >
>>>>>>>> >> > _______________________________________________
>>>>>>>> >> > cfe-commits mailing list
>>>>>>>> >> > cfe-commits at cs.uiuc.edu
>>>>>>>> >> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> cfe-commits mailing list
>>>>>>> cfe-commits at cs.uiuc.edu
>>>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140630/e30ed580/attachment.html>
-------------- next part --------------
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp	(revision 211654)
+++ lib/Sema/SemaInit.cpp	(working copy)
@@ -353,8 +353,9 @@
   //   If there are fewer initializer-clauses in the list than there are
   //   members in the aggregate, then each member not explicitly initialized
   //   ...
-  if (SemaRef.getLangOpts().CPlusPlus11 &&
-      Entity.getType()->getBaseElementTypeUnsafe()->isRecordType()) {
+  bool EmptyInitList = SemaRef.getLangOpts().CPlusPlus11 &&
+      Entity.getType()->getBaseElementTypeUnsafe()->isRecordType();
+  if (EmptyInitList) {
     // C++1y / DR1070:
     //   shall be initialized [...] from an empty initializer list.
     //
@@ -376,6 +377,57 @@
   }
 
   InitializationSequence InitSeq(SemaRef, Entity, Kind, SubInit);
+  // libstdc++4.6 marks the vector default constructor as explicit in
+  // _GLIBCXX_DEBUG mode, so recover using the C++03 logic in that case.
+  // stlport does so too. Look for std::__debug for libstdc++, and for
+  // std:: for stlport.
+  if (!InitSeq && EmptyInitList && InitSeq.getFailureKind() ==
+          InitializationSequence::FK_ExplicitConstructor) {
+    OverloadCandidateSet::iterator Best;
+    OverloadingResult O =
+        InitSeq.getFailedCandidateSet()
+            .BestViableFunction(SemaRef, Kind.getLocation(), Best);
+    (void)O;
+    assert(O == OR_Success && "Inconsistent overload resolution");
+    CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
+    CXXRecordDecl *R = CtorDecl->getParent();
+
+    if (CtorDecl->getMinRequiredArguments() == 0 &&
+        CtorDecl->isExplicit() && // XXX or isExplicitSpecified() ?
+        R->getDeclName().isIdentifier() &&
+        SemaRef.SourceMgr.isInSystemHeader(CtorDecl->getLocation())) {
+
+      NamespaceDecl *ND = dyn_cast<NamespaceDecl>(R->getDeclContext());
+      NamespaceDecl *NND =
+          ND ? dyn_cast<NamespaceDecl>(ND->getLexicalParent()) : nullptr;
+
+      bool IsStd = ND && SemaRef.getStdNamespace()->InEnclosingNamespaceSetOf(ND);
+      bool IsStdDebug = ND && NND && ND->getName() == "__debug" &&
+          SemaRef.getStdNamespace()->InEnclosingNamespaceSetOf(NND);
+
+      StringRef N = R->getName();
+      if ((IsStd || IsStdDebug) && ( 
+          N == "basic_string" || N == "deque" || N == "forward_list" ||
+          N == "list" || N == "map" || N == "multimap" || N == "multiset" ||
+          N == "priority_queue" || N == "queue" || N == "set" ||
+          N == "stack" || N == "unordered_map" || N == "unordered_set" ||
+          N == "vector")) {
+
+        InitSeq.InitializeFrom(
+            SemaRef, Entity,
+            InitializationKind::CreateValue(Loc, Loc, Loc, true),
+            MultiExprArg(), /*TopLevelOfInitList=*/false);
+        // Emit a warning for this.  System header warnings aren't shown
+        // by default, but people working on system headers should see it.
+        if (!VerifyOnly) {
+          SemaRef.Diag(CtorDecl->getLocation(),
+                       diag::warn_invalid_initializer_from_system_header);
+          SemaRef.Diag(Entity.getDecl()->getLocation(),
+                       diag::note_used_in_initialization_here);
+        }
+      }
+    }
+  }
   if (!InitSeq) {
     if (!VerifyOnly) {
       InitSeq.Diagnose(SemaRef, Entity, Kind, SubInit);
Index: test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp
===================================================================
--- test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp	(revision 0)
+++ test/SemaCXX/cxx0x-initializer-stdinitializerlist-system-header.cpp	(revision 0)
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wsystem-headers %s
+
+// libstdc++4.6 in debug mode has explicit default constructors.
+// stlport has this for all containers.
+#ifdef BE_THE_HEADER
+#pragma clang system_header
+namespace std {
+namespace __debug {
+template <class T>
+class vector {
+public:
+  explicit vector() {} // expected-warning{{should not be explicit}}
+};
+}
+}
+#else
+
+#define BE_THE_HEADER
+#include __FILE__
+
+struct { int a, b; std::__debug::vector<int> c; } e[] = { {1, 1} }; // expected-note{{used in initialization here}}
+
+#endif
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 211654)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -2128,6 +2128,10 @@
 def warn_attribute_dllimport_static_field_definition : Warning<
   "definition of dllimport static field">,
   InGroup<DiagGroup<"dllimport-static-field-def">>;
+def warn_invalid_initializer_from_system_header : Warning<
+  "invalid constructor form class in system header, should not be explicit">,
+  InGroup<DiagGroup<"invalid-initializer-from-system-header">>;
+def note_used_in_initialization_here : Note<"used in initialization here">;
 def err_attribute_dll_member_of_dll_class : Error<
   "attribute %q0 cannot be applied to member of %q1 class">;
 def err_attribute_weakref_not_static : Error<


More information about the cfe-commits mailing list