Skip to content

Commit

Permalink
[clang] Implement CWG2398 provisional TTP matching to class templates
Browse files Browse the repository at this point in the history
This extends default argument deduction to cover class templates as
well.

This solves some ambuguity introduced in P0522 regarding how
template template parameters are partially ordered, and should reduce
the negative impact of enabling `-frelaxed-template-template-args`
by default.

Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;

template <template <class T4> class TT1, class T5> struct B<TT1<T5>>;   // #1
template <class T6, class T7>                      struct B<A<T6, T7>>; // #2

template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous.
This patch restores the pre-P0522 behavior, `#2` is picked again.
  • Loading branch information
mizvekov committed Aug 20, 2024
1 parent 14b0812 commit 3f95419
Show file tree
Hide file tree
Showing 26 changed files with 773 additions and 382 deletions.
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/DumpAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
TEMPLATE_KIND(SubstTemplateTemplateParm);
TEMPLATE_KIND(SubstTemplateTemplateParmPack);
TEMPLATE_KIND(UsingTemplate);
TEMPLATE_KIND(DeducedTemplate);
#undef TEMPLATE_KIND
}
llvm_unreachable("Unhandled NameKind enum");
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/SemanticHighlighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,7 @@ class CollectExtraHighlightings
case TemplateName::SubstTemplateTemplateParm:
case TemplateName::SubstTemplateTemplateParmPack:
case TemplateName::UsingTemplate:
case TemplateName::DeducedTemplate:
// Names that could be resolved to a TemplateDecl are handled elsewhere.
break;
}
Expand Down
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ Resolutions to C++ Defect Reports
of the target type, even if the type of the bit-field is larger.
(`CWG2627: Bit-fields and narrowing conversions <https://cplusplus.github.io/CWG/issues/2627.html>`_)

- Clang now has improved resolution to CWG2398, allowing class templates to have
default arguments deduced when partial ordering.

C Language Changes
------------------

Expand Down
11 changes: 9 additions & 2 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
ASTContext&>
SubstTemplateTemplateParmPacks;
mutable llvm::ContextualFoldingSet<DeducedTemplateStorage, ASTContext &>
DeducedTemplates;

mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
ArrayParameterTypes;
Expand Down Expand Up @@ -2291,6 +2293,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
unsigned Index,
bool Final) const;

TemplateName getDeducedTemplateName(TemplateName Underlying,
DefaultArguments DefaultArgs) const;

enum GetBuiltinTypeError {
/// No error
GE_None,
Expand Down Expand Up @@ -2774,11 +2779,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// template name uses the shortest form of the dependent
/// nested-name-specifier, which itself contains all canonical
/// types, values, and templates.
TemplateName getCanonicalTemplateName(const TemplateName &Name) const;
TemplateName getCanonicalTemplateName(TemplateName Name,
bool IgnoreDeduced = false) const;

/// Determine whether the given template names refer to the same
/// template.
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y,
bool IgnoreDeduced = false) const;

/// Determine whether the two declarations refer to the same entity.
bool isSameEntity(const NamedDecl *X, const NamedDecl *Y) const;
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/AST/ASTImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,11 @@ class TypeSourceInfo;
/// the declarations it contains.
[[nodiscard]] llvm::Error ImportDefinition(Decl *From);

llvm::Error
ImportTemplateArguments(ArrayRef<TemplateArgument> FromArgs,
SmallVectorImpl<TemplateArgument> &ToArgs);
Expected<TemplateArgument> Import(const TemplateArgument &From);

/// Cope with a name conflict when importing a declaration into the
/// given context.
///
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/AST/DependenceFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,11 @@ toTemplateNameDependence(NestedNameSpecifierDependence D) {
return Dependence(D).templateName();
}

inline TemplateNameDependence
toTemplateNameDependence(TemplateArgumentDependence D) {
return Dependence(D).templateName();
}

LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();

} // namespace clang
Expand Down
17 changes: 17 additions & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,23 @@ let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParmPack"> in {
return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index, final);
}]>;
}
let Class = PropertyTypeCase<TemplateName, "DeducedTemplate"> in {
def : ReadHelper<[{
auto DTS = node.getAsDeducedTemplateName();
}]>;
def : Property<"underlying", TemplateName> {
let Read = [{ DTS->getUnderlying() }];
}
def : Property<"startPos", UInt32> {
let Read = [{ DTS->getDefaultArguments().StartPos }];
}
def : Property<"defaultArgs", Array<TemplateArgument>> {
let Read = [{ DTS->getDefaultArguments().Args }];
}
def : Creator<[{
return ctx.getDeducedTemplateName(underlying, {startPos, defaultArgs});
}]>;
}

