diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8c9d3facd1c9..77f1b9b0d707 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5896,7 +5896,7 @@ def note_deleted_special_member_class_subobject : Note< def note_deleted_default_ctor_uninit_field : Note< "%select{default constructor of|constructor inherited by}0 " "%1 is implicitly deleted because field %2 of " - "%select{reference|const-qualified}4 type %3 would not be initialized">; + "%select{reference|const-qualified|reducer}4 type %3 would not be initialized">; def note_deleted_default_ctor_all_const : Note< "%select{default constructor of|constructor inherited by}0 " "%1 is implicitly deleted because all " @@ -10895,8 +10895,8 @@ def incomplete_hyperobject : Error< def nested_hyperobject : Error< "type %0, which contains a hyperobject, may not be a hyperobject">; -def reducer_callbacks_not_allowed: Warning< - "reducer callbacks not implemented for structure members">, +def reducer_registration_not_implemented: Warning< + "reducer registration not implemented for structure members">, InGroup; def err_invalid_reducer_callback : Error< diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 117e802dae2d..44b70b24cacb 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1083,6 +1083,15 @@ void CXXRecordDecl::addedMember(Decl *D) { data().DefaultedCopyConstructorIsDeleted = true; } + if (T->isHyperobjectType()) { + // Do not allow braced list initialization, which would + // suppress hyperobject registration. + data().Aggregate = false; + data().HasIrrelevantDestructor = false; + data().HasTrivialSpecialMembers &= ~SMF_All; + data().HasTrivialSpecialMembersForCall &= ~SMF_All; + } + if (!Field->hasInClassInitializer() && !Field->isMutable()) { if (CXXRecordDecl *FieldType = T->getAsCXXRecordDecl()) { if (FieldType->hasDefinition() && !FieldType->allowConstDefaultInit()) diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 8460eec245dd..766c20f8189a 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -707,6 +707,10 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS, } } + ReducerCallbacks RCB = {0, 0}; + if (getReducer(Field, RCB)) + EmitReducerInit(Field, RCB, LHS.getPointer(*this)); + // Ensure that we destroy this object if an exception is thrown // later in the constructor. QualType::DestructionKind dtorKind = FieldType.isDestructedType(); @@ -1639,6 +1643,11 @@ namespace { LValue LV = CGF.EmitLValueForField(ThisLV, field); assert(LV.isSimple()); + if (field->getType()->isHyperobjectType()) { + llvm::Function *F = + CGF.CGM.getIntrinsic(llvm::Intrinsic::reducer_unregister); + CGF.Builder.CreateCall(F, {LV.getPointer(CGF)}); + } CGF.emitDestroy(LV.getAddress(CGF), field->getType(), destroyer, flags.isForNormalCleanup() && useEHCleanupForArray); } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 95ab36c8f43d..b39f70789d7b 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1877,7 +1877,8 @@ void CodeGenFunction::emitZeroOrPatternForAutoVarInit(QualType type, } } -bool CodeGenFunction::getReducer(const VarDecl *D, ReducerCallbacks &CB) { +bool CodeGenFunction::getReducer(const DeclaratorDecl *D, + ReducerCallbacks &CB) { if (const HyperobjectType *H = D->getType()->getAs()) { if (H->hasCallbacks()) { CB.Identity = H->getIdentity(); @@ -1902,7 +1903,7 @@ void CodeGenFunction::destroyHyperobject(CodeGenFunction &CGF, Address Addr, } } -void CodeGenFunction::EmitReducerInit(const VarDecl *D, +void CodeGenFunction::EmitReducerInit(const DeclaratorDecl *D, const ReducerCallbacks &C, llvm::Value *Addr) { RValue Identity = EmitAnyExpr(C.Identity); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index f39f7874af7a..678f373f99ab 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3778,8 +3778,8 @@ class CodeGenFunction : public CodeGenTypeCache { Expr *Reduce; }; - bool getReducer(const VarDecl *D, ReducerCallbacks &CB); - void EmitReducerInit(const VarDecl *D, const ReducerCallbacks &CB, + bool getReducer(const DeclaratorDecl *D, ReducerCallbacks &CB); + void EmitReducerInit(const DeclaratorDecl *D, const ReducerCallbacks &CB, llvm::Value *Addr); /// Emits the alloca and debug information for the size expressions for each diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c577c4bd3855..2dcb41563a24 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -19234,11 +19234,12 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, continue; } - if (!FDTy->isDependentType()) { + // In C++ a constructor and destructor will be synthesized + // to register hyperobjects. + if (!CXXRecord && !FDTy->isDependentType()) { if (const HyperobjectType *HT = FDTy->getAs()) { - if (HT->hasCallbacks()) - Diag(FD->getLocation(), diag::reducer_callbacks_not_allowed) - << FD->getDeclName(); + Diag(FD->getLocation(), diag::reducer_registration_not_implemented) + << FD->getDeclName(); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d1b810b08cf8..9b59bd7d76a4 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5096,7 +5096,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, "Unhandled implicit init kind!"); QualType FieldBaseElementType = - SemaRef.Context.getBaseElementType(Field->getType()); + SemaRef.Context.getBaseElementType(Field->getType().stripHyperobject()); if (FieldBaseElementType->isRecordType()) { InitializedEntity InitEntity = @@ -5863,7 +5863,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, QualType FieldType = Context.getBaseElementType(Field->getType()); - const RecordType* RT = FieldType->getAs(); + const RecordType* RT = FieldType.stripHyperobject()->getAs(); if (!RT) continue; @@ -9595,6 +9595,12 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { << !!ICI << MD->getParent() << FD << FieldType << /*Reference*/0; return true; } + if (FieldType->isHyperobjectType() && !FD->hasInClassInitializer()) { + if (Diagnose) + S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) + << !!ICI << MD->getParent() << FD << FieldType << /*Reducer*/2; + return true; + } // C++11 [class.ctor]p5 (modified by DR2394): any non-variant non-static // data member of const-qualified type (or array thereof) with no // brace-or-equal-initializer is not const-default-constructible. diff --git a/clang/test/Cilk/222.cpp b/clang/test/Cilk/222.cpp index 8184b3e11f22..e92e8b975ad7 100644 --- a/clang/test/Cilk/222.cpp +++ b/clang/test/Cilk/222.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -x c++ -fopencilk -emit-llvm -verify -mllvm -use-opencilk-runtime-bc=false -mllvm -debug-abi-calls -o /dev/null +// expected-no-diagnostics #define DEPTH 3 template struct R { static void identity(void *); @@ -6,13 +7,7 @@ template struct R { int get(int depth) { return depth <= 0 ? i : field.get(depth - 1); } public: R field; - // expected-note@-1{{in instantiation}} - // expected-note@-2{{in instantiation}} - // expected-note@-3{{in instantiation}} int _Hyperobject(identity, reduce) i; - // expected-warning@-1{{reducer callbacks not implemented for structure members}} - // expected-warning@-2{{reducer callbacks not implemented for structure members}} - // expected-warning@-3{{reducer callbacks not implemented for structure members}} }; template<> struct R<0> { int field; int get(int) { return field; } }; @@ -20,7 +15,3 @@ template<> struct R<0> { int field; int get(int) { return field; } }; extern R r; int f() { return r.get(DEPTH / 2); } -// expected-note@-1{{in instantiation}} -// expected-note@-2{{in instantiation}} -// expected-note@-3{{in instantiation}} - diff --git a/clang/test/Cilk/hyper-destruct2.cpp b/clang/test/Cilk/hyper-destruct2.cpp new file mode 100644 index 000000000000..6f796f68d464 --- /dev/null +++ b/clang/test/Cilk/hyper-destruct2.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 %s -x c++ -fopencilk -verify -disable-llvm-passes -S -emit-llvm -o - | FileCheck %s +// expected-no-diagnostics +template +struct Inner +{ + static void identity(void *); + static void reduce(void *, void *); + Inner(); + ~Inner() noexcept { } +}; + +struct Outer { + Inner _Hyperobject(&Inner::identity, &Inner::reduce) member; + Outer(); + ~Outer(); +}; + +// Make sure the appropriate variant of ~Inner() is emitted. +// CHECK: {{^}}define{{.*}} void @_ZN5OuterD2Ev +// CHECK: call void @_ZN5InnerIcED2Ev +// CHECK: {{^}}define linkonce_odr void @_ZN5InnerIcED2Ev + +Outer::~Outer() { } diff --git a/clang/test/Cilk/hyper-errors.c b/clang/test/Cilk/hyper-errors.c index 01e269add34e..5458face1382 100644 --- a/clang/test/Cilk/hyper-errors.c +++ b/clang/test/Cilk/hyper-errors.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -fopencilk -verify -fsyntax-only -Werror=incompatible-function-pointer-types -Werror=int-conversion -// RUN: %clang_cc1 %s -x c++ -fopencilk -verify -fsyntax-only struct C { int _Hyperobject c; }; +// expected-warning@-1{{reducer registration not implemented for structure members}} struct C _Hyperobject c; // expected-error{{type 'struct C', which contains a hyperobject, may not be a hyperobject}} long _Hyperobject d; // expected-note{{previous definition}} void f() { @@ -17,7 +17,7 @@ extern void reduce(void *, void *), identity(void *); struct D { int _Hyperobject(identity, reduce) field; - // expected-warning@-1{{reducer callbacks not implemented for structure members}} + // expected-warning@-1{{reducer registration not implemented for structure members}} }; int _Hyperobject(reduce, identity) h; diff --git a/clang/test/Cilk/hyper-errors.cpp b/clang/test/Cilk/hyper-errors.cpp new file mode 100644 index 000000000000..e5a45d155d18 --- /dev/null +++ b/clang/test/Cilk/hyper-errors.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 %s -x c++ -fopencilk -verify -fsyntax-only +struct C { int _Hyperobject c = 0; }; +struct C _Hyperobject c; // expected-error{{type 'struct C', which contains a hyperobject, may not be a hyperobject}} +long _Hyperobject d; // expected-note{{previous definition}} +void f() { + extern int _Hyperobject d; + // expected-error@-1{{redeclaration of 'd' with a different type: 'int _Hyperobject' vs 'long _Hyperobject'}} +} +char _Hyperobject e; // expected-note{{previous definition}} +typedef long _Hyperobject long_h; +void g() { + extern long_h e; // expected-error{{redeclaration of 'e'}} +} + +extern void reduce(void *, void *), identity(void *); + +struct D { + int _Hyperobject(identity, reduce) field; +}; + +int _Hyperobject(reduce, identity) h; + // expected-error@-1{{incompatible function pointer types passing 'void (*)(void *, void *)' to parameter of type 'void (*)(void *)'}} + // expected-error@-2{{incompatible function pointer types passing 'void (*)(void *)' to parameter of type 'void (*)(void *, void *)'}} + +int _Hyperobject(x) i; // expected-error{{use of undeclared identifier 'x'}} +int _Hyperobject(0) j; // expected-error{{hyperobject must have 0 or 2 callbacks}} +int _Hyperobject(0,0,0,0) k; // expected-error{{hyperobject must have 0 or 2 callbacks}} +int _Hyperobject(0, 1) x; // expected-error{{incompatible integer to pointer conversion passing 'int' to parameter of type 'void (*)(void *, void *)'}} + +void function() { + int _Hyperobject(typo1, reduce) var1 = 0; + // expected-error@-1{{use of undeclared identifier 'typo1'}} + int _Hyperobject(typo2, typo3) var2 = 0; + // expected-error@-1{{use of undeclared identifier 'typo2'}} + // expected-error@-2{{use of undeclared identifier 'typo3'}} + int _Hyperobject(0, typo4) var3 = 0; + // expected-error@-1{{use of undeclared identifier 'typo4'}} +} diff --git a/clang/test/Cilk/hyper-init-error.cpp b/clang/test/Cilk/hyper-init-error.cpp new file mode 100644 index 000000000000..bc54fb0fa29d --- /dev/null +++ b/clang/test/Cilk/hyper-init-error.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -fopencilk -verify -fsyntax-only +extern void id(void *), reduce(void *, void *); +struct uninit_hyperobject { + // expected-note@-1{{implicit copy}} + // expected-note@-2{{implicit move}} + // expected-note@-3{{implicit default}} + int _Hyperobject(id, reduce) field; + // expected-note@-1{{would not be initialized}} +}; + +// braced initializer lists do not work +uninit_hyperobject h1 = {-1}; +// expected-error@-1{{no matching constructor for initialization}} + +uninit_hyperobject h2; +// expected-error@-1{{implicitly-deleted default constructor}} + +struct init_hyperobject { + int _Hyperobject(id, reduce) field = 0; +}; + +init_hyperobject h3; diff --git a/clang/test/Cilk/hyper-member.cpp b/clang/test/Cilk/hyper-member.cpp new file mode 100644 index 000000000000..28ccb6b78a19 --- /dev/null +++ b/clang/test/Cilk/hyper-member.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 %s -x c++ -triple aarch64-freebsd -fopencilk -S -emit-llvm -disable-llvm-passes -o - | FileCheck %s +struct ctor_dtor { ctor_dtor(); ~ctor_dtor(); long data; }; +struct ctor_only { ctor_only(); long data; }; +struct dtor_only { ~dtor_only(); long data; }; +struct neither { long data; }; +extern void identity(void *), reduce(void *, void *); +struct with_ctor_dtor { + with_ctor_dtor(); + ~with_ctor_dtor(); + ctor_dtor _Hyperobject(identity, reduce) field; +}; + +// Hyperobject field is constructed then registered. +// CHECK-LABEL: _ZN14with_ctor_dtorC2Ev +// CHECK: call void @_ZN9ctor_dtorC1Ev +// CHECK: call void @llvm.reducer.register +with_ctor_dtor::with_ctor_dtor() { } + +// Hyperobject field is destructed then unregistered. +// CHECK-LABEL: _ZN14with_ctor_dtorD2Ev +// CHECK: call void @llvm.reducer.unregister +// CHECK: call void @_ZN9ctor_dtorD1Ev +with_ctor_dtor::~with_ctor_dtor() { } + +template struct wrapper { + wrapper(); + ~wrapper(); + Field field; +}; + +// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9ctor_dtorEC2Ev +// CHECK: call void @_ZN9ctor_dtorC1Ev +// CHECK: call void @llvm.reducer.register +template<> wrapper::wrapper() { } +// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9ctor_dtorED2Ev +// CHECK: call void @llvm.reducer.unregister +// CHECK: call void @_ZN9ctor_dtorD1Ev +template<> wrapper::~wrapper() { } + +// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9ctor_onlyEC2Ev +// CHECK: call void @_ZN9ctor_onlyC1Ev +// CHECK: call void @llvm.reducer.register +template<> wrapper::wrapper() { } + +// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9ctor_onlyED2Ev +// CHECK: call void @llvm.reducer.unregister +// CHECK-NOT: call void @_ZN9ctor_onlyD1Ev +template<> wrapper::~wrapper() { } + +// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9dtor_onlyEC2Ev +// CHECK-NOT: call void @_ZN9dtor_onlyC1Ev +// CHECK: call void @llvm.reducer.register +template<> wrapper::wrapper() { } + +// CHECK-LABEL: define dso_local void @_ZN7wrapperIH9dtor_onlyED2Ev +// CHECK: call void @llvm.reducer.unregister +// CHECK: call void @_ZN9dtor_onlyD1Ev +template<> wrapper::~wrapper() { } + +// CHECK-LABEL: define dso_local void @_ZN7wrapperIH7neitherEC2Ev +// CHECK-NOT: call void @_ZN7neitherC1Ev +// CHECK: call void @llvm.reducer.register +template<> wrapper::wrapper() { } + +// CHECK-LABEL: define dso_local void @_ZN7wrapperIH7neitherED2Ev +// CHECK: call void @llvm.reducer.unregister +// CHECK-NOT: call void @_ZN7neitherD1Ev +template<> wrapper::~wrapper() { } diff --git a/clang/test/Cilk/hyper-register.cpp b/clang/test/Cilk/hyper-register.cpp new file mode 100644 index 000000000000..a39e6050b08c --- /dev/null +++ b/clang/test/Cilk/hyper-register.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 %s -x c++ -fopencilk -S -emit-llvm -disable-llvm-passes -triple aarch64-freebsd14.1 -o - | FileCheck %s + +struct S { + static void identity(void *); + static void reduce(void *, void *); + int _Hyperobject(identity, reduce) member = 0; + S(); + ~S(); +}; + +// CHECK-LABEL: _ZN1SC2Ev +// CHECK: call void @llvm.reducer.register +S::S() {} + +// CHECK-LABEL: _ZN1SD2Ev +// CHECK: call void @llvm.reducer.unregister +S::~S() {} + +void f() { + struct S s; +} diff --git a/clang/test/Cilk/hyper-struct-assign.c b/clang/test/Cilk/hyper-struct-assign.c index 23fbc8ae77ed..91c2871fbbc6 100644 --- a/clang/test/Cilk/hyper-struct-assign.c +++ b/clang/test/Cilk/hyper-struct-assign.c @@ -1,6 +1,7 @@ // RUN: %clang_cc1 %s -fopencilk -verify -fsyntax-only struct S { long _Hyperobject field; }; +// expected-warning@-1{{reducer registration not implemented for structure members}} extern struct S x, y; struct S simple_assign(long val) diff --git a/clang/test/Cilk/hyper-template-errors.cpp b/clang/test/Cilk/hyper-template-errors.cpp index 300dc90acf6e..b456d8f8434a 100644 --- a/clang/test/Cilk/hyper-template-errors.cpp +++ b/clang/test/Cilk/hyper-template-errors.cpp @@ -7,7 +7,8 @@ struct reducer // expected-error@-1{{type 'long _Hyperobject', which contains a hyperobject, may not be a hyperobject}} // expected-error@-2{{type 'reducer', which contains a hyperobject, may not be a hyperobject}} // expected-error@-3{{type 'wrap', which contains a hyperobject, may not be a hyperobject}} - int _Hyperobject value2; + int _Hyperobject value2 = 0; + reducer(); }; reducer r_hl; // expected-note{{in instantiation}} diff --git a/clang/test/Cilk/hyper-template2.cpp b/clang/test/Cilk/hyper-template2.cpp index 01b90a8cda76..883ad62e7961 100644 --- a/clang/test/Cilk/hyper-template2.cpp +++ b/clang/test/Cilk/hyper-template2.cpp @@ -1,20 +1,18 @@ -// RUN: %clang_cc1 %s -x c++ -fopencilk -verify -S -emit-llvm -disable-llvm-passes -o - | FileCheck %s +// RUN: %clang_cc1 %s -x c++ -fopencilk -S -emit-llvm -disable-llvm-passes -o - | FileCheck %s template struct reducer { static void identity(void *); static void reduce(void *, void *); char pad; - // Registration of structure members is not implemented. VIEW _Hyperobject(identity, reduce) value; - // expected-warning@-1{{reducer callbacks not implemented}} reducer(); ~reducer(); }; // CHECK: call {{.+}} @_ZN7reducerIsEC1Ev // CHECK: @_ZN7reducerIsED1Ev -reducer r; // expected-note{{in instantiation}} +reducer r; // CHECK-LABEL: _Z1fv // CHECK: call ptr @llvm.hyper.lookup diff --git a/clang/test/Cilk/hyper-type-delete.cpp b/clang/test/Cilk/hyper-type-delete.cpp index 48d6af8f3437..c005d6221287 100644 --- a/clang/test/Cilk/hyper-type-delete.cpp +++ b/clang/test/Cilk/hyper-type-delete.cpp @@ -9,7 +9,7 @@ void reduce(void *l, void *r); using S_r = S _Hyperobject(identity, reduce); class Foo { - S_r r; // expected-warning{{reducer callbacks not implemented for structure members}} + S_r r; public: ~Foo() { delete r; }; // expected-error{{cannot delete expression of type 'S_r' (aka 'S _Hyperobject(identity, reduce)')}} };