https://github.com/spaits updated https://github.com/llvm/llvm-project/pull/201379
From cd148bf201459dbe9ac18b8cf4a473147a67ab1e Mon Sep 17 00:00:00 2001 From: Gabor Spaits <[email protected]> Date: Thu, 4 Jun 2026 21:50:26 +0200 Subject: [PATCH 1/7] [Sema]Report error for non-base types in constructor initializers before causing issue in initializer order --- clang/lib/Sema/SemaDeclCXX.cpp | 49 +++++++++++++++++----------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 418ff01f3d98a..215bd3a7d3327 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -17,6 +17,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ComparisonCategories.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DynamicRecursiveASTVisitor.h" @@ -4819,33 +4820,33 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, return true; } + if (!Dependent && declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl())) + return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl); + // Check for direct and virtual base classes. const CXXBaseSpecifier *DirectBaseSpec = nullptr; const CXXBaseSpecifier *VirtualBaseSpec = nullptr; - if (!Dependent) { - if (declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl())) - return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl); - - FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, - VirtualBaseSpec); - - // C++ [base.class.init]p2: - // Unless the mem-initializer-id names a nonstatic data member of the - // constructor's class or a direct or virtual base of that class, the - // mem-initializer is ill-formed. - if (!DirectBaseSpec && !VirtualBaseSpec) { - // If the class has any dependent bases, then it's possible that - // one of those types will resolve to the same type as - // BaseType. Therefore, just treat this as a dependent base - // class initialization. FIXME: Should we try to check the - // initialization anyway? It seems odd. - if (ClassDecl->hasAnyDependentBases()) - Dependent = true; - else - return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) - << BaseType << Context.getCanonicalTagType(ClassDecl) - << BaseTInfo->getTypeLoc().getSourceRange(); - } + + FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, + VirtualBaseSpec); + + // C++ [base.class.init]p2: + // Unless the mem-initializer-id names a nonstatic data member of the + // constructor's class or a direct or virtual base of that class, the + // mem-initializer is ill-formed. + if (!DirectBaseSpec && !VirtualBaseSpec) { + // If the class has any dependent bases, then it's possible that + // one of those types will resolve to the same type as + // BaseType. Therefore, just treat this as a dependent base + // class initialization. FIXME: Should we try to check the + // initialization anyway? It seems odd. + if (ClassDecl->hasAnyDependentBases()) + Dependent = true; + // We may have a delegating initializer + else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl())) + return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) + << BaseType << Context.getCanonicalTagType(ClassDecl) + << BaseTInfo->getTypeLoc().getSourceRange(); } if (Dependent) { From 60e1c1fdeadc699efc7d08edca5862f63f584bf3 Mon Sep 17 00:00:00 2001 From: Gabor Spaits <[email protected]> Date: Thu, 4 Jun 2026 22:26:40 +0200 Subject: [PATCH 2/7] Fix and clean up testing --- .../cppcoreguidelines/pro-type-member-init.cpp | 2 +- clang/test/SemaCXX/constructor-initializer.cpp | 18 ++++++++++++++++++ .../warn-reorder-ctor-initialization.cpp | 10 ---------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp index 55963eae2c1b5..e1724c3c1e338 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp @@ -647,7 +647,7 @@ namespace gh192510 { }; template<typename T> - class X: public Base { + class X: public Base, private C<T> { using INT = C<T>; X(INT i) : INT(i) {} // no crash diff --git a/clang/test/SemaCXX/constructor-initializer.cpp b/clang/test/SemaCXX/constructor-initializer.cpp index 96be8dda97735..ff6374d6eb6ef 100644 --- a/clang/test/SemaCXX/constructor-initializer.cpp +++ b/clang/test/SemaCXX/constructor-initializer.cpp @@ -323,3 +323,21 @@ A f2(const B &b) { return b; // expected-error {{no matching constructor for initialization of 'B'}} } } + +namespace PR7179 { +struct X +{ + struct Y + { + template <class T> Y(T x) : X(x) { } // expected-error {{type 'X' is not a direct or virtual base of 'PR7179::X::Y'}} + }; +}; +} + +namespace PR201379 { +struct S1 { + template<typename T> + S1(T) : d(), T() {} // expected-error {{type 'T' is not a direct or virtual base of 'PR201379::S1'}} + int d; +}; +} diff --git a/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp b/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp index 0613338945978..b0153c6984b5b 100644 --- a/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp +++ b/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp @@ -120,16 +120,6 @@ namespace test3 { }; } -namespace PR7179 { - struct X - { - struct Y - { - template <class T> Y(T x) : X(x) { } - }; - }; -} - namespace test3 { struct foo { struct { From 10ce0dacdf643412bf7a9a8871f74d6cf433a3d2 Mon Sep 17 00:00:00 2001 From: Gabor Spaits <[email protected]> Date: Thu, 4 Jun 2026 22:30:46 +0200 Subject: [PATCH 3/7] Fix and clean up testing and some formatting too --- clang/lib/Sema/SemaDeclCXX.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 215bd3a7d3327..aeb4258e9603d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4820,7 +4820,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, return true; } - if (!Dependent && declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl())) + if (!Dependent && + declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl())) return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl); // Check for direct and virtual base classes. @@ -4835,14 +4836,15 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // constructor's class or a direct or virtual base of that class, the // mem-initializer is ill-formed. if (!DirectBaseSpec && !VirtualBaseSpec) { - // If the class has any dependent bases, then it's possible that - // one of those types will resolve to the same type as - // BaseType. Therefore, just treat this as a dependent base - // class initialization. FIXME: Should we try to check the - // initialization anyway? It seems odd. + // If the class has any dependent bases, then it's possible that one of + // those types will resolve to the same type as BaseType. Therefore, just + // treat this as a dependent base class initialization. + // FIXME: Should we try to check the initialization anyway? It seems odd. if (ClassDecl->hasAnyDependentBases()) Dependent = true; - // We may have a delegating initializer + // We may have a delegating initializer here, since that is also a type, + // that isn't a direct or virtual base of the instantiated type. That will + // be handled later. else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl())) return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) << BaseType << Context.getCanonicalTagType(ClassDecl) From 32b76252ff31ee9a376e84a018c233717e537038 Mon Sep 17 00:00:00 2001 From: Gabor Spaits <[email protected]> Date: Thu, 4 Jun 2026 22:35:19 +0200 Subject: [PATCH 4/7] Comment --- clang/lib/Sema/SemaDeclCXX.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index aeb4258e9603d..125f2ba82553a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4842,9 +4842,9 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // FIXME: Should we try to check the initialization anyway? It seems odd. if (ClassDecl->hasAnyDependentBases()) Dependent = true; - // We may have a delegating initializer here, since that is also a type, - // that isn't a direct or virtual base of the instantiated type. That will - // be handled later. + // We may have a delegating initializer here but in a dependent context. + // Since that is also a type, that isn't a direct or virtual base of the + // instantiated type. That will be handled later. else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl())) return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) << BaseType << Context.getCanonicalTagType(ClassDecl) From 393f244a70537d93051e82b4795e4e5c721a51e2 Mon Sep 17 00:00:00 2001 From: Gabor Spaits <[email protected]> Date: Wed, 24 Jun 2026 11:26:12 +0200 Subject: [PATCH 5/7] Think of the case where there is a base class --- clang/lib/Sema/SemaDeclCXX.cpp | 68 +++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 125f2ba82553a..3e62fe3d30631 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4802,6 +4802,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, bool Dependent = CurContext->isDependentContext() && (BaseType->isDependentType() || Init->isTypeDependent()); + llvm::errs() << "Dependent? " << Dependent << '\n'; SourceRange InitRange = Init->getSourceRange(); if (EllipsisLoc.isValid()) { // This is a pack expansion. @@ -4828,28 +4829,51 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, const CXXBaseSpecifier *DirectBaseSpec = nullptr; const CXXBaseSpecifier *VirtualBaseSpec = nullptr; - FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, - VirtualBaseSpec); - - // C++ [base.class.init]p2: - // Unless the mem-initializer-id names a nonstatic data member of the - // constructor's class or a direct or virtual base of that class, the - // mem-initializer is ill-formed. - if (!DirectBaseSpec && !VirtualBaseSpec) { - // If the class has any dependent bases, then it's possible that one of - // those types will resolve to the same type as BaseType. Therefore, just - // treat this as a dependent base class initialization. - // FIXME: Should we try to check the initialization anyway? It seems odd. - if (ClassDecl->hasAnyDependentBases()) - Dependent = true; - // We may have a delegating initializer here but in a dependent context. - // Since that is also a type, that isn't a direct or virtual base of the - // instantiated type. That will be handled later. - else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl())) - return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) - << BaseType << Context.getCanonicalTagType(ClassDecl) - << BaseTInfo->getTypeLoc().getSourceRange(); - } + FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, + VirtualBaseSpec); + + // C++ [base.class.init]p2: + // Unless the mem-initializer-id names a nonstatic data member of the + // constructor's class or a direct or virtual base of that class, the + // mem-initializer is ill-formed. + if (!DirectBaseSpec && !VirtualBaseSpec) { + // If the class has any dependent bases, then it's possible that one of + // those types will resolve to the same type as BaseType. Therefore, just + // treat this as a dependent base class initialization. + // FIXME: Should we try to check the initialization anyway? It seems odd. + if (ClassDecl->hasAnyDependentBases()) + Dependent = true; + // We may have a delegating initializer here but in a dependent context. + // Since that is also a type, that isn't a direct or virtual base of the + // instantiated type. That will be handled later. + // + // Another scenario we may get here is when the initialization list contains + // a type template parameter. If the class has any bases classes, the program can be valid, but if not, then the program must be invalid. + // For example, the following case must be invalid, no matter how we choose the type of the template at initialization: + // + // struct S0 { + // S0(int) {} + // template <class T> + // S0(T) : T(42), Member(42) {}; + // int Member{21}; + // }; + // + // This code can be valid, if we choose `SomeBase` as our template argument: + // + // class SomeBase {}; + // + // struct S0 : SomeBase { + // S0(int) {} + // template <class T> + // S0(T) : Member(42), T(42) {}; + // int Member{21}; + // }; + else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl()) && + ClassDecl->bases().empty()) + return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) + << BaseType << Context.getCanonicalTagType(ClassDecl) + << BaseTInfo->getTypeLoc().getSourceRange(); + } if (Dependent) { DiscardCleanupsInEvaluationContext(); From f6d280c123045254d8fd7a95fe471c9cffc134de Mon Sep 17 00:00:00 2001 From: Gabor Spaits <[email protected]> Date: Wed, 24 Jun 2026 11:31:26 +0200 Subject: [PATCH 6/7] Remove unnecessary include --- clang/lib/Sema/SemaDeclCXX.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 3e62fe3d30631..578ae9506db3c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -17,7 +17,6 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ComparisonCategories.h" -#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DynamicRecursiveASTVisitor.h" From 14b2e163bdc1be5d5c15babc5768a40d14915067 Mon Sep 17 00:00:00 2001 From: Gabor Spaits <[email protected]> Date: Wed, 24 Jun 2026 11:36:29 +0200 Subject: [PATCH 7/7] Yeah the debug print shouldnt really stay in the pr --- clang/lib/Sema/SemaDeclCXX.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 578ae9506db3c..26d247013c682 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4801,7 +4801,6 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, bool Dependent = CurContext->isDependentContext() && (BaseType->isDependentType() || Init->isTypeDependent()); - llvm::errs() << "Dependent? " << Dependent << '\n'; SourceRange InitRange = Init->getSourceRange(); if (EllipsisLoc.isValid()) { // This is a pack expansion. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
