diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c0dae22e0deee4579e18e36c38a8f0902ef8186c..4cd9a72c7c61713c132bcb474746b3ed69d89a8b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2124,9 +2124,10 @@ public: unsigned Quals); CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals); - CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class); - CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, bool RValueThis, - unsigned ThisQuals); + CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class, + unsigned Quals); + CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, + bool RValueThis, unsigned ThisQuals); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ba1b4f77fcace2f2db05473c6d712868922b297a..a4528eda0fad6d3f92a5d2201dbb8716c787decf 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7559,7 +7559,9 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( QualType FieldType = Context.getBaseElementType(Field->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXMethodDecl *CopyAssign = - LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0)) + LookupCopyingAssignment(FieldClassDecl, + ArgQuals | FieldType.getCVRQualifiers(), + false, 0)) ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign); } } @@ -7966,7 +7968,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, - false, 0)) + 0, false, 0)) ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } @@ -7976,7 +7978,7 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { CXXRecordDecl *BaseClassDecl = cast(Base->getType()->getAs()->getDecl()); if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, - false, 0)) + 0, false, 0)) ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign); } @@ -7986,8 +7988,10 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { ++Field) { QualType FieldType = Context.getBaseElementType(Field->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl, - false, 0)) + if (CXXMethodDecl *MoveAssign = + LookupMovingAssignment(FieldClassDecl, + FieldType.getCVRQualifiers(), + false, 0)) ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign); } } @@ -8580,7 +8584,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { QualType FieldType = Context.getBaseElementType(Field->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXConstructorDecl *CopyConstructor = - LookupCopyingConstructor(FieldClassDecl, Quals)) + LookupCopyingConstructor(FieldClassDecl, + Quals | FieldType.getCVRQualifiers())) ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor); } } @@ -8708,7 +8713,8 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { if (const RecordType *BaseType = B->getType()->getAs()) { CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); - CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); + CXXConstructorDecl *Constructor = + LookupMovingConstructor(BaseClassDecl, 0); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) @@ -8722,7 +8728,8 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { B != BEnd; ++B) { if (const RecordType *BaseType = B->getType()->getAs()) { CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); - CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); + CXXConstructorDecl *Constructor = + LookupMovingConstructor(BaseClassDecl, 0); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. if (Constructor) @@ -8734,10 +8741,10 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { - if (const RecordType *RecordTy - = Context.getBaseElementType(F->getType())->getAs()) { - CXXRecordDecl *FieldRecDecl = cast(RecordTy->getDecl()); - CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl); + QualType FieldType = Context.getBaseElementType(F->getType()); + if (CXXRecordDecl *FieldRecDecl = FieldType->getAsCXXRecordDecl()) { + CXXConstructorDecl *Constructor = + LookupMovingConstructor(FieldRecDecl, FieldType.getCVRQualifiers()); // If this is a deleted function, add it anyway. This might be conformant // with the standard. This might not. I'm not sure. It might not matter. // In particular, the problem is that this function never gets called. It diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 94efb2fff3807f47639cfaec93ef0cef348ffe47..84096074f23ae0d15189480f97a7d9da71291210 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2432,10 +2432,11 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, } /// \brief Look up the moving constructor for the given class. -CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class) { +CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class, + unsigned Quals) { SpecialMemberOverloadResult *Result = - LookupSpecialMember(Class, CXXMoveConstructor, false, - false, false, false, false); + LookupSpecialMember(Class, CXXMoveConstructor, Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, false, false, false); return cast_or_null(Result->getMethod()); } @@ -2476,12 +2477,14 @@ CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class, /// \brief Look up the moving assignment operator for the given class. CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, + unsigned Quals, bool RValueThis, unsigned ThisQuals) { assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment this"); SpecialMemberOverloadResult *Result = - LookupSpecialMember(Class, CXXMoveAssignment, false, false, RValueThis, + LookupSpecialMember(Class, CXXMoveAssignment, Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, RValueThis, ThisQuals & Qualifiers::Const, ThisQuals & Qualifiers::Volatile); diff --git a/clang/test/CXX/except/except.spec/p14.cpp b/clang/test/CXX/except/except.spec/p14.cpp index 8763a7028195357fe04914aad2c7a8b988a3e466..4f50afb54887389c8b2665d77a2786f7298ec7f8 100644 --- a/clang/test/CXX/except/except.spec/p14.cpp +++ b/clang/test/CXX/except/except.spec/p14.cpp @@ -39,3 +39,27 @@ struct IC1 { // we cannot currently compute the set of thrown types. static_assert(noexcept(IC0()), "IC0() does not throw"); static_assert(!noexcept(IC1()), "IC1() throws"); + +namespace PR13381 { + struct NoThrowMove { + NoThrowMove(const NoThrowMove &); + NoThrowMove(NoThrowMove &&) noexcept; + NoThrowMove &operator=(const NoThrowMove &); + NoThrowMove &operator=(NoThrowMove &&) noexcept; + }; + struct NoThrowMoveOnly { + NoThrowMoveOnly(NoThrowMoveOnly &&) noexcept; + NoThrowMoveOnly &operator=(NoThrowMoveOnly &&) noexcept; + }; + struct X { + const NoThrowMove a; + NoThrowMoveOnly b; + + static X val(); + static X &ref(); + }; + // These both perform a move, but that copy might throw, because it calls + // NoThrowMove's copy constructor (because PR13381::a is const). + static_assert(!noexcept(X(X::val())), ""); + static_assert(!noexcept(X::ref() = X::val()), ""); +}