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