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@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@-2 {{no matching constructor}} expected-note@-2 > {{candidate}} expected-note@-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@-3 2{{volatile qualifier}} > - // expected-note@-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@-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@-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@-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@-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@-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@-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@-2 {{deleted}} > +#endif > + b ? A() : C(); > +#if __cplusplus <= 201402L > + // expected-error@-2 {{deleted}} > +#endif > } > } > > @@ -874,10 +883,12 @@ namespace dr479 { // dr479: yes > void f() { > throw S(); > // expected-error@-1 {{temporary of type 'dr479::S' has private > destructor}} > - // expected-error@-2 {{calling a private constructor}} > - // expected-error@-3 {{exception object of type 'dr479::S' has private > destructor}} > + // expected-error@-2 {{exception object of type 'dr479::S' has private > destructor}} > #if __cplusplus < 201103L > - // expected-error@-5 {{C++98 requires an accessible copy constructor}} > + // expected-error@-4 {{C++98 requires an accessible copy constructor}} > +#endif > +#if __cplusplus <= 201402L > + // expected-error@-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@-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@-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@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits