diff --git a/include/mrdocs/Metadata/Function.hpp b/include/mrdocs/Metadata/Function.hpp index fc0866548..a1d4f385b 100644 --- a/include/mrdocs/Metadata/Function.hpp +++ b/include/mrdocs/Metadata/Function.hpp @@ -155,6 +155,8 @@ struct FunctionInfo FnFlags0 specs0{.raw{0}}; FnFlags1 specs1{.raw{0}}; + NoexceptInfo Noexcept; + //-------------------------------------------- explicit FunctionInfo(SymbolID ID) noexcept diff --git a/include/mrdocs/Metadata/Specifiers.hpp b/include/mrdocs/Metadata/Specifiers.hpp index f10492079..de4197a3e 100644 --- a/include/mrdocs/Metadata/Specifiers.hpp +++ b/include/mrdocs/Metadata/Specifiers.hpp @@ -13,6 +13,7 @@ #include #include +#include #include namespace clang { @@ -70,30 +71,31 @@ enum class ExplicitKind */ enum class NoexceptKind { - None = 0, - // throw() - ThrowNone, - // throw(type-id-list) - Throw, - // throw(...) (microsoft extension) - ThrowAny, - // __declspec(nothrow) (microsoft extension) - NoThrow, - // noexcept-specifier, no constant-expression - Noexcept, - // noexcept-specifier, constant-expression evaluates to false - NoexceptFalse, - // noexcept-specifier, constant-expression evaluates to true - NoexceptTrue, - // noexcept-specifier, dependent constant-expression - NoexceptDependent, - - // not evaluated yet, for special member function - Unevaluated, - // not instantiated yet - Uninstantiated, - // not parsed yet - Unparsed + /** Potentially-throwing exception specification + */ + False = 0, + /** Non-throwing exception specification + */ + True, + /** Dependent exception specification + */ + Dependent +}; + +// KRYSTIAN FIXME: this needs to be improved (a lot) +struct NoexceptInfo +{ + /** Whether a noexcept-specifier was user-written. + */ + bool Implicit = true; + + /** The evaluated exception specification. + */ + NoexceptKind Kind = NoexceptKind::False; + + /** The operand of the noexcept-specifier, if any. + */ + std::string Operand; }; /** Operator kinds @@ -183,6 +185,21 @@ MRDOCS_DECL dom::String toString(NoexceptKind kind) noexcept; MRDOCS_DECL dom::String toString(ReferenceKind kind) noexcept; MRDOCS_DECL dom::String toString(StorageClassKind kind) noexcept; +/** Convert NoexceptInfo to a string. + + @param resolved If true, the operand is not shown when + the exception specification is non-dependent. + + @param implicit If true, implicit exception specifications + are shown. +*/ +MRDOCS_DECL +dom::String +toString( + NoexceptInfo info, + bool resolved = false, + bool implicit = false); + } // mrdocs } // clang diff --git a/include/mrdocs/Metadata/Type.hpp b/include/mrdocs/Metadata/Type.hpp index 0139a9482..5ea1e381e 100644 --- a/include/mrdocs/Metadata/Type.hpp +++ b/include/mrdocs/Metadata/Type.hpp @@ -216,7 +216,7 @@ struct FunctionTypeInfo std::vector> ParamTypes; QualifierKind CVQualifiers = QualifierKind::None; ReferenceKind RefQualifier = ReferenceKind::None; - NoexceptKind ExceptionSpec = NoexceptKind::None; + NoexceptInfo ExceptionSpec; TypeInfo* innerType() const noexcept override { diff --git a/mrdocs.rnc b/mrdocs.rnc index 9a7ffb34a..43177ef9d 100644 --- a/mrdocs.rnc +++ b/mrdocs.rnc @@ -75,6 +75,7 @@ grammar Access?, ID, attribute class { "constructor"|"destructor"|"conversion" } ?, + attribute exception-spec { text } ?, Location *, ( Attr * | diff --git a/share/mrdocs/addons/generator/asciidoc/partials/signature/function.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/signature/function.adoc.hbs index ea0b18f9c..9904bb83e 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/signature/function.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/signature/function.adoc.hbs @@ -19,7 +19,7 @@ {{~#if symbol.isConst}} const{{/if~}} {{#if symbol.isVolatile}} volatile{{/if~}} {{#if symbol.refQualifier}} {{symbol.refQualifier}}{{/if~}} -{{#if (eq symbol.exceptionSpec "noexcept")}} noexcept{{/if~}} +{{#if symbol.exceptionSpec}} {{symbol.exceptionSpec}}{{/if~}} {{#if (eq symbol.class "normal")}}{{>declarator-after symbol.return}}{{/if~}} {{#if symbol.hasOverrideAttr}} override{{/if~}} {{#if symbol.isFinal}} final{{/if~}} diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index f7476898f..5445bd29c 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -709,9 +709,15 @@ class ASTVisitor //------------------------------------------------ - std::string - getTypeAsString( - QualType T) + std::string getExprAsString(const Expr* E) + { + std::string result; + llvm::raw_string_ostream stream(result); + E->printPretty(stream, nullptr, context_.getPrintingPolicy()); + return result; + } + + std::string getTypeAsString(QualType T) { return T.getAsString(context_.getPrintingPolicy()); } @@ -970,8 +976,7 @@ class ASTVisitor T->getRefQualifier()); I->CVQualifiers = convertToQualifierKind( T->getMethodQuals().getFastQualifiers()); - I->ExceptionSpec = convertToNoexceptKind( - T->getExceptionSpecType()); + buildNoexceptInfo(I->ExceptionSpec, T); *std::exchange(inner, &I->ReturnType) = std::move(I); qt = T->getReturnType(); continue; @@ -1270,6 +1275,99 @@ class ASTVisitor V.getZExtValue()); } + void + buildNoexceptInfo( + NoexceptInfo& I, + ExceptionSpecificationType Kind, + const Expr* E) + { + I.Implicit = Kind == ExceptionSpecificationType::EST_None; + I.Kind = convertToNoexceptKind(Kind); + + if(! E) + return; + + I.Operand = getExprAsString(E); + } + + void + buildNoexceptInfo( + NoexceptInfo& I, + TypeSourceInfo* FTSI) + { + MRDOCS_ASSERT(FTSI && FTSI->getType()->isFunctionProtoType()); + if(auto* FPT = FTSI->getType()->getAs()) + { + buildNoexceptInfo(I, + FPT->getExceptionSpecType(), + FPT->getNoexceptExpr()); + } + } + + void + buildNoexceptInfo( + NoexceptInfo& I, + const FunctionProtoType* FPT) + { + MRDOCS_ASSERT(FPT); + I.Implicit = ! FPT->hasNoexceptExceptionSpec(); + #if 0 + // if the exception specification is unevaluated, + // we just consider it to be dependent + if(FPT->getExceptionSpecType() == + ExceptionSpecificationType::EST_Unevaluated) + I.Kind = NoexceptKind::Dependent; + else + I.Kind = convertToNoexceptKind(FPT->canThrow()); + #endif + I.Kind = convertToNoexceptKind(FPT->getExceptionSpecType()); + + // store the operand, if any + if(Expr* NoexceptExpr = FPT->getNoexceptExpr()) + I.Operand = getExprAsString(NoexceptExpr); + } + + #if 0 + void + buildNoexceptInfo( + NoexceptInfo& I, + ExceptionSpecificationType Kind, + const Expr* E) + { + if(Kind == ExceptionSpecificationType::EST_None) + return; + I.Kind = convertToNoexceptKind(Kind); + + if(! E) + return; + #if 0 + I.Operand = getSourceCode( + E->getSourceRange()); + #else + + llvm::raw_string_ostream stream(I.Operand); + E->printPretty(stream, nullptr, context_.getPrintingPolicy()); + #endif + } + + void + buildNoexceptInfo( + NoexceptInfo& I, + FunctionDecl* FD) + { + auto Kind = FD->getExceptionSpecType(); + if(Kind == ExceptionSpecificationType::EST_None) + return; + const Expr* E = nullptr; + if(auto FTL = FD->getFunctionTypeLoc()) + { + if(auto* FPT = FTL.getAs().getTypePtr()) + E = FPT->getNoexceptExpr(); + } + buildNoexceptInfo(I, Kind, E); + } + #endif + void buildExprInfo( ExprInfo& I, @@ -1308,6 +1406,16 @@ class ASTVisitor I.Value.emplace(getValue(V)); } + QualType + getDeclaratorType( + const DeclaratorDecl* DD) + { + if(auto* TSI = DD->getTypeSourceInfo(); + TSI && ! TSI->getType().isNull()) + return TSI->getType(); + return DD->getType(); + } + std::unique_ptr buildTemplateParam( const NamedDecl* N) @@ -2151,6 +2259,17 @@ class ASTVisitor addSourceLocation(I, D->getBeginLoc(), D->isThisDeclarationADefinition(), documented); + // KRYSTIAN TODO: move other extraction that requires + // a valid function type here + if(auto FT = getDeclaratorType(D); ! FT.isNull()) + { + const auto* FPT = FT->template getAs(); + + buildNoexceptInfo(I.Noexcept, FPT); + + I.specs0.hasTrailingReturn |= FPT->hasTrailingReturn(); + } + // // FunctionDecl // @@ -2165,14 +2284,10 @@ class ASTVisitor // subsumes D->hasAttr() // subsumes D->getType()->getAs()->getNoReturnAttr() I.specs0.hasOverrideAttr |= D->template hasAttr(); - if(auto const* FP = D->getType()->template getAs()) - I.specs0.hasTrailingReturn |= FP->hasTrailingReturn(); I.specs0.constexprKind |= convertToConstexprKind( D->getConstexprKind()); - I.specs0.exceptionSpec |= - convertToNoexceptKind( - D->getExceptionSpecType()); + I.specs0.overloadedOperator |= convertToOperatorKind( D->getOverloadedOperator()); diff --git a/src/lib/AST/ASTVisitorHelpers.hpp b/src/lib/AST/ASTVisitorHelpers.hpp index f08a67e57..da233e8c7 100644 --- a/src/lib/AST/ASTVisitorHelpers.hpp +++ b/src/lib/AST/ASTVisitorHelpers.hpp @@ -114,20 +114,43 @@ convertToNoexceptKind( { using OldKind = ExceptionSpecificationType; using NewKind = NoexceptKind; + // KRYSTIAN TODO: right now we convert pre-C++17 dynamic exception + // specifications to an (roughly) equivalent noexcept-specifier switch(spec) { - case OldKind::EST_None: return NewKind::None; - case OldKind::EST_DynamicNone: return NewKind::ThrowNone; - case OldKind::EST_Dynamic: return NewKind::Throw; - case OldKind::EST_MSAny: return NewKind::ThrowAny; - case OldKind::EST_NoThrow: return NewKind::NoThrow; - case OldKind::EST_BasicNoexcept: return NewKind::Noexcept; - case OldKind::EST_DependentNoexcept: return NewKind::NoexceptDependent; - case OldKind::EST_NoexceptFalse: return NewKind::NoexceptFalse; - case OldKind::EST_NoexceptTrue: return NewKind::NoexceptTrue; - case OldKind::EST_Unevaluated: return NewKind::Unevaluated; - case OldKind::EST_Uninstantiated: return NewKind::Uninstantiated; - case OldKind::EST_Unparsed: return NewKind::Unparsed; + case OldKind::EST_None: + case OldKind::EST_MSAny: + case OldKind::EST_Unevaluated: + case OldKind::EST_Uninstantiated: + // we *shouldn't* ever encounter an unparsed exception specification, + // assuming that clang is working correctly... + case OldKind::EST_Unparsed: + case OldKind::EST_Dynamic: + case OldKind::EST_NoexceptFalse: + return NewKind::False; + case OldKind::EST_NoThrow: + case OldKind::EST_BasicNoexcept: + case OldKind::EST_NoexceptTrue: + case OldKind::EST_DynamicNone: + return NewKind::True; + case OldKind::EST_DependentNoexcept: + return NewKind::Dependent; + default: + MRDOCS_UNREACHABLE(); + } +} + +NoexceptKind +convertToNoexceptKind( + CanThrowResult kind) +{ + using OldKind = CanThrowResult; + using NewKind = NoexceptKind; + switch(kind) + { + case OldKind::CT_Can: return NewKind::False; + case OldKind::CT_Cannot: return NewKind::True; + case OldKind::CT_Dependent: return NewKind::Dependent; default: MRDOCS_UNREACHABLE(); } diff --git a/src/lib/AST/AnyBlock.hpp b/src/lib/AST/AnyBlock.hpp index 6c37cdb1b..99ec2dd0a 100644 --- a/src/lib/AST/AnyBlock.hpp +++ b/src/lib/AST/AnyBlock.hpp @@ -191,6 +191,19 @@ decodeRecord( return Error::success(); } +inline +Error +decodeRecord( + Record const& R, + NoexceptInfo& I, + llvm::StringRef Blob) +{ + I.Implicit = R[0]; + I.Kind = static_cast(R[1]); + I.Operand = Blob; + return Error::success(); +} + //------------------------------------------------ struct BitcodeReader::AnyBlock @@ -859,7 +872,7 @@ class TypeInfoBlock return Error("wrong TypeInfo kind"); return decodeRecord(R, static_cast< FunctionTypeInfo&>(*I_).RefQualifier, Blob); - case TYPEINFO_EXCEPTION_SPEC: + case TYPEINFO_NOEXCEPT: if(! I_->isFunction()) return Error("wrong TypeInfo kind"); return decodeRecord(R, static_cast< @@ -1312,7 +1325,6 @@ class FunctionParamBlock } }; - //------------------------------------------------ template @@ -1427,6 +1439,8 @@ class FunctionBlock return decodeRecord(R, {&I->specs0.raw, &I->specs1.raw}, Blob); case FUNCTION_CLASS: return decodeRecord(R, I->Class, Blob); + case FUNCTION_NOEXCEPT: + return decodeRecord(R, I->Noexcept, Blob); default: return TopLevelBlock::parseRecord(R, ID, Blob); } diff --git a/src/lib/AST/BitcodeIDs.hpp b/src/lib/AST/BitcodeIDs.hpp index 6f7553b4d..60579d0c4 100644 --- a/src/lib/AST/BitcodeIDs.hpp +++ b/src/lib/AST/BitcodeIDs.hpp @@ -106,7 +106,7 @@ enum RecordID TYPEINFO_ID, TYPEINFO_NAME, TYPEINFO_CVQUAL, - TYPEINFO_EXCEPTION_SPEC, + TYPEINFO_NOEXCEPT, TYPEINFO_REFQUAL, BASE_ACCESS, BASE_IS_VIRTUAL, @@ -117,6 +117,7 @@ enum RecordID FRIEND_SYMBOL, FUNCTION_BITS, FUNCTION_CLASS, + FUNCTION_NOEXCEPT, FUNCTION_PARAM_NAME, FUNCTION_PARAM_DEFAULT, GUIDE_EXPLICIT, diff --git a/src/lib/AST/BitcodeWriter.cpp b/src/lib/AST/BitcodeWriter.cpp index 8c4a86f5a..3ddc2be64 100644 --- a/src/lib/AST/BitcodeWriter.cpp +++ b/src/lib/AST/BitcodeWriter.cpp @@ -177,6 +177,26 @@ static void LocationAbbrev( llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob) }); } +// Assumes that the file will not have more than 65535 lines. +static void NoexceptAbbrev( + std::shared_ptr& Abbrev) +{ + AbbrevGen(Abbrev, { + // NoexceptInfo::Implicit + llvm::BitCodeAbbrevOp( + llvm::BitCodeAbbrevOp::Fixed, + BitCodeConstants::BoolSize), + // NoexceptInfo::Kind + llvm::BitCodeAbbrevOp( + llvm::BitCodeAbbrevOp::Fixed, 2), + // NoexceptInfo::Operand + llvm::BitCodeAbbrevOp( + llvm::BitCodeAbbrevOp::Fixed, + BitCodeConstants::StringLengthSize), + // 5. The string blob + llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob) }); +} + //------------------------------------------------ struct RecordIDDsc @@ -235,7 +255,7 @@ BlockIdNameMap = []() {BI_SPECIALIZATION_BLOCK_ID, "SpecializationBlock"}, {BI_FRIEND_BLOCK_ID, "FriendBlock"}, {BI_ENUMERATOR_BLOCK_ID, "EnumeratorBlock"}, - {BI_VARIABLE_BLOCK_ID, "VarBlock"} + {BI_VARIABLE_BLOCK_ID, "VarBlock"}, }; MRDOCS_ASSERT(Inits.size() == BlockIdCount); for (const auto& Init : Inits) @@ -267,6 +287,7 @@ RecordIDNameMap = []() {FRIEND_SYMBOL, {"FriendSymbol", &SymbolIDAbbrev}}, {FUNCTION_BITS, {"Bits", &Integer32ArrayAbbrev}}, {FUNCTION_CLASS, {"FunctionClass", &Integer32Abbrev}}, + {FUNCTION_NOEXCEPT, {"FunctionNoexcept", &NoexceptAbbrev}}, {FUNCTION_PARAM_NAME, {"Name", &StringAbbrev}}, {FUNCTION_PARAM_DEFAULT, {"Default", &StringAbbrev}}, {GUIDE_EXPLICIT, {"Explicit", &Integer32Abbrev}}, @@ -307,7 +328,7 @@ RecordIDNameMap = []() {TYPEINFO_ID, {"TypeinfoID", &SymbolIDAbbrev}}, {TYPEINFO_NAME, {"TypeinfoName", &StringAbbrev}}, {TYPEINFO_CVQUAL, {"TypeinfoCV", &Integer32Abbrev}}, - {TYPEINFO_EXCEPTION_SPEC, {"TypeinfoNoexcept", &Integer32Abbrev}}, + {TYPEINFO_NOEXCEPT, {"TypeinfoNoexcept", &NoexceptAbbrev}}, {TYPEINFO_REFQUAL, {"TypeinfoRefqual", &Integer32Abbrev}}, {TYPEDEF_IS_USING, {"IsUsing", &BoolAbbrev}}, {VARIABLE_BITS, {"Bits", &Integer32ArrayAbbrev}} @@ -357,7 +378,7 @@ RecordsByBlock{ FIELD_IS_MUTABLE, FIELD_IS_BITFIELD}}, // FunctionInfo {BI_FUNCTION_BLOCK_ID, - {FUNCTION_BITS, FUNCTION_CLASS}}, + {FUNCTION_BITS, FUNCTION_CLASS, FUNCTION_NOEXCEPT}}, // Param {BI_FUNCTION_PARAM_BLOCK_ID, {FUNCTION_PARAM_NAME, FUNCTION_PARAM_DEFAULT}}, @@ -401,7 +422,7 @@ RecordsByBlock{ // TypeInfo {BI_TYPEINFO_BLOCK_ID, {TYPEINFO_KIND, TYPEINFO_IS_PACK, TYPEINFO_ID, TYPEINFO_NAME, - TYPEINFO_CVQUAL, TYPEINFO_EXCEPTION_SPEC, TYPEINFO_REFQUAL}}, + TYPEINFO_CVQUAL, TYPEINFO_NOEXCEPT, TYPEINFO_REFQUAL}}, {BI_TYPEINFO_PARENT_BLOCK_ID, {}}, {BI_TYPEINFO_CHILD_BLOCK_ID, @@ -414,7 +435,7 @@ RecordsByBlock{ // VariableInfo {BI_VARIABLE_BLOCK_ID, {VARIABLE_BITS}}, // GuideInfo - {BI_GUIDE_BLOCK_ID, {GUIDE_EXPLICIT}} + {BI_GUIDE_BLOCK_ID, {GUIDE_EXPLICIT}}, }; //------------------------------------------------ @@ -686,6 +707,23 @@ emitRecord( Loc.Path + Loc.Filename); } +void +BitcodeWriter:: +emitRecord( + NoexceptInfo const& I, RecordID ID) +{ + MRDOCS_ASSERT(RecordIDNameMap[ID] && "Unknown RecordID."); + MRDOCS_ASSERT(RecordIDNameMap[ID].Abbrev == &NoexceptAbbrev && + "Abbrev type mismatch."); + if (!prepRecordData(ID, true)) + return; + + Record.push_back(I.Implicit); + Record.push_back(to_underlying(I.Kind)); + Record.push_back(I.Operand.size()); + Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, I.Operand); +} + void BitcodeWriter:: emitRecord( @@ -846,6 +884,7 @@ emitBlock( emitBlock(I.ReturnType); for (const auto& N : I.Params) emitBlock(N); + emitRecord(I.Noexcept, FUNCTION_NOEXCEPT); } void @@ -988,7 +1027,7 @@ emitBlock( emitBlock(P, BI_TYPEINFO_PARAM_BLOCK_ID); emitRecord(t.RefQualifier, TYPEINFO_REFQUAL); - emitRecord(t.ExceptionSpec, TYPEINFO_EXCEPTION_SPEC); + emitRecord(t.ExceptionSpec, TYPEINFO_NOEXCEPT); } }); } diff --git a/src/lib/AST/BitcodeWriter.hpp b/src/lib/AST/BitcodeWriter.hpp index 050b6371c..836847639 100644 --- a/src/lib/AST/BitcodeWriter.hpp +++ b/src/lib/AST/BitcodeWriter.hpp @@ -78,6 +78,7 @@ class BitcodeWriter void emitRecord(SymbolID const& Str, RecordID ID); void emitRecord(llvm::StringRef Str, RecordID ID); void emitRecord(Location const& Loc, RecordID ID); + void emitRecord(NoexceptInfo const& I, RecordID ID); void emitRecord(bool Value, RecordID ID); void emitRecord(std::initializer_list values, RecordID ID); diff --git a/src/lib/Gen/xml/CXXTags.hpp b/src/lib/Gen/xml/CXXTags.hpp index 2a5ceb233..7b58cbc8c 100644 --- a/src/lib/Gen/xml/CXXTags.hpp +++ b/src/lib/Gen/xml/CXXTags.hpp @@ -253,8 +253,9 @@ writeType( if(t.RefQualifier != ReferenceKind::None) attrs.push({"ref-qualifier", toString(t.RefQualifier)}); - if(t.ExceptionSpec != NoexceptKind::None) - attrs.push({"exception-spec", toString(t.ExceptionSpec)}); + // KRYSTIAN TODO: TypeInfo should use ExceptionInfo! + if(auto spec = toString(t.ExceptionSpec); ! spec.empty()) + attrs.push({"exception-spec", spec}); } // ---------------------------------------------------------------- diff --git a/src/lib/Gen/xml/XMLWriter.cpp b/src/lib/Gen/xml/XMLWriter.cpp index 041d00318..af137dbd3 100644 --- a/src/lib/Gen/xml/XMLWriter.cpp +++ b/src/lib/Gen/xml/XMLWriter.cpp @@ -318,11 +318,15 @@ writeFunction( { openTemplate(I.Template); + auto except_spec = toString(I.Noexcept); + tags_.open(functionTagName, { { "class", toString(I.Class), I.Class != FunctionClass::Normal }, { "name", I.Name }, { I.Access }, + { "exception-spec", except_spec, + ! except_spec.empty() }, { I.id } }); diff --git a/src/lib/Metadata/DomMetadata.cpp b/src/lib/Metadata/DomMetadata.cpp index 4566904bf..5957abf91 100644 --- a/src/lib/Metadata/DomMetadata.cpp +++ b/src/lib/Metadata/DomMetadata.cpp @@ -776,6 +776,19 @@ DomInfo::construct() const { "template", domCreate(I_.Template, domCorpus_) }, { "overloadedOperator", I_.specs0.overloadedOperator.get() }, }); + + entries.emplace_back("exceptionSpec", toString(I_.Noexcept)); + #if 0 + if(I_.Noexcept.Kind != NoexceptKind::None) + { + dom::String exceptSpec = "noexcept"; + if(! I_.Noexcept.Operand.empty()) + exceptSpec = fmt::format( + "noexcept({})", + I_.Noexcept.Operand); + entries.emplace_back("exceptionSpec", std::move(exceptSpec)); + } + #endif } if constexpr(T::isTypedef()) { diff --git a/src/lib/Metadata/Reduce.cpp b/src/lib/Metadata/Reduce.cpp index 6dcced0eb..a0727fd8d 100644 --- a/src/lib/Metadata/Reduce.cpp +++ b/src/lib/Metadata/Reduce.cpp @@ -200,6 +200,8 @@ void merge(FunctionInfo& I, FunctionInfo&& Other) I.Template = std::move(Other.Template); I.specs0.raw.value |= Other.specs0.raw.value; I.specs1.raw.value |= Other.specs1.raw.value; + if(I.Noexcept.Implicit) + I.Noexcept = std::move(Other.Noexcept); } void merge(GuideInfo& I, GuideInfo&& Other) diff --git a/src/lib/Metadata/Specifiers.cpp b/src/lib/Metadata/Specifiers.cpp index 1fbfccf96..466319540 100644 --- a/src/lib/Metadata/Specifiers.cpp +++ b/src/lib/Metadata/Specifiers.cpp @@ -70,23 +70,34 @@ dom::String toString(NoexceptKind kind) noexcept { switch(kind) { - case NoexceptKind::None: return ""; - case NoexceptKind::ThrowNone: return "throw()"; - case NoexceptKind::Throw: return "throw"; - case NoexceptKind::ThrowAny: return "throw(...)"; - case NoexceptKind::NoThrow: return "__declspec(nothrow)"; - case NoexceptKind::Noexcept: return "noexcept"; - case NoexceptKind::NoexceptFalse: return "noexcept(false)"; - case NoexceptKind::NoexceptTrue: return "noexcept(true)"; - case NoexceptKind::NoexceptDependent: return "noexcept(expr)"; - case NoexceptKind::Unevaluated: return ""; - case NoexceptKind::Uninstantiated: return ""; - case NoexceptKind::Unparsed: return ""; + case NoexceptKind::False: return ""; + case NoexceptKind::True: return "noexcept"; + case NoexceptKind::Dependent: return "noexcept(...)"; default: MRDOCS_UNREACHABLE(); } } +dom::String +toString( + NoexceptInfo info, + bool resolved, + bool implicit) +{ + if(! implicit && info.Implicit) + return ""; + if(info.Kind == NoexceptKind::Dependent && + info.Operand.empty()) + return ""; + if(info.Kind == NoexceptKind::False && + (resolved || info.Operand.empty())) + return ""; + if(info.Kind == NoexceptKind::True && + (resolved || info.Operand.empty())) + return "noexcept"; + return fmt::format("noexcept({})", info.Operand); +} + dom::String toString(ReferenceKind kind) noexcept { switch(kind) diff --git a/src/lib/Metadata/Type.cpp b/src/lib/Metadata/Type.cpp index 1e166c106..dde5a7ce0 100644 --- a/src/lib/Metadata/Type.cpp +++ b/src/lib/Metadata/Type.cpp @@ -251,8 +251,8 @@ operator()( if(t.RefQualifier != ReferenceKind::None) write(' ', toString(t.RefQualifier)); - if(t.ExceptionSpec != NoexceptKind::None) - write(' ', toString(t.ExceptionSpec)); + if(auto spec = toString(t.ExceptionSpec); ! spec.empty()) + write(' ', spec); } if(TypeInfo* inner = t.innerType()) diff --git a/test-files/old-tests/explicit-ctor.xml b/test-files/old-tests/explicit-ctor.xml index a6519c8c3..9223bed22 100644 --- a/test-files/old-tests/explicit-ctor.xml +++ b/test-files/old-tests/explicit-ctor.xml @@ -17,9 +17,8 @@ - + - @@ -53,9 +52,8 @@ - + - @@ -89,9 +87,8 @@ - + - @@ -127,9 +124,8 @@ - + - diff --git a/test-files/old-tests/mem-fn.xml b/test-files/old-tests/mem-fn.xml index 44f304cc3..d593f84dd 100644 --- a/test-files/old-tests/mem-fn.xml +++ b/test-files/old-tests/mem-fn.xml @@ -51,9 +51,8 @@ - + - @@ -121,30 +120,27 @@ - + - - + - - + - @@ -157,10 +153,9 @@ - + -