// Type cases for TemplateArgument.
def : PropertyTypeKind<TemplateArgument, TemplateArgumentKind,
Expand Down
63 changes: 60 additions & 3 deletions clang/include/clang/AST/TemplateName.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class NestedNameSpecifier;
enum OverloadedOperatorKind : int;
class OverloadedTemplateStorage;
class AssumedTemplateStorage;
class DeducedTemplateStorage;
struct PrintingPolicy;
class QualifiedTemplateName;
class SubstTemplateTemplateParmPackStorage;
Expand All @@ -50,16 +51,17 @@ class UncommonTemplateNameStorage {
enum Kind {
Overloaded,
Assumed, // defined in DeclarationName.h
Deduced,
SubstTemplateTemplateParm,
SubstTemplateTemplateParmPack
};

struct BitsTag {
LLVM_PREFERRED_TYPE(Kind)
unsigned Kind : 2;
unsigned Kind : 3;

// The template parameter index.
unsigned Index : 15;
unsigned Index : 14;

/// The pack index, or the number of stored templates
/// or template arguments, depending on which subclass we have.
Expand Down Expand Up @@ -90,6 +92,12 @@ class UncommonTemplateNameStorage {
: nullptr;
}

DeducedTemplateStorage *getAsDeducedTemplateName() {
return Bits.Kind == Deduced
? reinterpret_cast<DeducedTemplateStorage *>(this)
: nullptr;
}

SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() {
return Bits.Kind == SubstTemplateTemplateParm
? reinterpret_cast<SubstTemplateTemplateParmStorage *>(this)
Expand Down Expand Up @@ -172,6 +180,15 @@ class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage,
unsigned Index, bool Final);
};

struct DefaultArguments {
// The position in the template parameter list
// the first argument corresponds to.
unsigned StartPos;
ArrayRef<TemplateArgument> Args;

operator bool() const { return !Args.empty(); }
};

/// Represents a C++ template name within the type system.
///
/// A C++ template name refers to a template within the C++ type
Expand Down Expand Up @@ -246,6 +263,10 @@ class TemplateName {
/// A template name that refers to a template declaration found through a
/// specific using shadow declaration.
UsingTemplate,

/// A template name that refers to another TemplateName with deduced default
/// arguments.
DeducedTemplate,
};

TemplateName() = default;
Expand All @@ -257,6 +278,7 @@ class TemplateName {
explicit TemplateName(QualifiedTemplateName *Qual);
explicit TemplateName(DependentTemplateName *Dep);
explicit TemplateName(UsingShadowDecl *Using);
explicit TemplateName(DeducedTemplateStorage *Deduced);

/// Determine whether this template name is NULL.
bool isNull() const;
Expand All @@ -271,7 +293,13 @@ class TemplateName {
/// to, if any. If the template name does not refer to a specific
/// declaration because it is a dependent name, or if it refers to a
/// set of function templates, returns NULL.
TemplateDecl *getAsTemplateDecl() const;
TemplateDecl *getAsTemplateDecl(bool IgnoreDeduced = false) const;

/// Retrieves the underlying template declaration that
/// this template name refers to, along with the
/// deduced default arguments, if any.
std::pair<TemplateDecl *, DefaultArguments>
getTemplateDeclAndDefaultArgs() const;

/// Retrieve the underlying, overloaded function template
/// declarations that this template name refers to, if known.
Expand Down Expand Up @@ -313,6 +341,11 @@ class TemplateName {
/// template declaration is introduced, if any.
UsingShadowDecl *getAsUsingShadowDecl() const;

/// Retrieve the deduced template info, if any.
DeducedTemplateStorage *getAsDeducedTemplateName() const;

std::optional<TemplateName> desugar(bool IgnoreDeduced) const;

TemplateName getUnderlying() const;

TemplateNameDependence getDependence() const;
Expand Down Expand Up @@ -412,6 +445,30 @@ class SubstTemplateTemplateParmStorage
std::optional<unsigned> PackIndex);
};

class DeducedTemplateStorage : public UncommonTemplateNameStorage,
public llvm::FoldingSetNode {
friend class ASTContext;

TemplateName Underlying;

DeducedTemplateStorage(TemplateName Underlying,
const DefaultArguments &DefArgs);

public:
TemplateName getUnderlying() const { return Underlying; }

DefaultArguments getDefaultArguments() const {
return {/*StartPos=*/Bits.Index,
/*Args=*/{reinterpret_cast<const TemplateArgument *>(this + 1),
Bits.Data}};
}

void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;

static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
TemplateName Underlying, const DefaultArguments &DefArgs);
};

inline TemplateName TemplateName::getUnderlying() const {
if (SubstTemplateTemplateParmStorage *subst
= getAsSubstTemplateTemplateParm())
Expand Down
10 changes: 7 additions & 3 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -11725,6 +11725,9 @@ class Sema final : public SemaBase {
/// receive true if the cause for the error is the associated constraints of
/// the template not being satisfied by the template arguments.
///
/// \param DefaultArgs any default arguments from template specialization
/// deduction.
///
/// \param PartialOrderingTTP If true, assume these template arguments are
/// the injected template arguments for a template template parameter.
/// This will relax the requirement that all its possible uses are valid:
Expand All @@ -11734,7 +11737,8 @@ class Sema final : public SemaBase {
/// \returns true if an error occurred, false otherwise.
bool CheckTemplateArgumentList(
TemplateDecl *Template, SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
TemplateArgumentListInfo &TemplateArgs,
const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
bool UpdateArgsWithConversions = true,
Expand Down Expand Up @@ -12471,8 +12475,8 @@ class Sema final : public SemaBase {
sema::TemplateDeductionInfo &Info);

bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc,
bool IsDeduced);
TemplateParameterList *PParam, TemplateDecl *AArg,
const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced);

/// Mark which template parameters are used in a given expression.
///
Expand Down
Loading

0 comments on commit 3f95419

Please sign in to comment.