Skip to content

Commit

Permalink
[Clang] Implements CTAD for aggregates P1816R0 and P2082R1
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D139837
  • Loading branch information
Yuanfang Chen committed Jun 29, 2023
1 parent b287a4c commit 632dd6a
Show file tree
Hide file tree
Showing 20 changed files with 845 additions and 193 deletions.
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Expand Up @@ -112,6 +112,8 @@ C++20 Feature Support
- Clang now supports `requires cplusplus20` for module maps.
- Implemented missing parts of `P2002R1: Consistent comparison operators <https://wg21.link/P2002R1>`_
- Clang now defines `__cpp_consteval` macro.
- Implemented `P1816R0: <https://wg21.link/p1816r0>`_ and `P2082R1: <https://wg21.link/p2082r1>`_,
which allows CTAD for aggregates.

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
Expand Down
19 changes: 13 additions & 6 deletions clang/include/clang/AST/DeclBase.h
Expand Up @@ -1382,6 +1382,13 @@ class DeclContextLookupResult {
}
};

/// Only used by CXXDeductionGuideDecl.
enum class DeductionCandidate : unsigned char {
Normal,
Copy,
Aggregate,
};

/// DeclContext - This is used only as base class of specific decl types that
/// can act as declaration contexts. These decls are (only the top classes
/// that directly derive from DeclContext are mentioned, not their subclasses):
Expand Down Expand Up @@ -1620,10 +1627,10 @@ class DeclContext {
/// Stores the bits used by FunctionDecl.
/// If modified NumFunctionDeclBits and the accessor
/// methods in FunctionDecl and CXXDeductionGuideDecl
/// (for IsCopyDeductionCandidate) should be updated appropriately.
/// (for DeductionCandidateKind) should be updated appropriately.
class FunctionDeclBitfields {
friend class FunctionDecl;
/// For IsCopyDeductionCandidate
/// For DeductionCandidateKind
friend class CXXDeductionGuideDecl;
/// For the bits in DeclContextBitfields.
uint64_t : NumDeclContextBits;
Expand Down Expand Up @@ -1678,10 +1685,10 @@ class DeclContext {
/// function using attribute 'target'.
uint64_t IsMultiVersion : 1;

/// [C++17] Only used by CXXDeductionGuideDecl. Indicates that
/// the Deduction Guide is the implicitly generated 'copy
/// deduction candidate' (is used during overload resolution).
uint64_t IsCopyDeductionCandidate : 1;
/// Only used by CXXDeductionGuideDecl. Indicates the kind
/// of the Deduction Guide that is implicitly generated
/// (used during overload resolution).
uint64_t DeductionCandidateKind : 2;

/// Store the ODRHash after first calculation.
uint64_t HasODRHash : 1;
Expand Down
20 changes: 10 additions & 10 deletions clang/include/clang/AST/DeclCXX.h
Expand Up @@ -1942,13 +1942,13 @@ class CXXDeductionGuideDecl : public FunctionDecl {
ExplicitSpecifier ES,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation,
CXXConstructorDecl *Ctor)
CXXConstructorDecl *Ctor, DeductionCandidate Kind)
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
SC_None, false, false, ConstexprSpecKind::Unspecified),
Ctor(Ctor), ExplicitSpec(ES) {
if (EndLocation.isValid())
setRangeEnd(EndLocation);
setIsCopyDeductionCandidate(false);
setDeductionCandidateKind(Kind);
}

CXXConstructorDecl *Ctor;
Expand All @@ -1963,7 +1963,8 @@ class CXXDeductionGuideDecl : public FunctionDecl {
Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation,
CXXConstructorDecl *Ctor = nullptr);
CXXConstructorDecl *Ctor = nullptr,
DeductionCandidate Kind = DeductionCandidate::Normal);

static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);

