diff --git a/include/mrdocs/Metadata/Template.hpp b/include/mrdocs/Metadata/Template.hpp index 79d3c7191..74e628b5b 100644 --- a/include/mrdocs/Metadata/Template.hpp +++ b/include/mrdocs/Metadata/Template.hpp @@ -207,6 +207,9 @@ struct TypeTParam { /** Keyword (class/typename) the parameter uses */ TParamKeyKind KeyKind = TParamKeyKind::Class; + + /** The type-constraint for the parameter, if any. */ + std::unique_ptr Constraint; }; struct NonTypeTParam diff --git a/include/mrdocs/Metadata/Type.hpp b/include/mrdocs/Metadata/Type.hpp index 5d87eabec..b73c4ef2e 100644 --- a/include/mrdocs/Metadata/Type.hpp +++ b/include/mrdocs/Metadata/Type.hpp @@ -26,7 +26,7 @@ namespace clang { namespace mrdocs { -enum QualifierKind : int +enum QualifierKind { None, Const, @@ -39,6 +39,7 @@ enum class TypeKind { Named = 1, // for bitstream Decltype, + Auto, LValueReference, RValueReference, Pointer, @@ -49,6 +50,14 @@ enum class TypeKind MRDOCS_DECL dom::String toString(TypeKind kind) noexcept; +enum class AutoKind +{ + Auto, + DecltypeAuto +}; + +MRDOCS_DECL dom::String toString(AutoKind kind) noexcept; + struct TypeInfo { /** The kind of TypeInfo this is @@ -63,6 +72,7 @@ struct TypeInfo constexpr bool isNamed() const noexcept { return Kind == TypeKind::Named; } constexpr bool isDecltype() const noexcept { return Kind == TypeKind::Decltype; } + constexpr bool isAuto() const noexcept { return Kind == TypeKind::Auto; } constexpr bool isLValueReference() const noexcept { return Kind == TypeKind::LValueReference; } constexpr bool isRValueReference() const noexcept { return Kind == TypeKind::RValueReference; } constexpr bool isPointer() const noexcept { return Kind == TypeKind::Pointer; } @@ -100,6 +110,7 @@ struct IsType : TypeInfo static constexpr bool isNamed() noexcept { return K == TypeKind::Named; } static constexpr bool isDecltype() noexcept { return K == TypeKind::Decltype; } + static constexpr bool isAuto() noexcept { return K == TypeKind::Auto; } static constexpr bool isLValueReference() noexcept { return K == TypeKind::LValueReference; } static constexpr bool isRValueReference() noexcept { return K == TypeKind::RValueReference; } static constexpr bool isPointer() noexcept { return K == TypeKind::Pointer; } @@ -129,6 +140,14 @@ struct DecltypeTypeInfo ExprInfo Operand; }; +struct AutoTypeInfo + : IsType +{ + QualifierKind CVQualifiers = QualifierKind::None; + AutoKind Keyword = AutoKind::Auto; + std::unique_ptr Constraint; +}; + struct LValueReferenceTypeInfo : IsType { @@ -226,6 +245,10 @@ visit( return f(static_cast&>(II), std::forward(args)...); + case TypeKind::Auto: + return f(static_cast&>(II), + std::forward(args)...); case TypeKind::LValueReference: return f(static_cast&>(II), diff --git a/share/mrdocs/addons/generator/asciidoc/partials/declarator-before.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/declarator-before.adoc.hbs index dd24f0942..29d9ab88b 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/declarator-before.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/declarator-before.adoc.hbs @@ -5,6 +5,7 @@ {{#if element-type~}}{{~>declarator-before element-type nolink=nolink~}}{{/if~}} {{#if return-type~}}{{~>declarator-before return-type nolink=nolink~}}{{/if~}} {{#if (eq kind "named")}}{{>name-info name nolink=nolink}}{{/if~}} +{{#if (eq kind "auto")}}{{#if constraint}}{{>name-info constraint nolink=nolink}} {{/if~}}{{keyword}}{{/if~}} {{#if cv-qualifiers~}} {{#if pointee-type}} {{cv-qualifiers}}{{else}} {{cv-qualifiers}}{{/if~}} {{/if~}} diff --git a/share/mrdocs/addons/generator/asciidoc/partials/template-param.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/template-param.adoc.hbs index 6afd331ff..d9136bb37 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/template-param.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/template-param.adoc.hbs @@ -1,5 +1,6 @@ {{#if (eq kind "type")~}} - {{key}}{{#if is-pack}}...{{/if~}} + {{#if constraint}}{{>name-info constraint}}{{else}}{{key}}{{/if~}} + {{#if is-pack}}...{{/if~}} {{#if name}} {{name}}{{/if~}} {{#if default}} = {{>template-arg default~}}{{/if~}} {{else if (eq kind "non-type")~}} diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 57bd719b4..48f9b7ee0 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -697,7 +697,6 @@ class ASTVisitor odr_hash_.AddStmt(RC); usr_.append("@TPL#"); usr_.append(llvm::itostr(odr_hash_.CalculateHash())); - llvm::outs() << usr_ << '\n'; odr_hash_.clear(); } } @@ -713,7 +712,6 @@ class ASTVisitor odr_hash_.AddStmt(RC); usr_.append("@TRC#"); usr_.append(llvm::itostr(odr_hash_.CalculateHash())); - llvm::outs() << usr_ << '\n'; odr_hash_.clear(); } @@ -1025,10 +1023,28 @@ class ASTVisitor const NestedNameSpecifier* NNS, ExtractMode extract_mode = ExtractMode::IndirectDependency); + #if 0 std::unique_ptr buildNameInfo( const Decl* D, ExtractMode extract_mode = ExtractMode::IndirectDependency); + #endif + + template> + std::unique_ptr + buildNameInfo( + DeclarationName Name, + std::optional TArgs = std::nullopt, + const NestedNameSpecifier* NNS = nullptr, + ExtractMode extract_mode = ExtractMode::IndirectDependency); + + template> + std::unique_ptr + buildNameInfo( + const Decl* D, + std::optional TArgs = std::nullopt, + const NestedNameSpecifier* NNS = nullptr, + ExtractMode extract_mode = ExtractMode::IndirectDependency); template @@ -1149,6 +1165,15 @@ class ASTVisitor if(P->hasDefaultArgument() && !R->Default) R->Default = buildTemplateArg( P->getDefaultArgument().getArgument()); + if(const TypeConstraint* TC = P->getTypeConstraint()) + { + const NestedNameSpecifier* NNS = + TC->getNestedNameSpecifierLoc().getNestedNameSpecifier(); + std::optional TArgs; + if(TC->hasExplicitTemplateArgs()) + TArgs.emplace(TC->getTemplateArgsAsWritten()); + R->Constraint = buildNameInfo(TC->getNamedConcept(), TArgs, NNS); + } return; } else if constexpr(kind == Decl::NonTypeTemplateParm) @@ -1871,12 +1896,11 @@ class ASTVisitor return std::make_pair(param_arg->getAsType(), std::move(ControllingArgs)); } - std::string - extractName( - const NamedDecl* D) + std::string extractName(DeclarationName N) { std::string result; - DeclarationName N = D->getDeclName(); + if(N.isEmpty()) + return result; switch(N.getNameKind()) { case DeclarationName::Identifier: @@ -1896,14 +1920,11 @@ class ASTVisitor break; case DeclarationName::CXXConversionFunctionName: { - MRDOCS_ASSERT(isa(D)); - const auto* CD = cast(D); result.append("operator "); // KRYSTIAN FIXME: we *really* should not be // converting types to strings like this result.append(toString( - *buildTypeInfo( - CD->getReturnType()))); + *buildTypeInfo(N.getCXXNameType()))); break; } case DeclarationName::CXXOperatorName: @@ -1926,16 +1947,19 @@ class ASTVisitor return result; } + std::string extractName(const NamedDecl* D) + { + return extractName(D->getDeclName()); + } + //------------------------------------------------ - const Decl* - getParentDecl(const Decl* D) + const Decl* getParentDecl(const Decl* D) { return getParentDecl(const_cast(D)); } - Decl* - getParentDecl(Decl* D) + Decl* getParentDecl(Decl* D) { while((D = cast_if_present< Decl>(D->getDeclContext()))) @@ -3764,15 +3788,14 @@ class TerminalTypeVisitor VisitAutoType( const AutoType* T) { - // KRYSTIAN TODO: we should probably add a TypeInfo - // to represent deduced types that also stores what - // it was deduced as. + #if 0 // KRYSTIAN NOTE: we don't use isDeduced because it will // return true if the type is dependent // if the type has been deduced, use the deduced type if(QualType DT = T->getDeducedType(); ! DT.isNull()) return Visit(DT); - getDerived().buildTerminal(NNS_, T, Quals_, IsPack_); + #endif + getDerived().buildAuto(T, Quals_, IsPack_); return true; } @@ -3984,6 +4007,14 @@ class TerminalTypeVisitor { } + void + buildAuto( + const AutoType* T, + unsigned quals, + bool pack) + { + } + void buildTerminal( const NestedNameSpecifier* NNS, @@ -4100,6 +4131,30 @@ class TypeInfoBuilder Result->IsPackExpansion = pack; } + void + buildAuto( + const AutoType* T, + unsigned quals, + bool pack) + { + auto I = std::make_unique(); + I->CVQualifiers = convertToQualifierKind(quals); + I->Keyword = convertToAutoKind(T->getKeyword()); + if(T->isConstrained()) + { + std::optional> TArgs; + if(auto Args = T->getTypeConstraintArguments(); + ! Args.empty()) + TArgs.emplace(Args); + I->Constraint = getASTVisitor().buildNameInfo( + T->getTypeConstraintConcept(), TArgs); + // Constraint->Prefix = getASTVisitor().buildNameInfo( + // cast(CD->getDeclContext())); + } + *Inner = std::move(I); + Result->IsPackExpansion = pack; + } + void buildTerminal( const NestedNameSpecifier* NNS, @@ -4373,6 +4428,7 @@ buildNameInfo( return I; } +#if 0 std::unique_ptr ASTVisitor:: buildNameInfo( @@ -4391,6 +4447,55 @@ buildNameInfo( I->Prefix = buildNameInfo(getParentDecl(D), extract_mode); return I; } +#endif + +template +std::unique_ptr +ASTVisitor:: +buildNameInfo( + DeclarationName Name, + std::optional TArgs, + const NestedNameSpecifier* NNS, + ExtractMode extract_mode) +{ + if(Name.isEmpty()) + return nullptr; + std::unique_ptr I = nullptr; + if(TArgs) + { + auto Specialization = std::make_unique(); + buildTemplateArgs(Specialization->TemplateArgs, *TArgs); + I = std::move(Specialization); + } + else + { + I = std::make_unique(); + } + I->Name = extractName(Name); + if(NNS) + I->Prefix = buildNameInfo(NNS, extract_mode); + return I; +} + +template +std::unique_ptr +ASTVisitor:: +buildNameInfo( + const Decl* D, + std::optional TArgs, + const NestedNameSpecifier* NNS, + ExtractMode extract_mode) +{ + const auto* ND = dyn_cast_if_present(D); + if(! ND) + return nullptr; + auto I = buildNameInfo(ND->getDeclName(), + std::move(TArgs), NNS, extract_mode); + if(! I) + return nullptr; + getDependencyID(getInstantiatedFrom(D), I->id); + return I; +} //------------------------------------------------ diff --git a/src/lib/AST/ASTVisitorHelpers.hpp b/src/lib/AST/ASTVisitorHelpers.hpp index 71c3d1cfe..fd81637e7 100644 --- a/src/lib/AST/ASTVisitorHelpers.hpp +++ b/src/lib/AST/ASTVisitorHelpers.hpp @@ -344,6 +344,26 @@ convertToFunctionClass( } } +/** Convert a Clang AutoTypeKeyword into a MrDocs AutoKind + */ +AutoKind +convertToAutoKind( + AutoTypeKeyword kind) +{ + using OldKind = AutoTypeKeyword; + using NewKind = AutoKind; + switch(kind) + { + case OldKind::Auto: + case OldKind::GNUAutoType: + return NewKind::Auto; + case OldKind::DecltypeAuto: + return NewKind::DecltypeAuto; + default: + MRDOCS_UNREACHABLE(); + } +} + // ---------------------------------------------------------------- /** Visit a Decl and call the appropriate visitor function. diff --git a/src/lib/AST/AnyBlock.hpp b/src/lib/AST/AnyBlock.hpp index 1ede93322..161f5fc9e 100644 --- a/src/lib/AST/AnyBlock.hpp +++ b/src/lib/AST/AnyBlock.hpp @@ -860,6 +860,9 @@ class TypeInfoBlock case TypeKind::Decltype: I_ = std::make_unique(); break; + case TypeKind::Auto: + I_ = std::make_unique(); + break; case TypeKind::LValueReference: I_ = std::make_unique(); break; @@ -910,6 +913,11 @@ class TypeInfoBlock return Error("wrong TypeInfo kind"); return decodeRecord(R, static_cast< FunctionTypeInfo&>(*I_).IsVariadic, Blob); + case TYPEINFO_AUTO_KEYWORD: + if(! I_->isAuto()) + return Error("wrong TypeInfo kind"); + return decodeRecord(R, static_cast< + AutoTypeInfo&>(*I_).Keyword, Blob); default: return AnyBlock::parseRecord(R, ID, Blob); } @@ -1136,37 +1144,7 @@ class TemplateParamBlock } Error - readSubBlock( - unsigned ID) override - { - switch(ID) - { - case BI_TEMPLATE_PARAM_BLOCK_ID: - { - if(! I_->isTemplate()) - return formatError("only TemplateTParam may have template parameters"); - TemplateParamBlock B( - static_cast( - *I_.get()).Params.emplace_back(), br_); - return br_.readBlock(B, ID); - } - case BI_TEMPLATE_ARG_BLOCK_ID: - { - TemplateArgBlock B(I_->Default, br_); - return br_.readBlock(B, ID); - } - case BI_TYPEINFO_BLOCK_ID: - { - if(! I_->isNonType()) - return formatError("only NonTypeTParams may have a type"); - TypeInfoBlock B(static_cast< - NonTypeTParam&>(*I_.get()).Type, br_); - return br_.readBlock(B, ID); - } - default: - return AnyBlock::readSubBlock(ID); - } - } + readSubBlock(unsigned ID) override; }; //------------------------------------------------ @@ -1239,6 +1217,48 @@ class NameInfoBlock } }; +Error +TemplateParamBlock:: +readSubBlock( + unsigned ID) +{ + switch(ID) + { + case BI_TEMPLATE_PARAM_BLOCK_ID: + { + if(! I_->isTemplate()) + return formatError("only TemplateTParam may have template parameters"); + TemplateParamBlock B( + static_cast( + *I_.get()).Params.emplace_back(), br_); + return br_.readBlock(B, ID); + } + case BI_TEMPLATE_ARG_BLOCK_ID: + { + TemplateArgBlock B(I_->Default, br_); + return br_.readBlock(B, ID); + } + case BI_TYPEINFO_BLOCK_ID: + { + if(! I_->isNonType()) + return formatError("only NonTypeTParams may have a type"); + TypeInfoBlock B(static_cast< + NonTypeTParam&>(*I_.get()).Type, br_); + return br_.readBlock(B, ID); + } + case BI_NAME_INFO_ID: + { + if(! I_->isType()) + return formatError("only TypeTypeTParams may have a type constraint"); + NameInfoBlock B(static_cast< + TypeTParam&>(*I_.get()).Constraint, br_); + return br_.readBlock(B, ID); + } + default: + return AnyBlock::readSubBlock(ID); + } +} + //------------------------------------------------ class TemplateBlock @@ -1372,6 +1392,8 @@ readSubBlock(unsigned ID) { if constexpr(requires { t.Name; }) NI = &t.Name; + if constexpr(requires { t.Constraint; }) + NI = &t.Constraint; }); if(! NI) return Error("wrong TypeInfo kind"); diff --git a/src/lib/AST/BitcodeIDs.hpp b/src/lib/AST/BitcodeIDs.hpp index 83077dbe9..62c4aceb5 100644 --- a/src/lib/AST/BitcodeIDs.hpp +++ b/src/lib/AST/BitcodeIDs.hpp @@ -114,6 +114,7 @@ enum RecordID TYPEINFO_NOEXCEPT, TYPEINFO_REFQUAL, TYPEINFO_IS_VARIADIC, + TYPEINFO_AUTO_KEYWORD, BASE_ACCESS, BASE_IS_VIRTUAL, FIELD_ATTRIBUTES, diff --git a/src/lib/AST/BitcodeWriter.cpp b/src/lib/AST/BitcodeWriter.cpp index 2e823a15a..5db5d1c87 100644 --- a/src/lib/AST/BitcodeWriter.cpp +++ b/src/lib/AST/BitcodeWriter.cpp @@ -353,6 +353,7 @@ RecordIDNameMap = []() {TYPEINFO_NOEXCEPT, {"TypeinfoNoexcept", &NoexceptAbbrev}}, {TYPEINFO_REFQUAL, {"TypeinfoRefqual", &Integer32Abbrev}}, {TYPEINFO_IS_VARIADIC, {"TypeinfoIsVariadic", &BoolAbbrev}}, + {TYPEINFO_AUTO_KEYWORD, {"TypeinfoAutoKeyword", &Integer32Abbrev}}, {TYPEDEF_IS_USING, {"IsUsing", &BoolAbbrev}}, {VARIABLE_BITS, {"Bits", &Integer32ArrayAbbrev}}, {USING_SYMBOLS, {"UsingSymbols", &SymbolIDsAbbrev}}, @@ -459,7 +460,8 @@ RecordsByBlock{ // TypeInfo {BI_TYPEINFO_BLOCK_ID, {TYPEINFO_KIND, TYPEINFO_IS_PACK, TYPEINFO_CVQUAL, - TYPEINFO_NOEXCEPT, TYPEINFO_REFQUAL, TYPEINFO_IS_VARIADIC}}, + TYPEINFO_NOEXCEPT, TYPEINFO_REFQUAL, TYPEINFO_IS_VARIADIC, + TYPEINFO_AUTO_KEYWORD}}, {BI_TYPEINFO_PARENT_BLOCK_ID, {}}, {BI_TYPEINFO_CHILD_BLOCK_ID, @@ -1081,6 +1083,13 @@ emitBlock( emitBlock(t.Operand); } + if constexpr(T::isAuto()) + { + emitRecord(t.Keyword, TYPEINFO_AUTO_KEYWORD); + if(t.Constraint); + emitBlock(*t.Constraint); + } + if constexpr(T::isFunction()) { emitBlock(t.ReturnType, BI_TYPEINFO_CHILD_BLOCK_ID); @@ -1268,6 +1277,8 @@ emitBlock( if constexpr(T::isType()) { emitRecord(P.KeyKind, TEMPLATE_PARAM_KEY_KIND); + if(P.Constraint) + emitBlock(*P.Constraint); } if constexpr(T::isNonType()) { diff --git a/src/lib/Gen/xml/CXXTags.hpp b/src/lib/Gen/xml/CXXTags.hpp index 4be2dfe56..b019e9d74 100644 --- a/src/lib/Gen/xml/CXXTags.hpp +++ b/src/lib/Gen/xml/CXXTags.hpp @@ -243,6 +243,13 @@ writeType( attrs.push({"operand", t.Operand.Written}); } + if constexpr(T::isAuto()) + { + attrs.push({"keyword", toString(t.Keyword)}); + if(t.Constraint) + attrs.push({"constraint", toString(*t.Constraint)}); + } + if constexpr(T::isFunction()) { if(t.IsVariadic) diff --git a/src/lib/Metadata/DomMetadata.cpp b/src/lib/Metadata/DomMetadata.cpp index 96a196124..5a00d2599 100644 --- a/src/lib/Metadata/DomMetadata.cpp +++ b/src/lib/Metadata/DomMetadata.cpp @@ -269,6 +269,8 @@ static dom::Value domCreate( std::unique_ptr const&, DomCorpus const&); static dom::Value domCreate( std::unique_ptr const& I, DomCorpus const&); +static dom::Value domCreate( + std::unique_ptr const& I, DomCorpus const&); //------------------------------------------------ @@ -387,6 +389,9 @@ domCreate( { entries.emplace_back("key", toString(t.KeyKind)); + if(t.Constraint) + entries.emplace_back("constraint", + domCreate(t.Constraint, domCorpus)); } if constexpr(T::isNonType()) { @@ -468,6 +473,15 @@ domCreate( if constexpr(T::isDecltype()) entries.emplace_back("operand", t.Operand.Written); + if constexpr(T::isAuto()) + { + entries.emplace_back("keyword", + toString(t.Keyword)); + if(t.Constraint) + entries.emplace_back("constraint", + domCreate(t.Constraint, domCorpus)); + } + if constexpr(requires { t.CVQualifiers; }) entries.emplace_back("cv-qualifiers", toString(t.CVQualifiers)); diff --git a/src/lib/Metadata/Finalize.cpp b/src/lib/Metadata/Finalize.cpp index b473f0d4e..cc3daaa9f 100644 --- a/src/lib/Metadata/Finalize.cpp +++ b/src/lib/Metadata/Finalize.cpp @@ -122,6 +122,9 @@ class Finalizer visit(param, [this](Ty& P) { + if constexpr(Ty::isType()) + finalize(P.Constraint); + if constexpr(Ty::isNonType()) finalize(P.Type); @@ -158,6 +161,9 @@ class Finalizer if constexpr(Ty::isNamed()) finalize(T.Name); + + if constexpr(Ty::isAuto()) + finalize(T.Constraint); }); } diff --git a/src/lib/Metadata/Type.cpp b/src/lib/Metadata/Type.cpp index 4c7b192b6..48b4c97f5 100644 --- a/src/lib/Metadata/Type.cpp +++ b/src/lib/Metadata/Type.cpp @@ -43,6 +43,8 @@ toString( return "named"; case TypeKind::Decltype: return "decltype"; + case TypeKind::Auto: + return "auto"; case TypeKind::LValueReference: return "lvalue-reference"; case TypeKind::RValueReference: @@ -60,6 +62,21 @@ toString( } } +dom::String +toString( + AutoKind kind) noexcept +{ + switch(kind) + { + case AutoKind::Auto: + return "auto"; + case AutoKind::DecltypeAuto: + return "decltype(auto)"; + default: + MRDOCS_UNREACHABLE(); + } +} + SymbolID TypeInfo:: namedSymbol() const noexcept @@ -151,6 +168,23 @@ operator()( if constexpr(T::isDecltype()) write("decltype(", t.Operand.Written, ')'); + if constexpr(T::isAuto()) + { + if(t.Constraint) + write(toString(*t.Constraint), ' '); + switch(t.Keyword) + { + case AutoKind::Auto: + write("auto"); + break; + case AutoKind::DecltypeAuto: + write("decltype(auto)"); + break; + default: + MRDOCS_UNREACHABLE(); + } + } + if constexpr(T::isNamed()) write(toString(*t.Name));