Skip to content

Commit 1ed4033

Browse files
committed
Prevent dependent code generation when substituting constraints
1 parent d40a808 commit 1ed4033

File tree

5 files changed

+60
-12
lines changed

5 files changed

+60
-12
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13181,6 +13181,10 @@ class Sema final : public SemaBase {
1318113181
// FIXME: Should we have a similar limit for other forms of synthesis?
1318213182
unsigned NonInstantiationEntries;
1318313183

13184+
/// The number of \p CodeSynthesisContexts that are not constraint
13185+
/// substitution.
13186+
unsigned NonConstraintSubstitutionEntries;
13187+
1318413188
/// The depth of the context stack at the point when the most recent
1318513189
/// error or warning was produced.
1318613190
///
@@ -13503,6 +13507,11 @@ class Sema final : public SemaBase {
1350313507
return CodeSynthesisContexts.size() > NonInstantiationEntries;
1350413508
}
1350513509

13510+
/// Determine whether we are currently performing constraint substitution.
13511+
bool inConstraintSubstitution() const {
13512+
return CodeSynthesisContexts.size() > NonConstraintSubstitutionEntries;
13513+
}
13514+
1350613515
using EntityPrinter = llvm::function_ref<void(llvm::raw_ostream &)>;
1350713516

1350813517
/// \brief create a Requirement::SubstitutionDiagnostic with only a

clang/lib/Sema/Sema.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
263263
TyposCorrected(0), IsBuildingRecoveryCallExpr(false), NumSFINAEErrors(0),
264264
AccessCheckingSFINAE(false), CurrentInstantiationScope(nullptr),
265265
InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
266-
ArgumentPackSubstitutionIndex(-1), SatisfactionCache(Context) {
266+
NonConstraintSubstitutionEntries(0), ArgumentPackSubstitutionIndex(-1),
267+
SatisfactionCache(Context) {
267268
assert(pp.TUKind == TUKind);
268269
TUScope = nullptr;
269270

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,9 @@ void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
828828
if (!Ctx.isInstantiationRecord())
829829
++NonInstantiationEntries;
830830

831+
if (Ctx.Kind != CodeSynthesisContext::ConstraintSubstitution)
832+
++NonConstraintSubstitutionEntries;
833+
831834
// Check to see if we're low on stack space. We can't do anything about this
832835
// from here, but we can at least warn the user.
833836
StackHandler.warnOnStackNearlyExhausted(Ctx.PointOfInstantiation);
@@ -840,6 +843,11 @@ void Sema::popCodeSynthesisContext() {
840843
--NonInstantiationEntries;
841844
}
842845

846+
if (Active.Kind != CodeSynthesisContext::ConstraintSubstitution) {
847+
assert(NonConstraintSubstitutionEntries > 0);
848+
--NonConstraintSubstitutionEntries;
849+
}
850+
843851
InNonInstantiationSFINAEContext = Active.SavedInNonInstantiationSFINAEContext;
844852

845853
// Name lookup no longer looks in this template's defining module.
@@ -1363,13 +1371,6 @@ namespace {
13631371
bool BailOutOnIncomplete;
13641372

13651373
private:
1366-
bool isSubstitutingConstraints() const {
1367-
return llvm::any_of(SemaRef.CodeSynthesisContexts, [](auto &Context) {
1368-
return Context.Kind ==
1369-
Sema::CodeSynthesisContext::ConstraintSubstitution;
1370-
});
1371-
}
1372-
13731374
// CWG2770: Function parameters should be instantiated when they are
13741375
// needed by a satisfaction check of an atomic constraint or
13751376
// (recursively) by another function parameter.
@@ -1431,7 +1432,8 @@ namespace {
14311432
ArrayRef<UnexpandedParameterPack> Unexpanded,
14321433
bool &ShouldExpand, bool &RetainExpansion,
14331434
std::optional<unsigned> &NumExpansions) {
1434-
if (SemaRef.CurrentInstantiationScope && isSubstitutingConstraints()) {
1435+
if (SemaRef.CurrentInstantiationScope &&
1436+
SemaRef.inConstraintSubstitution()) {
14351437
for (UnexpandedParameterPack ParmPack : Unexpanded) {
14361438
NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
14371439
if (!isa_and_present<ParmVarDecl>(VD))
@@ -1945,7 +1947,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
19451947
}
19461948

19471949
if (SemaRef.CurrentInstantiationScope) {
1948-
if (isSubstitutingConstraints() && isa<ParmVarDecl>(D) &&
1950+
if (SemaRef.inConstraintSubstitution() && isa<ParmVarDecl>(D) &&
19491951
maybeInstantiateFunctionParameterToScope(cast<ParmVarDecl>(D)))
19501952
return nullptr;
19511953
}

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "TreeTransform.h"
1313
#include "clang/AST/ASTConsumer.h"
1414
#include "clang/AST/ASTContext.h"
15+
#include "clang/AST/ASTLambda.h"
1516
#include "clang/AST/ASTMutationListener.h"
1617
#include "clang/AST/DeclTemplate.h"
1718
#include "clang/AST/DependentDiagnostic.h"
@@ -5284,8 +5285,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
52845285
savedContext.pop();
52855286
}
52865287

5287-
DeclGroupRef DG(Function);
5288-
Consumer.HandleTopLevelDecl(DG);
5288+
// With CWG2369, we substitute constraints before instantiating the associated
5289+
// function template. This helps prevent potential code generation for
5290+
// dependent types, particularly under the MS ABI.
5291+
if (!inConstraintSubstitution() ||
5292+
!getLambdaAwareParentOfDeclContext(Function)->isDependentContext()) {
5293+
DeclGroupRef DG(Function);
5294+
Consumer.HandleTopLevelDecl(DG);
5295+
}
52895296

52905297
// This class may have local implicit instantiations that need to be
52915298
// instantiation within this scope.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -std=c++20 -triple=x86_64-windows-msvc -Wno-defaulted-function-deleted -fms-compatibility -fms-extensions -emit-llvm %s -o - | FileCheck %s
2+
3+
namespace CWG2369_Regression {
4+
5+
template <class, class Up>
6+
using compare_three_way_result_t = Up::type;
7+
8+
struct sfinae_assign_base {};
9+
10+
template <class Tp>
11+
concept is_derived_from_optional =
12+
requires(Tp param) { []<class Up>(Up) {}(param); };
13+
14+
template <class Tp, class Up>
15+
requires(is_derived_from_optional<Up>)
16+
compare_three_way_result_t<Tp, Up> operator<=>(Tp, Up);
17+
18+
struct RuntimeModeArgs {
19+
auto operator<=>(const RuntimeModeArgs &) const = default;
20+
sfinae_assign_base needs_admin;
21+
};
22+
23+
RuntimeModeArgs foo() {
24+
return {};
25+
}
26+
27+
// CHECK: ?foo@CWG2369_Regression@@YA?AURuntimeModeArgs@1@XZ
28+
29+
}

0 commit comments

Comments
 (0)