Expand All @@ -1980,16 +1981,15 @@ class CXXDeductionGuideDecl : public FunctionDecl {

/// Get the constructor from which this deduction guide was generated, if
/// this is an implicit deduction guide.
CXXConstructorDecl *getCorrespondingConstructor() const {
return Ctor;
}
CXXConstructorDecl *getCorrespondingConstructor() const { return Ctor; }

void setIsCopyDeductionCandidate(bool isCDC = true) {
FunctionDeclBits.IsCopyDeductionCandidate = isCDC;
void setDeductionCandidateKind(DeductionCandidate K) {
FunctionDeclBits.DeductionCandidateKind = static_cast<unsigned char>(K);
}

bool isCopyDeductionCandidate() const {
return FunctionDeclBits.IsCopyDeductionCandidate;
DeductionCandidate getDeductionCandidateKind() const {
return static_cast<DeductionCandidate>(
FunctionDeclBits.DeductionCandidateKind);
}

// Implement isa/cast/dyncast/etc.
Expand Down
28 changes: 23 additions & 5 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -3996,7 +3996,8 @@ class Sema final {
bool AllowExplicitConversion = false,
ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
ConversionSequenceList EarlyConversions = std::nullopt,
OverloadCandidateParamOrder PO = {});
OverloadCandidateParamOrder PO = {},
bool AggregateCandidateDeduction = false);
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
Expand Down Expand Up @@ -4037,7 +4038,8 @@ class Sema final {
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,
bool PartialOverloading = false, bool AllowExplicit = true,
ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
OverloadCandidateParamOrder PO = {});
OverloadCandidateParamOrder PO = {},
bool AggregateCandidateDeduction = false);
bool CheckNonDependentConversions(
FunctionTemplateDecl *FunctionTemplate, ArrayRef<QualType> ParamTypes,
ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet,
Expand Down Expand Up @@ -9112,7 +9114,7 @@ class Sema final {
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info,
bool PartialOverloading,
bool PartialOverloading, bool AggregateDeductionCandidate,
llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent);

TemplateDeductionResult
Expand Down Expand Up @@ -9172,10 +9174,16 @@ class Sema final {
/// not already done so.
void DeclareImplicitDeductionGuides(TemplateDecl *Template,
SourceLocation Loc);
FunctionTemplateDecl *DeclareImplicitDeductionGuideFromInitList(
TemplateDecl *Template, MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc);
llvm::DenseMap<unsigned, CXXDeductionGuideDecl *>
AggregateDeductionCandidates;

QualType DeduceTemplateSpecializationFromInitializer(
TypeSourceInfo *TInfo, const InitializedEntity &Entity,
const InitializationKind &Kind, MultiExprArg Init);
const InitializationKind &Kind, MultiExprArg Init,
ParenListExpr *PL = nullptr);

QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name,
QualType Type, TypeSourceInfo *TSI,
Expand Down Expand Up @@ -9355,7 +9363,10 @@ class Sema final {
/// Memoization means we are _not_ instantiating a template because
/// it is already instantiated (but we entered a context where we
/// would have had to if it was not already instantiated).
Memoization
Memoization,

/// We are building deduction guides for a class.
BuildingDeductionGuides,
} Kind;

/// Was the enclosing context a non-instantiation SFINAE context?
Expand Down Expand Up @@ -9668,6 +9679,13 @@ class Sema final {
const RequiresExpr *E,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange);

struct BuildingDeductionGuidesTag {};
/// \brief Note that we are building deduction guides.
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
TemplateDecl *Entity, BuildingDeductionGuidesTag,
SourceRange InstantiationRange = SourceRange());

/// Note that we have finished instantiating this template.
void Clear();

Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Sema/TemplateDeduction.h
Expand Up @@ -234,6 +234,13 @@ class TemplateDeductionInfo {
/// different argument type from its substituted parameter type.
unsigned CallArgIndex = 0;

// C++20 [over.match.class.deduct]p5.2:
// During template argument deduction for the aggregate deduction
// candidate, the number of elements in a trailing parameter pack is only
// deduced from the number of remaining function arguments if it is not
// otherwise deduced.
bool AggregateDeductionCandidateHasMismatchedArity = false;

/// Information on packs that we're currently expanding.
///
/// FIXME: This should be kept internal to SemaTemplateDeduction.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ASTImporter.cpp
Expand Up @@ -3699,7 +3699,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
NameInfo, T, TInfo, ToEndLoc, Ctor))
return ToFunction;
cast<CXXDeductionGuideDecl>(ToFunction)
->setIsCopyDeductionCandidate(Guide->isCopyDeductionCandidate());
->setDeductionCandidateKind(Guide->getDeductionCandidateKind());
} else {
if (GetImportedOrCreateDecl(
ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart,
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Decl.cpp
Expand Up @@ -3009,7 +3009,8 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.HasSkippedBody = false;
FunctionDeclBits.WillHaveBody = false;
FunctionDeclBits.IsMultiVersion = false;
FunctionDeclBits.IsCopyDeductionCandidate = false;
FunctionDeclBits.DeductionCandidateKind =
static_cast<unsigned char>(DeductionCandidate::Normal);
FunctionDeclBits.HasODRHash = false;
FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate = false;
if (TrailingRequiresClause)
Expand Down
16 changes: 8 additions & 8 deletions clang/lib/AST/DeclCXX.cpp
Expand Up @@ -2112,21 +2112,21 @@ ExplicitSpecifier ExplicitSpecifier::getFromDecl(FunctionDecl *Function) {
}
}

CXXDeductionGuideDecl *
CXXDeductionGuideDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, ExplicitSpecifier ES,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation,
CXXConstructorDecl *Ctor) {
CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor,
DeductionCandidate Kind) {
return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T,
TInfo, EndLocation, Ctor);
TInfo, EndLocation, Ctor, Kind);
}

CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
return new (C, ID) CXXDeductionGuideDecl(
C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(),
QualType(), nullptr, SourceLocation(), nullptr);
QualType(), nullptr, SourceLocation(), nullptr,
DeductionCandidate::Normal);
}

RequiresExprBodyDecl *RequiresExprBodyDecl::Create(
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Frontend/FrontendActions.cpp
Expand Up @@ -412,6 +412,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
return "MarkingClassDllexported";
case CodeSynthesisContext::BuildingBuiltinDumpStructCall:
return "BuildingBuiltinDumpStructCall";
case CodeSynthesisContext::BuildingDeductionGuides:
return "BuildingDeductionGuides";
}
return "";
}
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Sema/SemaDecl.cpp
Expand Up @@ -12700,10 +12700,9 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
if (Init)
DeduceInits = Init;

if (DirectInit) {
if (auto *PL = dyn_cast_or_null<ParenListExpr>(Init))
DeduceInits = PL->exprs();
}
auto *PL = dyn_cast_if_present<ParenListExpr>(Init);
if (DirectInit && PL)
DeduceInits = PL->exprs();

if (isa<DeducedTemplateSpecializationType>(Deduced)) {
assert(VDecl && "non-auto type for init capture deduction?");
Expand All @@ -12713,7 +12712,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
// FIXME: Initialization should not be taking a mutable list of inits.
SmallVector<Expr*, 8> InitsCopy(DeduceInits.begin(), DeduceInits.end());
return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind,
InitsCopy);
InitsCopy, PL);
}

if (DirectInit) {
Expand Down

0 comments on commit 632dd6a

Please sign in to comment.