From: Douglas Gregor Date: Mon, 28 Nov 2011 20:03:15 +0000 (+0000) Subject: When synthesizing an implicitly-defined copy or move constructor, or X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f48538897ccd6726e87485267495a62fdfd0b369;p=clang When synthesizing an implicitly-defined copy or move constructor, or when computing the exception specification of a copy or move constructor, ignore non-static data member initializers. Fixes PR11418 / . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145269 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 52eb9b0d3f..59c5e7894f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2633,6 +2633,19 @@ struct BaseAndFieldInfo { else IIK = IIK_Default; } + + bool isImplicitCopyOrMove() const { + switch (IIK) { + case IIK_Copy: + case IIK_Move: + return true; + + case IIK_Default: + return false; + } + + return false; + } }; } @@ -2678,7 +2691,7 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, // C++0x [class.base.init]p8: if the entity is a non-static data member that // has a brace-or-equal-initializer, the entity is initialized as specified // in [dcl.init]. - if (Field->hasInClassInitializer()) { + if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) { CXXCtorInitializer *Init; if (Indirect) Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, @@ -8583,12 +8596,7 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { - if (F->hasInClassInitializer()) { - if (Expr *E = F->getInClassInitializer()) - ExceptSpec.CalledExpr(E); - else if (!F->isInvalidDecl()) - ExceptSpec.SetDelayed(); - } else if (const RecordType *RecordTy + if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs()) { CXXRecordDecl *FieldRecDecl = cast(RecordTy->getDecl()); CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl); diff --git a/test/CXX/special/class.copy/p15-0x.cpp b/test/CXX/special/class.copy/p15-0x.cpp index 32b2714fd7..fff8844255 100644 --- a/test/CXX/special/class.copy/p15-0x.cpp +++ b/test/CXX/special/class.copy/p15-0x.cpp @@ -16,3 +16,26 @@ namespace PR10622 { bar obj2(obj); } } + +namespace PR11418 { + template + T may_throw() { + return T(); + } + + template T &&declval() noexcept; + + struct NonPOD { + NonPOD(); + NonPOD(const NonPOD &) noexcept; + NonPOD(NonPOD &&) noexcept; + }; + + struct X { + NonPOD np = may_throw(); + }; + + static_assert(noexcept(declval()), "noexcept isn't working at all"); + static_assert(noexcept(X(declval())), "copy constructor can't throw"); + static_assert(noexcept(X(declval())), "move constructor can't throw"); +} diff --git a/test/CXX/special/class.copy/p15-inclass.cpp b/test/CXX/special/class.copy/p15-inclass.cpp new file mode 100644 index 0000000000..c4f8eafd93 --- /dev/null +++ b/test/CXX/special/class.copy/p15-inclass.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s + +namespace PR11418 { + struct NonPOD { + NonPOD(); + NonPOD(const NonPOD &); + NonPOD(NonPOD &&); + }; + + struct X { + NonPOD np; + int a = 17; + }; + + void check_copy(X x) { + X x2(x); + } + + void check_move(X x) { + X x3(static_cast(x)); + } + + // CHECK: define linkonce_odr void @_ZN7PR114181XC2EOS0_ + // CHECK-NOT: 17 + // CHECK: call void @_ZN7PR114186NonPODC1EOS0_ + // CHECK-NOT: 17 + // CHECK: load i32* + // CHECK-NOT: 17 + // CHECK: store i32 + // CHECK-NOT: 17 + // CHECK: ret + + // CHECK: define linkonce_odr void @_ZN7PR114181XC2ERKS0_ + // CHECK-NOT: 17 + // CHECK: call void @_ZN7PR114186NonPODC1ERKS0_ + // CHECK-NOT: 17 + // CHECK: load i32* + // CHECK-NOT: 17 + // CHECK: store i32 + // CHECK-NOT: 17 + // CHECK: ret +}