r352949 - [Sema][ObjC] Allow declaring ObjC pointer members with non-trivial
Akira Hatanaka via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 1 18:23:41 PST 2019
Author: ahatanak
Date: Fri Feb 1 18:23:40 2019
New Revision: 352949
URL: http://llvm.org/viewvc/llvm-project?rev=352949&view=rev
Log:
[Sema][ObjC] Allow declaring ObjC pointer members with non-trivial
ownership qualifications in C++ unions under ARC.
An ObjC pointer member with non-trivial ownership qualifications causes
all of the defaulted special functions of the enclosing union to be
defined as deleted, except when the member has an in-class initializer,
the default constructor isn't defined as deleted.
rdar://problem/34213306
Differential Revision: https://reviews.llvm.org/D57438
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/test/SemaObjCXX/arc-0x.mm
cfe/trunk/test/SemaObjCXX/objc-weak.mm
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=352949&r1=352948&r2=352949&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Feb 1 18:23:40 2019
@@ -4649,13 +4649,15 @@ def note_deleted_special_member_class_su
"copy assignment operator of|move assignment operator of|destructor of|"
"constructor inherited by}0 "
"%1 is implicitly deleted because "
- "%select{base class %3|%select{||||variant }4field %3}2 has "
+ "%select{base class %3|%select{||||variant }4field %3}2 "
+ "%select{has "
"%select{no|a deleted|multiple|an inaccessible|a non-trivial}4 "
"%select{%select{default constructor|copy constructor|move constructor|copy "
"assignment operator|move assignment operator|destructor|"
"%select{default|corresponding|default|default|default}4 constructor}0|"
"destructor}5"
- "%select{||s||}4">;
+ "%select{||s||}4"
+ "|is an ObjC pointer}6">;
def note_deleted_default_ctor_uninit_field : Note<
"%select{default constructor of|constructor inherited by}0 "
"%1 is implicitly deleted because field %2 of "
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=352949&r1=352948&r2=352949&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Feb 1 18:23:40 2019
@@ -991,6 +991,17 @@ void CXXRecordDecl::addedMember(Decl *D)
setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs);
Data.HasIrrelevantDestructor = false;
+
+ if (isUnion()) {
+ data().DefaultedCopyConstructorIsDeleted = true;
+ data().DefaultedMoveConstructorIsDeleted = true;
+ data().DefaultedMoveAssignmentIsDeleted = true;
+ data().DefaultedDestructorIsDeleted = true;
+ data().NeedOverloadResolutionForCopyConstructor = true;
+ data().NeedOverloadResolutionForMoveConstructor = true;
+ data().NeedOverloadResolutionForMoveAssignment = true;
+ data().NeedOverloadResolutionForDestructor = true;
+ }
} else if (!Context.getLangOpts().ObjCAutoRefCount) {
setHasObjectMember(true);
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=352949&r1=352948&r2=352949&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Feb 1 18:23:40 2019
@@ -15923,7 +15923,8 @@ void Sema::ActOnFields(Scope *S, SourceL
QualType T = Context.getObjCObjectPointerType(FD->getType());
FD->setType(T);
} else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
- Record && !ObjCFieldLifetimeErrReported && Record->isUnion()) {
+ Record && !ObjCFieldLifetimeErrReported && Record->isUnion() &&
+ !getLangOpts().CPlusPlus) {
// It's an error in ARC or Weak if a field has lifetime.
// We don't want to report this in a system header, though,
// so we just make the field unavailable.
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=352949&r1=352948&r2=352949&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Feb 1 18:23:40 2019
@@ -6891,6 +6891,8 @@ struct SpecialMemberDeletionInfo
return ICI ? Sema::CXXInvalid : CSM;
}
+ bool shouldDeleteForVariantObjCPtrMember(FieldDecl *FD, QualType FieldType);
+
bool visitBase(CXXBaseSpecifier *Base) { return shouldDeleteForBase(Base); }
bool visitField(FieldDecl *Field) { return shouldDeleteForField(Field); }
@@ -6962,13 +6964,14 @@ bool SpecialMemberDeletionInfo::shouldDe
S.Diag(Field->getLocation(),
diag::note_deleted_special_member_class_subobject)
<< getEffectiveCSM() << MD->getParent() << /*IsField*/true
- << Field << DiagKind << IsDtorCallInCtor;
+ << Field << DiagKind << IsDtorCallInCtor << /*IsObjCPtr*/false;
} else {
CXXBaseSpecifier *Base = Subobj.get<CXXBaseSpecifier*>();
S.Diag(Base->getBeginLoc(),
diag::note_deleted_special_member_class_subobject)
<< getEffectiveCSM() << MD->getParent() << /*IsField*/ false
- << Base->getType() << DiagKind << IsDtorCallInCtor;
+ << Base->getType() << DiagKind << IsDtorCallInCtor
+ << /*IsObjCPtr*/false;
}
if (DiagKind == 1)
@@ -7020,6 +7023,30 @@ bool SpecialMemberDeletionInfo::shouldDe
return false;
}
+bool SpecialMemberDeletionInfo::shouldDeleteForVariantObjCPtrMember(
+ FieldDecl *FD, QualType FieldType) {
+ // The defaulted special functions are defined as deleted if this is a variant
+ // member with a non-trivial ownership type, e.g., ObjC __strong or __weak
+ // type under ARC.
+ if (!FieldType.hasNonTrivialObjCLifetime())
+ return false;
+
+ // Don't make the defaulted default constructor defined as deleted if the
+ // member has an in-class initializer.
+ if (CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer())
+ return false;
+
+ if (Diagnose) {
+ auto *ParentClass = cast<CXXRecordDecl>(FD->getParent());
+ S.Diag(FD->getLocation(),
+ diag::note_deleted_special_member_class_subobject)
+ << getEffectiveCSM() << ParentClass << /*IsField*/true
+ << FD << 4 << /*IsDtorCallInCtor*/false << /*IsObjCPtr*/true;
+ }
+
+ return true;
+}
+
/// Check whether we should delete a special member function due to the class
/// having a particular direct or virtual base class.
bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
@@ -7040,7 +7067,8 @@ bool SpecialMemberDeletionInfo::shouldDe
S.Diag(Base->getBeginLoc(),
diag::note_deleted_special_member_class_subobject)
<< getEffectiveCSM() << MD->getParent() << /*IsField*/ false
- << Base->getType() << /*Deleted*/ 1 << /*IsDtorCallInCtor*/ false;
+ << Base->getType() << /*Deleted*/ 1 << /*IsDtorCallInCtor*/ false
+ << /*IsObjCPtr*/false;
S.NoteDeletedFunction(BaseCtor);
}
return BaseCtor->isDeleted();
@@ -7054,6 +7082,9 @@ bool SpecialMemberDeletionInfo::shouldDe
QualType FieldType = S.Context.getBaseElementType(FD->getType());
CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+ if (inUnion() && shouldDeleteForVariantObjCPtrMember(FD, FieldType))
+ return true;
+
if (CSM == Sema::CXXDefaultConstructor) {
// For a default constructor, all references must be initialized in-class
// and, if a union, it must have a non-const member.
@@ -7115,6 +7146,9 @@ bool SpecialMemberDeletionInfo::shouldDe
for (auto *UI : FieldRecord->fields()) {
QualType UnionFieldType = S.Context.getBaseElementType(UI->getType());
+ if (shouldDeleteForVariantObjCPtrMember(&*UI, UnionFieldType))
+ return true;
+
if (!UnionFieldType.isConstQualified())
AllVariantFieldsAreConst = false;
Modified: cfe/trunk/test/SemaObjCXX/arc-0x.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-0x.mm?rev=352949&r1=352948&r2=352949&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-0x.mm (original)
+++ cfe/trunk/test/SemaObjCXX/arc-0x.mm Fri Feb 1 18:23:40 2019
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fobjc-arc -verify -fblocks -fobjc-exceptions %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -fobjc-weak -verify -fblocks -fobjc-exceptions %s
// "Move" semantics, trivial version.
void move_it(__strong id &&from) {
@@ -111,3 +111,160 @@ namespace test_err_arc_array_param_no_ow
func(^(A *a[]){}); // expected-error{{must explicitly describe intended ownership of an object array parameter}}
}
}
+
+namespace test_union {
+ // Implicitly-declared special functions of a union are deleted by default if
+ // ARC is enabled and the union has an ObjC pointer field.
+ union U0 {
+ id f0; // expected-note 6 {{'U0' is implicitly deleted because variant field 'f0' is an ObjC pointer}}
+ };
+
+ union U1 {
+ __weak id f0; // expected-note 12 {{'U1' is implicitly deleted because variant field 'f0' is an ObjC pointer}}
+ U1() = default; // expected-warning {{explicitly defaulted default constructor is implicitly deleted}} expected-note {{explicitly defaulted function was implicitly deleted here}}
+ ~U1() = default; // expected-warning {{explicitly defaulted destructor is implicitly deleted}} expected-note {{explicitly defaulted function was implicitly deleted here}}
+ U1(const U1 &) = default; // expected-warning {{explicitly defaulted copy constructor is implicitly deleted}} expected-note 2 {{explicitly defaulted function was implicitly deleted here}}
+ U1(U1 &&) = default; // expected-warning {{explicitly defaulted move constructor is implicitly deleted}}
+ U1 & operator=(const U1 &) = default; // expected-warning {{explicitly defaulted copy assignment operator is implicitly deleted}} expected-note 2 {{explicitly defaulted function was implicitly deleted here}}
+ U1 & operator=(U1 &&) = default; // expected-warning {{explicitly defaulted move assignment operator is implicitly deleted}}
+ };
+
+ id getStrong();
+
+ // If the ObjC pointer field of a union has a default member initializer, the
+ // implicitly-declared default constructor of the union is not deleted by
+ // default.
+ union U2 {
+ id f0 = getStrong(); // expected-note 4 {{'U2' is implicitly deleted because variant field 'f0' is an ObjC pointer}}
+ ~U2();
+ };
+
+ // It's fine if the user has explicitly defined the special functions.
+ union U3 {
+ id f0;
+ U3();
+ ~U3();
+ U3(const U3 &);
+ U3(U3 &&);
+ U3 & operator=(const U3 &);
+ U3 & operator=(U3 &&);
+ };
+
+ // ObjC pointer fields in anonymous union fields delete the defaulted special
+ // functions of the containing class.
+ struct S0 {
+ union {
+ id f0; // expected-note 6 {{'' is implicitly deleted because variant field 'f0' is an ObjC pointer}}
+ char f1;
+ };
+ };
+
+ struct S1 {
+ union {
+ union { // expected-note 2 {{'S1' is implicitly deleted because variant field '' has a non-trivial}} expected-note 4 {{'S1' is implicitly deleted because field '' has a deleted}}
+ id f0; // expected-note 2 {{'' is implicitly deleted because variant field 'f0' is an ObjC pointer}}
+ char f1;
+ };
+ int f2;
+ };
+ };
+
+ struct S2 {
+ union {
+ // FIXME: the note should say 'f0' is causing the special functions to be deleted.
+ struct { // expected-note 6 {{'S2' is implicitly deleted because variant field '' has a non-trivial}}
+ id f0;
+ int f1;
+ };
+ int f2;
+ };
+ int f3;
+ };
+
+ U0 *x0;
+ U1 *x1;
+ U2 *x2;
+ U3 *x3;
+ S0 *x4;
+ S1 *x5;
+ S2 *x6;
+
+ static union { // expected-error {{call to implicitly-deleted default constructor of}}
+ id g0; // expected-note {{default constructor of '' is implicitly deleted because variant field 'g0' is an ObjC pointer}}
+ };
+
+ static union { // expected-error {{call to implicitly-deleted default constructor of}}
+ union { // expected-note {{default constructor of '' is implicitly deleted because field '' has a deleted default constructor}}
+ union { // expected-note {{default constructor of '' is implicitly deleted because field '' has a deleted default constructor}}
+ __weak id g1; // expected-note {{default constructor of '' is implicitly deleted because variant field 'g1' is an ObjC pointer}}
+ int g2;
+ };
+ int g3;
+ };
+ int g4;
+ };
+
+ void testDefaultConstructor() {
+ U0 t0; // expected-error {{call to implicitly-deleted default constructor}}
+ U1 t1; // expected-error {{call to implicitly-deleted default constructor}}
+ U2 t2;
+ U3 t3;
+ S0 t4; // expected-error {{call to implicitly-deleted default constructor}}
+ S1 t5; // expected-error {{call to implicitly-deleted default constructor}}
+ S2 t6; // expected-error {{call to implicitly-deleted default constructor}}
+ }
+
+ void testDestructor(U0 *u0, U1 *u1, U2 *u2, U3 *u3, S0 *s0, S1 *s1, S2 *s2) {
+ delete u0; // expected-error {{attempt to use a deleted function}}
+ delete u1; // expected-error {{attempt to use a deleted function}}
+ delete u2;
+ delete u3;
+ delete s0; // expected-error {{attempt to use a deleted function}}
+ delete s1; // expected-error {{attempt to use a deleted function}}
+ delete s2; // expected-error {{attempt to use a deleted function}}
+ }
+
+ void testCopyConstructor(U0 *u0, U1 *u1, U2 *u2, U3 *u3, S0 *s0, S1 *s1, S2 *s2) {
+ U0 t0(*u0); // expected-error {{call to implicitly-deleted copy constructor}}
+ U1 t1(*u1); // expected-error {{call to implicitly-deleted copy constructor}}
+ U2 t2(*u2); // expected-error {{call to implicitly-deleted copy constructor}}
+ U3 t3(*u3);
+ S0 t4(*s0); // expected-error {{call to implicitly-deleted copy constructor}}
+ S1 t5(*s1); // expected-error {{call to implicitly-deleted copy constructor}}
+ S2 t6(*s2); // expected-error {{call to implicitly-deleted copy constructor}}
+ }
+
+ void testCopyAssignment(U0 *u0, U1 *u1, U2 *u2, U3 *u3, S0 *s0, S1 *s1, S2 *s2) {
+ *x0 = *u0; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x1 = *u1; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x2 = *u2; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x3 = *u3;
+ *x4 = *s0; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x5 = *s1; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x6 = *s2; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ }
+
+ // The diagnostics below refer to the deleted copy constructors and assignment
+ // operators since defaulted move constructors and assignment operators that are
+ // defined as deleted are ignored by overload resolution.
+
+ void testMoveConstructor(U0 *u0, U1 *u1, U2 *u2, U3 *u3, S0 *s0, S1 *s1, S2 *s2) {
+ U0 t0(static_cast<U0 &&>(*u0)); // expected-error {{call to implicitly-deleted copy constructor}}
+ U1 t1(static_cast<U1 &&>(*u1)); // expected-error {{call to implicitly-deleted copy constructor}}
+ U2 t2(static_cast<U2 &&>(*u2)); // expected-error {{call to implicitly-deleted copy constructor}}
+ U3 t3(static_cast<U3 &&>(*u3));
+ S0 t4(static_cast<S0 &&>(*s0)); // expected-error {{call to implicitly-deleted copy constructor}}
+ S1 t5(static_cast<S1 &&>(*s1)); // expected-error {{call to implicitly-deleted copy constructor}}
+ S2 t6(static_cast<S2 &&>(*s2)); // expected-error {{call to implicitly-deleted copy constructor}}
+ }
+
+ void testMoveAssignment(U0 *u0, U1 *u1, U2 *u2, U3 *u3, S0 *s0, S1 *s1, S2 *s2) {
+ *x0 = static_cast<U0 &&>(*u0); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x1 = static_cast<U1 &&>(*u1); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x2 = static_cast<U2 &&>(*u2); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x3 = static_cast<U3 &&>(*u3);
+ *x4 = static_cast<S0 &&>(*s0); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x5 = static_cast<S1 &&>(*s1); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ *x6 = static_cast<S2 &&>(*s2); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}}
+ }
+}
Modified: cfe/trunk/test/SemaObjCXX/objc-weak.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/objc-weak.mm?rev=352949&r1=352948&r2=352949&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/objc-weak.mm (original)
+++ cfe/trunk/test/SemaObjCXX/objc-weak.mm Fri Feb 1 18:23:40 2019
@@ -13,7 +13,7 @@ struct S {
};
union U {
- __weak id a; // expected-error {{ARC forbids Objective-C objects in union}}
+ __weak id a;
S b; // expected-error {{union member 'b' has a non-trivial copy constructor}}
};
More information about the cfe-commits
mailing list