Skip to content

Commit

Permalink
Prevent dependent code generation when substituting constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
zyn0217 committed Jan 11, 2025
1 parent d40a808 commit 1ed4033
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 12 deletions.
9 changes: 9 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -13181,6 +13181,10 @@ class Sema final : public SemaBase {
// FIXME: Should we have a similar limit for other forms of synthesis?
unsigned NonInstantiationEntries;

/// The number of \p CodeSynthesisContexts that are not constraint
/// substitution.
unsigned NonConstraintSubstitutionEntries;

/// The depth of the context stack at the point when the most recent
/// error or warning was produced.
///
Expand Down Expand Up @@ -13503,6 +13507,11 @@ class Sema final : public SemaBase {
return CodeSynthesisContexts.size() > NonInstantiationEntries;
}

/// Determine whether we are currently performing constraint substitution.
bool inConstraintSubstitution() const {
return CodeSynthesisContexts.size() > NonConstraintSubstitutionEntries;
}

using EntityPrinter = llvm::function_ref<void(llvm::raw_ostream &)>;

/// \brief create a Requirement::SubstitutionDiagnostic with only a
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TyposCorrected(0), IsBuildingRecoveryCallExpr(false), NumSFINAEErrors(0),
AccessCheckingSFINAE(false), CurrentInstantiationScope(nullptr),
InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
ArgumentPackSubstitutionIndex(-1), SatisfactionCache(Context) {
NonConstraintSubstitutionEntries(0), ArgumentPackSubstitutionIndex(-1),
SatisfactionCache(Context) {
assert(pp.TUKind == TUKind);
TUScope = nullptr;

Expand Down
20 changes: 11 additions & 9 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,9 @@ void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
if (!Ctx.isInstantiationRecord())
++NonInstantiationEntries;

if (Ctx.Kind != CodeSynthesisContext::ConstraintSubstitution)
++NonConstraintSubstitutionEntries;

// Check to see if we're low on stack space. We can't do anything about this
// from here, but we can at least warn the user.
StackHandler.warnOnStackNearlyExhausted(Ctx.PointOfInstantiation);
Expand All @@ -840,6 +843,11 @@ void Sema::popCodeSynthesisContext() {
--NonInstantiationEntries;
}

if (Active.Kind != CodeSynthesisContext::ConstraintSubstitution) {
assert(NonConstraintSubstitutionEntries > 0);
--NonConstraintSubstitutionEntries;
}

InNonInstantiationSFINAEContext = Active.SavedInNonInstantiationSFINAEContext;

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

private:
bool isSubstitutingConstraints() const {
return llvm::any_of(SemaRef.CodeSynthesisContexts, [](auto &Context) {
return Context.Kind ==
Sema::CodeSynthesisContext::ConstraintSubstitution;
});
}

// CWG2770: Function parameters should be instantiated when they are
// needed by a satisfaction check of an atomic constraint or
// (recursively) by another function parameter.
Expand Down Expand Up @@ -1431,7 +1432,8 @@ namespace {
ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand, bool &RetainExpansion,
std::optional<unsigned> &NumExpansions) {
if (SemaRef.CurrentInstantiationScope && isSubstitutingConstraints()) {
if (SemaRef.CurrentInstantiationScope &&
SemaRef.inConstraintSubstitution()) {
for (UnexpandedParameterPack ParmPack : Unexpanded) {
NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
if (!isa_and_present<ParmVarDecl>(VD))
Expand Down Expand Up @@ -1945,7 +1947,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
}

if (SemaRef.CurrentInstantiationScope) {
if (isSubstitutingConstraints() && isa<ParmVarDecl>(D) &&
if (SemaRef.inConstraintSubstitution() && isa<ParmVarDecl>(D) &&
maybeInstantiateFunctionParameterToScope(cast<ParmVarDecl>(D)))
return nullptr;
}
Expand Down
11 changes: 9 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DependentDiagnostic.h"
Expand Down Expand Up @@ -5284,8 +5285,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
savedContext.pop();
}

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

// This class may have local implicit instantiations that need to be
// instantiation within this scope.
Expand Down
29 changes: 29 additions & 0 deletions clang/test/CodeGenCXX/ms-mangle-requires.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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

namespace CWG2369_Regression {

template <class, class Up>
using compare_three_way_result_t = Up::type;

struct sfinae_assign_base {};

template <class Tp>
concept is_derived_from_optional =
requires(Tp param) { []<class Up>(Up) {}(param); };

template <class Tp, class Up>
requires(is_derived_from_optional<Up>)
compare_three_way_result_t<Tp, Up> operator<=>(Tp, Up);

struct RuntimeModeArgs {
auto operator<=>(const RuntimeModeArgs &) const = default;
sfinae_assign_base needs_admin;
};

RuntimeModeArgs foo() {
return {};
}

// CHECK: ?foo@CWG2369_Regression@@YA?AURuntimeModeArgs@1@XZ

}

0 comments on commit 1ed4033

Please sign in to comment.