r288866 - [c++17] P0135R1: Guaranteed copy elision.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 8 19:29:26 PST 2016


On 8 Dec 2016 7:17 pm, "Duncan P. N. Exon Smith via cfe-commits" <
cfe-commits at lists.llvm.org> wrote:

+Eric, Marshall

I haven't looked, but: from the test name, "copy.fail.cpp", I suspect there
is a bug/incompatibility in the test.  It likely relies on the compiler
trying (and failing) to copy something in a context where r288866
guarantees that there is no copy.


Was this not fixed by "[libcxx] r289033 - Avoid C++17 guaranteed copy
elision when testing for non-copyability"?

> On 2016-Dec-08, at 18:00, Adrian Prantl <aprantl at apple.com> wrote:
>
> Hi Richard,
>
> at this point this is more a heads-up than anything actionable, but I
wanted to let you know that I bisected this bot failure (
http://lab.llvm.org:8080/green/job/clang-stage2-cmake-
RgSan_check/2721/consoleFull#10584592348254eaf0-7326-4999-85b0-388101f2d404)
of std/input.output/stream.buffers/streambuf/streambuf.cons/copy.fail.cpp
down to this commit.
>
> I will follow up once I have a better understanding what is going on
there.
>
> -- adrian
>
>> On Dec 6, 2016, at 3:52 PM, Richard Smith via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
>>
>> Author: rsmith
>> Date: Tue Dec  6 17:52:28 2016
>> New Revision: 288866
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=288866&view=rev
>> Log:
>> [c++17] P0135R1: Guaranteed copy elision.
>>
>> When an object of class type is initialized from a prvalue of the same
type
>> (ignoring cv qualifications), use the prvalue to initialize the object
directly
>> instead of inserting a redundant elidable call to a copy constructor.
>>
>> Added:
>>   cfe/trunk/test/CodeGenCXX/cxx1z-copy-omission.cpp
>>   cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp
>> Modified:
>>   cfe/trunk/include/clang/AST/Expr.h
>>   cfe/trunk/lib/AST/Expr.cpp
>>   cfe/trunk/lib/AST/ExprConstant.cpp
>>   cfe/trunk/lib/CodeGen/CGExpr.cpp
>>   cfe/trunk/lib/CodeGen/CGExprAgg.cpp
>>   cfe/trunk/lib/CodeGen/CGExprConstant.cpp
>>   cfe/trunk/lib/Sema/SemaExprCXX.cpp
>>   cfe/trunk/lib/Sema/SemaInit.cpp
>>   cfe/trunk/lib/Sema/SemaOverload.cpp
>>   cfe/trunk/test/CXX/drs/dr0xx.cpp
>>   cfe/trunk/test/CXX/drs/dr10xx.cpp
>>   cfe/trunk/test/CXX/drs/dr1xx.cpp
>>   cfe/trunk/test/CXX/drs/dr4xx.cpp
>>   cfe/trunk/test/SemaCXX/aggregate-initialization.cpp
>>   cfe/trunk/www/cxx_dr_status.html
>>   cfe/trunk/www/cxx_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=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/include/clang/AST/Expr.h (original)
>> +++ cfe/trunk/include/clang/AST/Expr.h Tue Dec  6 17:52:28 2016
>> @@ -3786,7 +3786,7 @@ public:
>>
>>  /// \brief Build an empty initializer list.
>>  explicit InitListExpr(EmptyShell Empty)
>> -    : Expr(InitListExprClass, Empty) { }
>> +    : Expr(InitListExprClass, Empty), AltForm(nullptr, true) { }
>>
>>  unsigned getNumInits() const { return InitExprs.size(); }
>>
>> @@ -3894,6 +3894,11 @@ public:
>>  // literal or an @encode?
>>  bool isStringLiteralInit() const;
>>
>> +  /// Is this a transparent initializer list (that is, an InitListExpr
that is
>> +  /// purely syntactic, and whose semantics are that of the sole
contained
>> +  /// initializer)?
>> +  bool isTransparent() const;
>> +
>>  SourceLocation getLBraceLoc() const { return LBraceLoc; }
>>  void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; }
>>  SourceLocation getRBraceLoc() const { return RBraceLoc; }
>>
>> Modified: cfe/trunk/lib/AST/Expr.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/
Expr.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/lib/AST/Expr.cpp (original)
>> +++ cfe/trunk/lib/AST/Expr.cpp Tue Dec  6 17:52:28 2016
>> @@ -1864,6 +1864,24 @@ bool InitListExpr::isStringLiteralInit()
>>  return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init);
>> }
>>
>> +bool InitListExpr::isTransparent() const {
>> +  assert(isSemanticForm() && "syntactic form never semantically
transparent");
>> +
>> +  // A glvalue InitListExpr is always just sugar.
>> +  if (isGLValue()) {
>> +    assert(getNumInits() == 1 && "multiple inits in glvalue init list");
>> +    return true;
>> +  }
>> +
>> +  // Otherwise, we're sugar if and only if we have exactly one
initializer that
>> +  // is of the same type.
>> +  if (getNumInits() != 1 || !getInit(0))
>> +    return false;
>> +
>> +  return getType().getCanonicalType() ==
>> +         getInit(0)->getType().getCanonicalType();
>> +}
>> +
>> SourceLocation InitListExpr::getLocStart() const {
>>  if (InitListExpr *SyntacticForm = getSyntacticForm())
>>    return SyntacticForm->getLocStart();
>> @@ -2246,12 +2264,15 @@ bool Expr::isUnusedResultAWarning(const
>>    // effects (e.g. a placement new with an uninitialized POD).
>>  case CXXDeleteExprClass:
>>    return false;
>> +  case MaterializeTemporaryExprClass:
>> +    return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
>> +               ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
>>  case CXXBindTemporaryExprClass:
>> -    return (cast<CXXBindTemporaryExpr>(this)
>> -            ->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2,
Ctx));
>> +    return cast<CXXBindTemporaryExpr>(this)->getSubExpr()
>> +               ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
>>  case ExprWithCleanupsClass:
>> -    return (cast<ExprWithCleanups>(this)
>> -            ->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2,
Ctx));
>> +    return cast<ExprWithCleanups>(this)->getSubExpr()
>> +               ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
>>  }
>> }
>>
>>
>> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/
ExprConstant.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
>> +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Dec  6 17:52:28 2016
>> @@ -5670,6 +5670,9 @@ bool RecordExprEvaluator::VisitCastExpr(
>> }
>>
>> bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
>> +  if (E->isTransparent())
>> +    return Visit(E->getInit(0));
>> +
>>  const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
>>  if (RD->isInvalidDecl()) return false;
>>  const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
>>
>> Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
CGExpr.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
>> +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Dec  6 17:52:28 2016
>> @@ -3522,7 +3522,7 @@ LValue CodeGenFunction::EmitInitListLVal
>>    return EmitAggExprToLValue(E);
>>
>>  // An lvalue initializer list must be initializing a reference.
>> -  assert(E->getNumInits() == 1 && "reference init with multiple
values");
>> +  assert(E->isTransparent() && "non-transparent glvalue init list");
>>  return EmitLValue(E->getInit(0));
>> }
>>
>>
>> Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
CGExprAgg.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
>> +++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Tue Dec  6 17:52:28 2016
>> @@ -1145,15 +1145,15 @@ void AggExprEmitter::VisitInitListExpr(I
>>  if (E->hadArrayRangeDesignator())
>>    CGF.ErrorUnsupported(E, "GNU array range designator extension");
>>
>> +  if (E->isTransparent())
>> +    return Visit(E->getInit(0));
>> +
>>  AggValueSlot Dest = EnsureSlot(E->getType());
>>
>>  LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
>>
>>  // Handle initialization of an array.
>>  if (E->getType()->isArrayType()) {
>> -    if (E->isStringLiteralInit())
>> -      return Visit(E->getInit(0));
>> -
>>    QualType elementType =
>>        CGF.getContext().getAsArrayType(E->getType())->getElementType();
>>
>> @@ -1162,16 +1162,6 @@ void AggExprEmitter::VisitInitListExpr(I
>>    return;
>>  }
>>
>> -  if (E->getType()->isAtomicType()) {
>> -    // An _Atomic(T) object can be list-initialized from an expression
>> -    // of the same type.
>> -    assert(E->getNumInits() == 1 &&
>> -           CGF.getContext().hasSameUnqualifiedType(E->
getInit(0)->getType(),
>> -                                                   E->getType()) &&
>> -           "unexpected list initialization for atomic object");
>> -    return Visit(E->getInit(0));
>> -  }
>> -
>>  assert(E->getType()->isRecordType() && "Only support structs/unions
here!");
>>
>>  // Do struct initialization; this code just sets each individual member
>>
>> Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
CGExprConstant.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
>> +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Tue Dec  6 17:52:28 2016
>> @@ -778,9 +778,6 @@ public:
>>  }
>>
>>  llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
>> -    if (ILE->isStringLiteralInit())
>> -      return Visit(ILE->getInit(0));
>> -
>>    llvm::ArrayType *AType =
>>        cast<llvm::ArrayType>(ConvertType(ILE->getType()));
>>    llvm::Type *ElemTy = AType->getElementType();
>> @@ -845,6 +842,9 @@ public:
>>  }
>>
>>  llvm::Constant *VisitInitListExpr(InitListExpr *ILE) {
>> +    if (ILE->isTransparent())
>> +      return Visit(ILE->getInit(0));
>> +
>>    if (ILE->getType()->isArrayType())
>>      return EmitArrayInitialization(ILE);
>>
>>
>> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/
SemaExprCXX.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Dec  6 17:52:28 2016
>> @@ -6836,6 +6836,16 @@ ExprResult Sema::IgnoredValueConversions
>>        return E;
>>      E = Res.get();
>>    }
>> +
>> +    // C++1z:
>> +    //   If the expression is a prvalue after this optional conversion,
the
>> +    //   temporary materialization conversion is applied.
>> +    //
>> +    // We skip this step: IR generation is able to synthesize the
storage for
>> +    // itself in the aggregate case, and adding the extra node to the
AST is
>> +    // just clutter.
>> +    // FIXME: We don't emit lifetime markers for the temporaries due to
this.
>> +    // FIXME: Do any other AST consumers care about this?
>>    return E;
>>  }
>>
>>
>> Modified: cfe/trunk/lib/Sema/SemaInit.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/
SemaInit.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/lib/Sema/SemaInit.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Dec  6 17:52:28 2016
>> @@ -3546,8 +3546,14 @@ static void TryConstructorInitialization
>>                                         InitializationSequence &Sequence,
>>                                         bool IsListInit = false,
>>                                         bool IsInitListCopy = false) {
>> -  assert((!IsListInit || (Args.size() == 1 &&
isa<InitListExpr>(Args[0]))) &&
>> -         "IsListInit must come with a single initializer list
argument.");
>> +  assert(((!IsListInit && !IsInitListCopy) ||
>> +          (Args.size() == 1 && isa<InitListExpr>(Args[0]))) &&
>> +         "IsListInit/IsInitListCopy must come with a single initializer
list "
>> +         "argument.");
>> +  InitListExpr *ILE =
>> +      (IsListInit || IsInitListCopy) ? cast<InitListExpr>(Args[0]) :
nullptr;
>> +  MultiExprArg UnwrappedArgs =
>> +      ILE ? MultiExprArg(ILE->getInits(), ILE->getNumInits()) : Args;
>>
>>  // The type we're constructing needs to be complete.
>>  if (!S.isCompleteType(Kind.getLocation(), DestType)) {
>> @@ -3555,6 +3561,35 @@ static void TryConstructorInitialization
>>    return;
>>  }
>>
>> +  // C++1z [dcl.init]p17:
>> +  //     - If the initializer expression is a prvalue and the
cv-unqualified
>> +  //       version of the source type is the same class as the class of
the
>> +  //       destination, the initializer expression is used to
initialize the
>> +  //       destination object.
>> +  // Per DR (no number yet), this does not apply when initializing a
base
>> +  // class or delegating to another constructor from a mem-initializer.
>> +  if (S.getLangOpts().CPlusPlus1z &&
>> +      Entity.getKind() != InitializedEntity::EK_Base &&
>> +      Entity.getKind() != InitializedEntity::EK_Delegating &&
>> +      UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isRValue() &&
>> +      S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(),
DestType)) {
>> +    // Convert qualifications if necessary.
>> +    QualType InitType = UnwrappedArgs[0]->getType();
>> +    ImplicitConversionSequence ICS;
>> +    ICS.setStandard();
>> +    ICS.Standard.setAsIdentityConversion();
>> +    ICS.Standard.setFromType(InitType);
>> +    ICS.Standard.setAllToTypes(InitType);
>> +    if (!S.Context.hasSameType(InitType, DestType)) {
>> +      ICS.Standard.Third = ICK_Qualification;
>> +      ICS.Standard.setToType(2, DestType);
>> +    }
>> +    Sequence.AddConversionSequenceStep(ICS, DestType);
>> +    if (ILE)
>> +      Sequence.RewrapReferenceInitList(DestType, ILE);
>> +    return;
>> +  }
>> +
>>  const RecordType *DestRecordType = DestType->getAs<RecordType>();
>>  assert(DestRecordType && "Constructor initialization requires record
type");
>>  CXXRecordDecl *DestRecordDecl
>> @@ -3588,20 +3623,16 @@ static void TryConstructorInitialization
>>  //     constructors of the class T and the argument list consists of the
>>  //     initializer list as a single argument.
>>  if (IsListInit) {
>> -    InitListExpr *ILE = cast<InitListExpr>(Args[0]);
>>    AsInitializerList = true;
>>
>>    // If the initializer list has no elements and T has a default
constructor,
>>    // the first phase is omitted.
>> -    if (ILE->getNumInits() != 0 || !DestRecordDecl->
hasDefaultConstructor())
>> +    if (!(UnwrappedArgs.empty() && DestRecordDecl->
hasDefaultConstructor()))
>>      Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
>>                                          CandidateSet, Ctors, Best,
>>                                          CopyInitialization,
AllowExplicit,
>>                                          /*OnlyListConstructor=*/true,
>>                                          IsListInit);
>> -
>> -    // Time to unwrap the init list.
>> -    Args = MultiExprArg(ILE->getInits(), ILE->getNumInits());
>>  }
>>
>>  // C++11 [over.match.list]p1:
>> @@ -3611,7 +3642,7 @@ static void TryConstructorInitialization
>>  //     elements of the initializer list.
>>  if (Result == OR_No_Viable_Function) {
>>    AsInitializerList = false;
>> -    Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
>> +    Result = ResolveConstructorOverload(S, Kind.getLocation(),
UnwrappedArgs,
>>                                        CandidateSet, Ctors, Best,
>>                                        CopyInitialization, AllowExplicit,
>>                                        /*OnlyListConstructors=*/false,
>> @@ -3821,8 +3852,8 @@ static void TryListInitialization(Sema &
>>      QualType InitType = InitList->getInit(0)->getType();
>>      if (S.Context.hasSameUnqualifiedType(InitType, DestType) ||
>>          S.IsDerivedFrom(InitList->getLocStart(), InitType, DestType)) {
>> -        Expr *InitAsExpr = InitList->getInit(0);
>> -        TryConstructorInitialization(S, Entity, Kind, InitAsExpr,
DestType,
>> +        Expr *InitListAsExpr = InitList;
>> +        TryConstructorInitialization(S, Entity, Kind, InitListAsExpr,
DestType,
>>                                     Sequence, /*InitListSyntax*/ false,
>>                                     /*IsInitListCopy*/ true);
>>        return;
>> @@ -4332,16 +4363,21 @@ static void TryReferenceInitializationCo
>>  }
>>
>>  //    - If the initializer expression
>> +  // C++14-and-before:
>>  //      - is an xvalue, class prvalue, array prvalue, or function
lvalue and
>>  //        "cv1 T1" is reference-compatible with "cv2 T2"
>> +  // C++1z:
>> +  //      - is an rvalue or function lvalue and "cv1 T1" is
reference-compatible
>> +  //        with "cv2 T2"
>>  // Note: functions are handled below.
>>  if (!T1Function &&
>>      (RefRelationship == Sema::Ref_Compatible ||
>>       (Kind.isCStyleOrFunctionalCast() &&
>>        RefRelationship == Sema::Ref_Related)) &&
>>      (InitCategory.isXValue() ||
>> -       (InitCategory.isPRValue() && T2->isRecordType()) ||
>> -       (InitCategory.isPRValue() && T2->isArrayType()))) {
>> +       (InitCategory.isPRValue() &&
>> +        (S.getLangOpts().CPlusPlus1z || T2->isRecordType() ||
>> +         T2->isArrayType())))) {
>>    ExprValueKind ValueKind = InitCategory.isXValue()? VK_XValue :
VK_RValue;
>>    if (InitCategory.isPRValue() && T2->isRecordType()) {
>>      // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the
>> @@ -6604,7 +6640,26 @@ InitializationSequence::Perform(Sema &S,
>>        CreatedObject = Conversion->getReturnType()->isRecordType();
>>      }
>>
>> +      // C++14 and before:
>> +      //   - if the function is a constructor, the call initializes a
temporary
>> +      //     of the cv-unqualified version of the destination type [...]
>> +      // C++1z:
>> +      //   - if the function is a constructor, the call is a prvalue of
the
>> +      //     cv-unqualified version of the destination type whose
return object
>> +      //     is initialized by the constructor [...]
>> +      // Both:
>> +      //     The [..] call is used to direct-initialize, according to
the rules
>> +      //     above, the object that is the destination of the
>> +      //     copy-initialization.
>> +      // In C++14 and before, that always means the "constructors are
>> +      // considered" bullet, because we have arrived at a
reference-related
>> +      // type. In C++1z, it only means that if the types are different
or we
>> +      // didn't produce a prvalue, so just check for that case here.
>>      bool RequiresCopy = !IsCopy && !isReferenceBinding(Steps.back());
>> +      if (S.getLangOpts().CPlusPlus1z && CurInit.get()->isRValue() &&
>> +          S.Context.hasSameUnqualifiedType(
>> +              Entity.getType().getNonReferenceType(),
CurInit.get()->getType()))
>> +        RequiresCopy = false;
>>      bool MaybeBindToTemp = RequiresCopy ||
shouldBindAsTemporary(Entity);
>>
>>      if (!MaybeBindToTemp && CreatedObject &&
shouldDestroyTemporary(Entity)) {
>>
>> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/
SemaOverload.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
>> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Dec  6 17:52:28 2016
>> @@ -4979,7 +4979,7 @@ TryObjectArgumentInitialization(Sema &S,
>>  // cv-qualification on the member function declaration.
>>  //
>>  // However, when finding an implicit conversion sequence for the
argument, we
>> -  // are not allowed to create temporaries or perform user-defined
conversions
>> +  // are not allowed to perform user-defined conversions
>>  // (C++ [over.match.funcs]p5). We perform a simplified version of
>>  // reference binding here, that allows class rvalues to bind to
>>  // non-constant references.
>>
>> Modified: cfe/trunk/test/CXX/drs/dr0xx.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/
drs/dr0xx.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/test/CXX/drs/dr0xx.cpp (original)
>> +++ cfe/trunk/test/CXX/drs/dr0xx.cpp Tue Dec  6 17:52:28 2016
>> @@ -248,7 +248,7 @@ namespace dr20 { // dr20: yes
>>  private:
>>    X(const X&); // expected-note {{here}}
>>  };
>> -  X f();
>> +  X &f();
>>  X x = f(); // expected-error {{private}}
>> }
>>
>> @@ -316,8 +316,15 @@ namespace dr25 { // dr25: yes
>> namespace dr26 { // dr26: yes
>>  struct A { A(A, const A & = A()); }; // expected-error {{must pass its
first argument by reference}}
>>  struct B {
>> -    B(); // expected-note {{candidate}}
>> -    B(const B &, B = B()); // expected-error {{no matching
constructor}} expected-note {{candidate}} expected-note {{here}}
>> +    B(); // expected-note 0-1{{candidate}}
>> +    B(const B &, B = B());
>> +#if __cplusplus <= 201402L
>> +    // expected-error at -2 {{no matching constructor}} expected-note at -2
{{candidate}} expected-note at -2 {{here}}
>> +#endif
>> +  };
>> +  struct C {
>> +    static C &f();
>> +    C(const C &, C = f()); // expected-error {{no matching
constructor}} expected-note {{candidate}} expected-note {{here}}
>>  };
>> }
>>
>> @@ -662,25 +669,33 @@ namespace dr58 { // dr58: yes
>>
>> namespace dr59 { // dr59: yes
>>  template<typename T> struct convert_to { operator T() const; };
>> -  struct A {}; // expected-note 2{{volatile qualifier}} expected-note
2{{requires 0 arguments}}
>> -  struct B : A {}; // expected-note 2{{volatile qualifier}}
expected-note 2{{requires 0 arguments}}
>> -#if __cplusplus >= 201103L // move constructors
>> -  // expected-note at -3 2{{volatile qualifier}}
>> -  // expected-note at -3 2{{volatile qualifier}}
>> -#endif
>> +  struct A {}; // expected-note 5+{{candidate}}
>> +  struct B : A {}; // expected-note 0+{{candidate}}
>>
>>  A a1 = convert_to<A>();
>>  A a2 = convert_to<A&>();
>>  A a3 = convert_to<const A>();
>> -  A a4 = convert_to<const volatile A>(); // expected-error {{no viable}}
>> +  A a4 = convert_to<const volatile A>();
>> +#if __cplusplus <= 201402L
>> +  // expected-error at -2 {{no viable}}
>> +#endif
>>  A a5 = convert_to<const volatile A&>(); // expected-error {{no viable}}
>>
>>  B b1 = convert_to<B>();
>>  B b2 = convert_to<B&>();
>>  B b3 = convert_to<const B>();
>> -  B b4 = convert_to<const volatile B>(); // expected-error {{no viable}}
>> +  B b4 = convert_to<const volatile B>();
>> +#if __cplusplus <= 201402L
>> +  // expected-error at -2 {{no viable}}
>> +#endif
>>  B b5 = convert_to<const volatile B&>(); // expected-error {{no viable}}
>>
>> +  A c1 = convert_to<B>();
>> +  A c2 = convert_to<B&>();
>> +  A c3 = convert_to<const B>();
>> +  A c4 = convert_to<const volatile B>(); // expected-error {{no viable}}
>> +  A c5 = convert_to<const volatile B&>(); // expected-error {{no
viable}}
>> +
>>  int n1 = convert_to<int>();
>>  int n2 = convert_to<int&>();
>>  int n3 = convert_to<const int>();
>> @@ -920,14 +935,17 @@ namespace dr84 { // dr84: yes
>>  struct A { operator B() const; };
>>  struct C {};
>>  struct B {
>> -    B(B&); // expected-note {{candidate}}
>> -    B(C); // expected-note {{no known conversion from 'dr84::B' to
'dr84::C'}}
>> +    B(B&); // expected-note 0-1{{candidate}}
>> +    B(C); // expected-note 0-1{{no known conversion from 'dr84::B' to
'dr84::C'}}
>>    operator C() const;
>>  };
>>  A a;
>>  // Cannot use B(C) / operator C() pair to construct the B from the B
temporary
>> -  // here.
>> -  B b = a; // expected-error {{no viable}}
>> +  // here. In C++1z, we initialize the B object directly using
'A::operator B()'.
>> +  B b = a;
>> +#if __cplusplus <= 201402L
>> +  // expected-error at -2 {{no viable}}
>> +#endif
>> }
>>
>> namespace dr85 { // dr85: yes
>>
>> Modified: cfe/trunk/test/CXX/drs/dr10xx.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/
drs/dr10xx.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/test/CXX/drs/dr10xx.cpp (original)
>> +++ cfe/trunk/test/CXX/drs/dr10xx.cpp Tue Dec  6 17:52:28 2016
>> @@ -3,8 +3,6 @@
>> // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions
-pedantic-errors
>> // RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions
-pedantic-errors
>>
>> -// expected-no-diagnostics
>> -
>> namespace std {
>>  __extension__ typedef __SIZE_TYPE__ size_t;
>>
>> @@ -32,6 +30,18 @@ namespace dr1048 { // dr1048: 3.6
>> #endif
>> }
>>
>> +namespace dr1054 { // dr1054: no
>> +  // FIXME: Test is incomplete.
>> +  struct A {} volatile a;
>> +  void f() {
>> +    // FIXME: This is wrong: an lvalue-to-rvalue conversion is applied
here,
>> +    // which copy-initializes a temporary from 'a'. Therefore this is
>> +    // ill-formed because A does not have a volatile copy constructor.
>> +    // (We might want to track this aspect under dr1383 instead?)
>> +    a; // expected-warning {{assign into a variable to force a volatile
load}}
>> +  }
>> +}
>> +
>> namespace dr1070 { // dr1070: 3.5
>> #if __cplusplus >= 201103L
>>  struct A {
>>
>> Modified: cfe/trunk/test/CXX/drs/dr1xx.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/
drs/dr1xx.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/test/CXX/drs/dr1xx.cpp (original)
>> +++ cfe/trunk/test/CXX/drs/dr1xx.cpp Tue Dec  6 17:52:28 2016
>> @@ -576,11 +576,18 @@ namespace dr151 { // dr151: yes
>>
>> namespace dr152 { // dr152: yes
>>  struct A {
>> -    A(); // expected-note {{not viable}}
>> +    A(); // expected-note 0-2{{not viable}}
>>    explicit A(const A&);
>>  };
>> -  A a1 = A(); // expected-error {{no matching constructor}}
>> +  A a1 = A();
>> +#if __cplusplus <= 201402L
>> +  // expected-error at -2 {{no matching constructor}}
>> +#endif
>>  A a2((A()));
>> +
>> +  A &f();
>> +  A a3 = f(); // expected-error {{no matching constructor}}
>> +  A a4(f());
>> }
>>
>> // dr153: na
>> @@ -823,11 +830,20 @@ namespace dr176 { // dr176: yes
>> namespace dr177 { // dr177: yes
>>  struct B {};
>>  struct A {
>> -    A(A &); // expected-note {{not viable: expects an l-value}}
>> -    A(const B &); // expected-note {{not viable: no known conversion
from 'dr177::A' to}}
>> +    A(A &); // expected-note 0-1{{not viable: expects an l-value}}
>> +    A(const B &); // expected-note 0-1{{not viable: no known conversion
from 'dr177::A' to}}
>>  };
>>  B b;
>> -  A a = b; // expected-error {{no viable constructor copying variable}}
>> +  A a = b;
>> +#if __cplusplus <= 201402L
>> +  // expected-error at -2 {{no viable constructor copying variable}}
>> +#endif
>> +
>> +  struct C { C(C&); }; // expected-note {{not viable: no known
conversion from 'dr177::D' to 'dr177::C &'}}
>> +  struct D : C {};
>> +  struct E { operator D(); };
>> +  E e;
>> +  C c = e; // expected-error {{no viable constructor copying variable
of type 'dr177::D'}}
>> }
>>
>> namespace dr178 { // dr178: yes
>>
>> Modified: cfe/trunk/test/CXX/drs/dr4xx.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/
drs/dr4xx.cpp?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/test/CXX/drs/dr4xx.cpp (original)
>> +++ cfe/trunk/test/CXX/drs/dr4xx.cpp Tue Dec  6 17:52:28 2016
>> @@ -553,12 +553,21 @@ namespace dr446 { // dr446: yes
>>    void(b ? a : a);
>>    b ? A() : a; // expected-error {{deleted}}
>>    b ? a : A(); // expected-error {{deleted}}
>> -    b ? A() : A(); // expected-error {{deleted}}
>> +    b ? A() : A();
>> +#if __cplusplus <= 201402L
>> +    // expected-error at -2 {{deleted}}
>> +#endif
>>
>>    void(b ? a : c);
>>    b ? a : C(); // expected-error {{deleted}}
>> -    b ? c : A(); // expected-error {{deleted}}
>> -    b ? A() : C(); // expected-error {{deleted}}
>> +    b ? c : A();
>> +#if __cplusplus <= 201402L
>> +    // expected-error at -2 {{deleted}}
>> +#endif
>> +    b ? A() : C();
>> +#if __cplusplus <= 201402L
>> +    // expected-error at -2 {{deleted}}
>> +#endif
>>  }
>> }
>>
>> @@ -874,10 +883,12 @@ namespace dr479 { // dr479: yes
>>  void f() {
>>    throw S();
>>    // expected-error at -1 {{temporary of type 'dr479::S' has private
destructor}}
>> -    // expected-error at -2 {{calling a private constructor}}
>> -    // expected-error at -3 {{exception object of type 'dr479::S' has
private destructor}}
>> +    // expected-error at -2 {{exception object of type 'dr479::S' has
private destructor}}
>> #if __cplusplus < 201103L
>> -    // expected-error at -5 {{C++98 requires an accessible copy
constructor}}
>> +    // expected-error at -4 {{C++98 requires an accessible copy
constructor}}
>> +#endif
>> +#if __cplusplus <= 201402L
>> +    // expected-error at -7 {{calling a private constructor}} (copy ctor)
>> #endif
>>  }
>>  void g() {
>>
>> Added: cfe/trunk/test/CodeGenCXX/cxx1z-copy-omission.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
CodeGenCXX/cxx1z-copy-omission.cpp?rev=288866&view=auto
>> ============================================================
==================
>> --- cfe/trunk/test/CodeGenCXX/cxx1z-copy-omission.cpp (added)
>> +++ cfe/trunk/test/CodeGenCXX/cxx1z-copy-omission.cpp Tue Dec  6
17:52:28 2016
>> @@ -0,0 +1,81 @@
>> +// RUN: %clang_cc1 -std=c++1z -emit-llvm -triple x86_64-linux-gnu -o -
%s | FileCheck %s
>> +
>> +struct A {
>> +  A(int);
>> +  A(A&&);
>> +  A(const A&);
>> +  ~A();
>> +
>> +  int arr[10];
>> +};
>> +
>> +A f();
>> +void h();
>> +
>> +// CHECK-LABEL: define {{.*}} @_Z1gv(
>> +void g() {
>> +  // CHECK: %[[A:.*]] = alloca
>> +  // CHECK-NOT: alloca
>> +  // CHECK-NOT: call
>> +  // CHECK: call {{.*}} @_Z1fv({{.*}}* sret %[[A]])
>> +  A a = A( A{ f() } );
>> +  // CHECK-NOT: call
>> +
>> +  // CHECK: call void @_Z1hv(
>> +  h();
>> +  // CHECK-NOT: call
>> +
>> +  // CHECK: call void @_ZN1AD1Ev({{.*}}* %[[A]])
>> +  // CHECK-NOT: call
>> +  // CHECK-LABEL: }
>> +}
>> +
>> +void f(A);
>> +
>> +// CHECK-LABEL: define {{.*}} @_Z1hv(
>> +void h() {
>> +  // CHECK: %[[A:.*]] = alloca
>> +  // CHECK-NOT: alloca
>> +  // CHECK-NOT: call
>> +
>> +  // CHECK: call {{.*}} @_Z1fv({{.*}}* sret %[[A]])
>> +  // CHECK-NOT: call
>> +  // CHECK: call {{.*}} @_Z1f1A({{.*}}* %[[A]])
>> +  f(f());
>> +  // CHECK-NOT: call
>> +  // CHECK: call void @_ZN1AD1Ev({{.*}}* %[[A]])
>> +
>> +  // CHECK: call void @_Z1hv(
>> +  h();
>> +
>> +  // CHECK-NOT: call
>> +  // CHECK-LABEL: }
>> +}
>> +
>> +// We still pass classes with trivial copy/move constructors and
destructors in
>> +// registers, even if the copy is formally omitted.
>> +struct B {
>> +  B(int);
>> +  int n;
>> +};
>> +
>> +B fB();
>> +void fB(B);
>> +
>> +// CHECK-LABEL: define {{.*}} @_Z1iv(
>> +void i() {
>> +  // CHECK: %[[B:.*]] = alloca
>> +  // CHECK-NOT: alloca
>> +  // CHECK-NOT: call
>> +
>> +  // CHECK: %[[B_N:.*]] = call i32 @_Z2fBv()
>> +  // CHECK-NOT: call
>> +  // CHECK: store i32 %[[B_N]],
>> +  // CHECK-NOT: call
>> +  // CHECK: %[[B_N:.*]] = load i32
>> +  // CHECK-NOT: call
>> +  // CHECK: call void @_Z2fB1B(i32 %[[B_N]])
>> +  fB(fB());
>> +
>> +  // CHECK-LABEL: }
>> +}
>>
>> Modified: cfe/trunk/test/SemaCXX/aggregate-initialization.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
SemaCXX/aggregate-initialization.cpp?rev=288866&
r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/test/SemaCXX/aggregate-initialization.cpp (original)
>> +++ cfe/trunk/test/SemaCXX/aggregate-initialization.cpp Tue Dec  6
17:52:28 2016
>> @@ -57,7 +57,7 @@ struct A {
>>  A(int);
>>  ~A();
>>
>> -  A(const A&) = delete; // expected-note 2 {{'A' has been explicitly
marked deleted here}}
>> +  A(const A&) = delete; // expected-note 0-2{{'A' has been explicitly
marked deleted here}}
>> };
>>
>> struct B {
>> @@ -70,10 +70,16 @@ struct C {
>>
>> void f() {
>>  A as1[1] = { };
>> -  A as2[1] = { 1 }; // expected-error {{copying array element of type
'A' invokes deleted constructor}}
>> +  A as2[1] = { 1 };
>> +#if __cplusplus <= 201402L
>> +  // expected-error at -2 {{copying array element of type 'A' invokes
deleted constructor}}
>> +#endif
>>
>>  B b1 = { };
>> -  B b2 = { 1 }; // expected-error {{copying member subobject of type
'A' invokes deleted constructor}}
>> +  B b2 = { 1 };
>> +#if __cplusplus <= 201402L
>> +  // expected-error at -2 {{copying member subobject of type 'A' invokes
deleted constructor}}
>> +#endif
>>
>>  C c1 = { 1 };
>> }
>>
>> Added: cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
SemaCXX/cxx1z-copy-omission.cpp?rev=288866&view=auto
>> ============================================================
==================
>> --- cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp (added)
>> +++ cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp Tue Dec  6 17:52:28
2016
>> @@ -0,0 +1,134 @@
>> +// RUN: %clang_cc1 -std=c++1z -verify %s
>> +
>> +struct Noncopyable {
>> +  Noncopyable();
>> +  Noncopyable(const Noncopyable &) = delete; // expected-note
1+{{deleted}}
>> +  virtual ~Noncopyable();
>> +};
>> +struct Derived : Noncopyable {};
>> +struct NoncopyableAggr {
>> +  Noncopyable nc;
>> +};
>> +struct Indestructible {
>> +  Indestructible();
>> +  ~Indestructible() = delete; // expected-note 1+{{deleted}}
>> +};
>> +struct Incomplete; // expected-note 1+{{declar}}
>> +
>> +Noncopyable make(int kind = 0) {
>> +  switch (kind) {
>> +  case 0: return {};
>> +  case 1: return Noncopyable();
>> +  case 2: return Noncopyable{};
>> +  case 3: return make();
>> +  }
>> +  __builtin_unreachable();
>> +}
>> +
>> +Indestructible make_indestructible();
>> +Incomplete make_incomplete(); // expected-note 1+{{here}}
>> +
>> +void take(Noncopyable nc) {}
>> +
>> +Noncopyable nrvo() {
>> +  Noncopyable nrvo;
>> +  return nrvo; // expected-error {{deleted constructor}}
>> +}
>> +
>> +Noncopyable nc1 = make();
>> +Noncopyable nc2 = Noncopyable();
>> +Noncopyable nc3 = Derived(); // expected-error {{deleted constructor}}
>> +
>> +NoncopyableAggr nca1 = NoncopyableAggr{};
>> +NoncopyableAggr nca2 = NoncopyableAggr{{}};
>> +NoncopyableAggr nca3 = NoncopyableAggr{NoncopyableAggr{Noncopyable()}};
>> +
>> +void test_expressions(bool b) {
>> +  auto lambda = [a = make()] {};
>> +
>> +  take({});
>> +  take(Noncopyable());
>> +  take(Noncopyable{});
>> +  take(make());
>> +
>> +  Noncopyable &&dc1 = dynamic_cast<Noncopyable&&>(Noncopyable());
>> +  Noncopyable &&dc2 = dynamic_cast<Noncopyable&&>(nc1);
>> +  Noncopyable &&dc3 = dynamic_cast<Noncopyable&&>(Derived());
>> +
>> +  Noncopyable sc1 = static_cast<Noncopyable>(Noncopyable());
>> +  Noncopyable sc2 = static_cast<Noncopyable>(nc1); // expected-error
{{deleted}}
>> +  Noncopyable sc3 = static_cast<Noncopyable&&>(Noncopyable()); //
expected-error {{deleted}}
>> +  Noncopyable sc4 = static_cast<Noncopyable>(static_cast<Noncopyable&&>(Noncopyable()));
// expected-error {{deleted}}
>> +
>> +  Noncopyable cc1 = (Noncopyable)Noncopyable();
>> +  Noncopyable cc2 = (Noncopyable)Derived(); // expected-error
{{deleted}}
>> +
>> +  Noncopyable fc1 = Noncopyable(Noncopyable());
>> +  Noncopyable fc2 = Noncopyable(Derived()); // expected-error
{{deleted}}
>> +
>> +  // We must check for a complete type for every materialized
temporary. (Note
>> +  // that in the special case of the top level of a decltype, no
temporary is
>> +  // materialized.)
>> +  make_incomplete(); // expected-error {{incomplete}}
>> +  make_incomplete().a; // expected-error {{incomplete}}
>> +  make_incomplete().*(int Incomplete::*)nullptr; // expected-error
{{incomplete}}
>> +  dynamic_cast<Incomplete&&>(make_incomplete()); // expected-error
{{incomplete}}
>> +  const_cast<Incomplete&&>(make_incomplete()); // expected-error
{{incomplete}}
>> +
>> +  sizeof(Indestructible{}); // expected-error {{deleted}}
>> +  sizeof(make_indestructible()); // expected-error {{deleted}}
>> +  sizeof(make_incomplete()); // expected-error {{incomplete}}
>> +  typeid(Indestructible{}); // expected-error {{deleted}}
>> +  typeid(make_indestructible()); // expected-error {{deleted}}
>> +  typeid(make_incomplete()); // expected-error {{incomplete}}
>> +
>> +  // FIXME: The first two cases here are now also valid in C++17
onwards.
>> +  using I = decltype(Indestructible()); // expected-error {{deleted}}
>> +  using I = decltype(Indestructible{}); // expected-error {{deleted}}
>> +  using I = decltype(make_indestructible());
>> +  using J = decltype(make_incomplete());
>> +
>> +  Noncopyable cond1 = b ? Noncopyable() : make();
>> +  Noncopyable cond2 = b ? Noncopyable() : Derived(); // expected-error
{{incompatible}}
>> +  Noncopyable cond3 = b ? Derived() : Noncopyable(); // expected-error
{{incompatible}}
>> +  Noncopyable cond4 = b ? Noncopyable() : nc1; // expected-error
{{deleted}}
>> +  Noncopyable cond5 = b ? nc1 : Noncopyable(); // expected-error
{{deleted}}
>> +  // Could convert both to an xvalue of type Noncopyable here, but
we're not
>> +  // permitted to consider that.
>> +  Noncopyable &&cond6 = b ? Noncopyable() : Derived(); //
expected-error {{incompatible}}
>> +  Noncopyable &&cond7 = b ? Derived() : Noncopyable(); //
expected-error {{incompatible}}
>> +  // Could convert both to a const lvalue of type Noncopyable here, but
we're
>> +  // not permitted to consider that, either.
>> +  const Noncopyable cnc;
>> +  const Noncopyable &cond8 = b ? cnc : Derived(); // expected-error
{{incompatible}}
>> +  const Noncopyable &cond9 = b ? Derived() : cnc; // expected-error
{{incompatible}}
>> +
>> +  extern const volatile Noncopyable make_cv();
>> +  Noncopyable cv_difference1 = make_cv();
>> +  const volatile Noncopyable cv_difference2 = make();
>> +}
>> +
>> +template<typename T> struct ConversionFunction { operator T(); };
>> +Noncopyable cf1 = ConversionFunction<Noncopyable>();
>> +Noncopyable cf2 = ConversionFunction<Noncopyable&&>(); //
expected-error {{deleted}}
>> +Noncopyable cf3 = ConversionFunction<const volatile Noncopyable>();
>> +const volatile Noncopyable cf4 = ConversionFunction<Noncopyable>();
>> +Noncopyable cf5 = ConversionFunction<Derived>(); // expected-error
{{deleted}}
>> +
>> +struct AsMember {
>> +  Noncopyable member;
>> +  AsMember() : member(make()) {}
>> +};
>> +// FIXME: DR (no number yet): we still get a copy for base or
delegating construction.
>> +struct AsBase : Noncopyable {
>> +  AsBase() : Noncopyable(make()) {} // expected-error {{deleted}}
>> +};
>> +struct AsDelegating final {
>> +  AsDelegating(const AsDelegating &) = delete;
>> +  static AsDelegating make(int);
>> +
>> +  // The base constructor version of this is problematic; the complete
object
>> +  // version would be OK. Perhaps we could allow copy omission here for
final
>> +  // classes?
>> +  AsDelegating(int n) : AsDelegating(make(n)) {} // expected-error
{{deleted}}
>> +};
>>
>> Modified: cfe/trunk/www/cxx_dr_status.html
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_
status.html?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/www/cxx_dr_status.html (original)
>> +++ cfe/trunk/www/cxx_dr_status.html Tue Dec  6 17:52:28 2016
>> @@ -6139,7 +6139,7 @@ and <I>POD class</I></td>
>>    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_
defects.html#1054">1054</a></td>
>>    <td>C++11</td>
>>    <td>Lvalue-to-rvalue conversions in expression statements</td>
>> -    <td class="none" align="center">Unknown</td>
>> +    <td class="none" align="center">No</td>
>>  </tr>
>>  <tr id="1055">
>>    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_
defects.html#1055">1055</a></td>
>>
>> Modified: cfe/trunk/www/cxx_status.html
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_
status.html?rev=288866&r1=288865&r2=288866&view=diff
>> ============================================================
==================
>> --- cfe/trunk/www/cxx_status.html (original)
>> +++ cfe/trunk/www/cxx_status.html Tue Dec  6 17:52:28 2016
>> @@ -694,7 +694,7 @@ as the draft C++1z standard evolves.
>>    <tr>
>>      <td>Guaranteed copy elision</td>
>>      <td><a href="http://wg21.link/p0135r1">P0135R1</a></td>
>> -      <td class="none" align="center">No</td>
>> +      <td class="svn" align="center">SVN</td>
>>    </tr>
>>    <tr>
>>      <td rowspan=2>Stricter expression evaluation order</td>
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>

_______________________________________________
cfe-commits mailing list
cfe-commits at lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20161208/88d6502c/attachment-0001.html>


More information about the cfe-commits mailing list