https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/211231
>From 1cee95814a28c5f67409bcb7a5c46b3155264aa0 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <[email protected]> Date: Wed, 22 Jul 2026 12:58:27 +0200 Subject: [PATCH] [Clang] Add [[clang::complete_on_member_instantiation]] --- clang/include/clang/Basic/Attr.td | 11 ++++- clang/include/clang/Basic/AttrDocs.td | 22 +++++++++ .../clang/Basic/DiagnosticSemaKinds.td | 3 ++ clang/lib/Sema/SemaDeclAttr.cpp | 15 ++++++ .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 +++ ...a-attribute-supported-attributes-list.test | 1 + .../attr-complete-on-member-instantiation.cpp | 49 +++++++++++++++++++ 7 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 clang/test/SemaCXX/attr-complete-on-member-instantiation.cpp diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 1a5bd2301dfc8..3555ccf3ce7ec 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -5316,7 +5316,7 @@ def HLSLVkLocation : HLSLAnnotationAttr { } // `row_major` / `column_major` are HLSL keywords that select the in-memory -// layout of a matrix-typed declaration. +// layout of a matrix-typed declaration. def HLSLRowMajor : TypeAttr { let Spellings = [CustomKeyword<"row_major">]; let LangOpts = [HLSL]; @@ -5503,3 +5503,12 @@ def Personality : InheritableAttr { let Subjects = SubjectList<[Function]>; let Documentation = [PersonalityDocs]; } + +def CompleteOnMemberInst : InheritableAttr { + let Spellings = [Clang<"complete_on_member_instantiation">]; + let Args = [TypeArgument<"CompleteType">]; + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [CompleteOnMemberInstDocs]; + let InheritEvenIfAlreadyPresent = 1; + let TemplateDependent = 1; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 05e4cb0870652..05ca4209d7d4a 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -10266,3 +10266,25 @@ The attribute is also supported with blocks and in Objective-C. } }]; } + +def CompleteOnMemberInstDocs : Documentation { + let Category = DocCatDecl; + let Content = [{ +The ``complete_on_member_instantiation`` attribute can be applied to classes +which require a type to be complete whenever a member function is called. +Incomplete types are diagnosed at the point of the member function call. + +.. code-block:: c++ + + template <class T> + class [[clang::complete_on_member_instantiation(T)]] vector { + T* begin(); + }; + + struct incomplete; + + void example(vector<incomplete>& v) { + v.begin(); // this is guaranteed to produce an error + } + }]; +} diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3ff7e30d9f1f7..5e2b82545f907 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2182,6 +2182,9 @@ def ext_out_of_line_qualified_id_type_names_constructor : ExtWarn< "%select{'typename'|'template'}2 keyword">, SFINAEFailure, InGroup<DiagGroup<"injected-class-name">>; +def err_incomplete_type_on_member_inst : Error< + "%0 has to be complete when calling a member function">; + // C++ class members def err_storageclass_invalid_for_member : Error< "storage class specified for a member declaration">; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 1b272b5416860..59bc09e471075 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2071,6 +2071,18 @@ static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) CommonAttr(S.Context, AL)); } +static void handleCompleteOnMemberInstAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.hasParsedType()) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; + return; + } + + TypeSourceInfo *ParmTSI = nullptr; + S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI); + assert(ParmTSI && "no type source info for attribute argument"); + D->addAttr(CompleteOnMemberInstAttr::Create(S.Context, ParmTSI, AL)); +} + static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.isDeclspecAttribute()) { const auto &Triple = S.getASTContext().getTargetInfo().getTriple(); @@ -7787,6 +7799,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_Common: handleCommonAttr(S, D, AL); break; + case ParsedAttr::AT_CompleteOnMemberInst: + handleCompleteOnMemberInstAttr(S, D, AL); + break; case ParsedAttr::AT_CUDAConstant: handleConstantAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index c2e90624b8a6e..0776144f8826e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5766,6 +5766,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, } } + if (auto *RD = dyn_cast<CXXRecordDecl>(Function->getDeclContext())) { + for (auto *COMI : RD->specific_attrs<CompleteOnMemberInstAttr>()) { + if (RequireCompleteType(PointOfInstantiation, COMI->getCompleteType(), + diag::err_incomplete_type_on_member_inst)) + return; + } + } + NonSFINAEContext _(*this); InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst.isInvalid()) diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 8bca68e2119e7..804399c967255 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -57,6 +57,7 @@ // CHECK-NEXT: CmseNSEntry (SubjectMatchRule_function) // CHECK-NEXT: Cold (SubjectMatchRule_function) // CHECK-NEXT: Common (SubjectMatchRule_variable) +// CHECK-NEXT: CompleteOnMemberInst (SubjectMatchRule_record) // CHECK-NEXT: Const (SubjectMatchRule_function) // CHECK-NEXT: ConstInit (SubjectMatchRule_variable_is_global) // CHECK-NEXT: Constructor (SubjectMatchRule_function) diff --git a/clang/test/SemaCXX/attr-complete-on-member-instantiation.cpp b/clang/test/SemaCXX/attr-complete-on-member-instantiation.cpp new file mode 100644 index 0000000000000..3b4de2963bb27 --- /dev/null +++ b/clang/test/SemaCXX/attr-complete-on-member-instantiation.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only + +template <class T> +struct [[clang::complete_on_member_instantiation]] S1 {}; // expected-error {{'clang::complete_on_member_instantiation' attribute takes one argument}} + +template <class T> +struct [[clang::complete_on_member_instantiation(1)]] S2 {}; // expected-error {{expected a type}} + +template <class T> +struct [[clang::complete_on_member_instantiation(T)]] RequiresComplete { + void func() {} +}; + +struct Complete {}; +struct Incomplete; // expected-note 7 {{forward declaration of 'Incomplete'}} + +void func(RequiresComplete<Incomplete>& incomplete, RequiresComplete<Complete>& complete) { + complete.func(); + incomplete.func(); // expected-error {{'Incomplete' has to be complete when calling a member function}} +} + +template <class T, class U> +struct [[clang::complete_on_member_instantiation(T), clang::complete_on_member_instantiation(U)]] RequiresComplete2 { + void func() {} +}; + +void func2(RequiresComplete2<Incomplete, Incomplete> both_incomplete, + RequiresComplete2<Incomplete, Complete> first_incomplete, + RequiresComplete2<Complete, Incomplete> second_incomplete) { + both_incomplete.func(); // expected-error {{'Incomplete' has to be complete when calling a member function}} + first_incomplete.func(); // expected-error {{'Incomplete' has to be complete when calling a member function}} + second_incomplete.func(); // expected-error {{'Incomplete' has to be complete when calling a member function}} +} + +template <class T, class U> +struct [[clang::complete_on_member_instantiation(T), clang::complete_on_member_instantiation(U)]] RequiresComplete3; + +template <class T, class U> +struct RequiresComplete3 { + void func() {} +}; + +void func2(RequiresComplete3<Incomplete, Incomplete> both_incomplete, + RequiresComplete3<Incomplete, Complete> first_incomplete, + RequiresComplete3<Complete, Incomplete> second_incomplete) { + both_incomplete.func(); // expected-error {{'Incomplete' has to be complete when calling a member function}} + first_incomplete.func(); // expected-error {{'Incomplete' has to be complete when calling a member function}} + second_incomplete.func(); // expected-error {{'Incomplete' has to be complete when calling a member function}} +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
