Skip to content

Commit 5d3c1dc

Browse files
committed
Reland "[flang] add option to generate runtime type info as external (llvm#145901)"
Merging upstream PR: llvm#146071. Reland llvm#145901 with a fix for shared library builds (see second commit). Lowering cannot directly use cl::opts from lib/Optimizer/Passes/CommandLineOpts.cpp without linking against `flangPasses`. Instead of adding the linking dependency, I think it is cleaner to use a proper lowering options and let the driver read the cl::opt (I would rather keep the option a cl::opt before doing a bit more testing and making it a proper driver option).
1 parent fadd3f9 commit 5d3c1dc

File tree

18 files changed

+267
-169
lines changed

18 files changed

+267
-169
lines changed

flang/include/flang/Evaluate/tools.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,7 @@ bool IsExtensibleType(const DerivedTypeSpec *);
15851585
bool IsSequenceOrBindCType(const DerivedTypeSpec *);
15861586
bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name);
15871587
bool IsBuiltinCPtr(const Symbol &);
1588+
bool IsFromBuiltinModule(const Symbol &);
15881589
bool IsEventType(const DerivedTypeSpec *);
15891590
bool IsLockType(const DerivedTypeSpec *);
15901591
bool IsNotifyType(const DerivedTypeSpec *);

flang/include/flang/Lower/LoweringOptions.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,9 @@ ENUM_LOWERINGOPT(RepackArraysWhole, unsigned, 1, 0)
6666
/// If true, CUDA Fortran runtime check is inserted.
6767
ENUM_LOWERINGOPT(CUDARuntimeCheck, unsigned, 1, 0)
6868

69+
/// If true, do not generate definition for runtime type info global objects of
70+
/// derived types defined in other compilation units.
71+
ENUM_LOWERINGOPT(SkipExternalRttiDefinition, unsigned, 1, 0)
72+
6973
#undef LOWERINGOPT
7074
#undef ENUM_LOWERINGOPT

flang/include/flang/Optimizer/CodeGen/CodeGen.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ struct FIRToLLVMPassOptions {
3939
// that such programs would crash at runtime if the derived type descriptors
4040
// are required by the runtime, so this is only an option to help debugging.
4141
bool ignoreMissingTypeDescriptors = false;
42+
// Similar to ignoreMissingTypeDescriptors, but generate external declaration
43+
// for the missing type descriptor globals instead.
44+
bool skipExternalRttiDefinition = false;
4245

4346
// Generate TBAA information for FIR types and memory accessing operations.
4447
bool applyTBAA = false;

flang/include/flang/Optimizer/Passes/CommandLineOpts.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ extern llvm::cl::opt<std::size_t> arrayStackAllocationThreshold;
3232
/// generated by the frontend.
3333
extern llvm::cl::opt<bool> ignoreMissingTypeDescriptors;
3434

35+
/// Shared option in tools to only generate rtti static object definitions for
36+
/// derived types defined in the current compilation unit. Derived type
37+
/// descriptor object for types defined in other objects will only be declared
38+
/// as external. This also changes the linkage of rtti objects defined in the
39+
/// current compilation unit from linkonce_odr to external so that unused rtti
40+
/// objects are retained and can be accessed from other compilation units. This
41+
/// is an experimental option to explore compilation speed improvements and is
42+
/// an ABI breaking change because of the linkage change.
43+
/// It will also require linking against module file objects of modules defining
44+
/// only types (even for trivial types without type bound procedures, which
45+
/// differs from most compilers).
46+
extern llvm::cl::opt<bool> skipExternalRttiDefinition;
47+
3548
/// Default optimization level used to create Flang pass pipeline is O0.
3649
extern llvm::OptimizationLevel defaultOptLevel;
3750

flang/include/flang/Optimizer/Support/Utils.h

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,32 +35,6 @@ inline std::int64_t toInt(mlir::arith::ConstantOp cop) {
3535
.getSExtValue();
3636
}
3737

38-
// Reconstruct binding tables for dynamic dispatch.
39-
using BindingTable = llvm::DenseMap<llvm::StringRef, unsigned>;
40-
using BindingTables = llvm::DenseMap<llvm::StringRef, BindingTable>;
41-
42-
inline void buildBindingTables(BindingTables &bindingTables,
43-
mlir::ModuleOp mod) {
44-
45-
// The binding tables are defined in FIR after lowering inside fir.type_info
46-
// operations. Go through each binding tables and store the procedure name and
47-
// binding index for later use by the fir.dispatch conversion pattern.
48-
for (auto typeInfo : mod.getOps<fir::TypeInfoOp>()) {
49-
unsigned bindingIdx = 0;
50-
BindingTable bindings;
51-
if (typeInfo.getDispatchTable().empty()) {
52-
bindingTables[typeInfo.getSymName()] = bindings;
53-
continue;
54-
}
55-
for (auto dtEntry :
56-
typeInfo.getDispatchTable().front().getOps<fir::DTEntryOp>()) {
57-
bindings[dtEntry.getMethod()] = bindingIdx;
58-
++bindingIdx;
59-
}
60-
bindingTables[typeInfo.getSymName()] = bindings;
61-
}
62-
}
63-
6438
// Translate front-end KINDs for use in the IR and code gen.
6539
inline std::vector<fir::KindTy>
6640
fromDefaultKinds(const Fortran::common::IntrinsicTypeDefaultKinds &defKinds) {

flang/include/flang/Semantics/runtime-type-info.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables(SemanticsContext &);
3838
/// to describe other derived types at runtime in flang descriptor.
3939
constexpr char typeInfoBuiltinModule[]{"__fortran_type_info"};
4040

41+
/// Name of the builtin derived type in __fortran_type_inf that is used for
42+
/// derived type descriptors.
43+
constexpr char typeDescriptorTypeName[]{"derivedtype"};
44+
4145
/// Name of the bindings descriptor component in the DerivedType type of the
4246
/// __Fortran_type_info module
4347
constexpr char bindingDescCompName[]{"binding"};

flang/lib/Evaluate/tools.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2334,6 +2334,11 @@ bool IsBuiltinCPtr(const Symbol &symbol) {
23342334
return false;
23352335
}
23362336

2337+
bool IsFromBuiltinModule(const Symbol &symbol) {
2338+
const Scope &scope{symbol.GetUltimate().owner()};
2339+
return IsSameModule(&scope, scope.context().GetBuiltinsScope());
2340+
}
2341+
23372342
bool IsIsoCType(const DerivedTypeSpec *derived) {
23382343
return IsBuiltinDerivedType(derived, "c_ptr") ||
23392344
IsBuiltinDerivedType(derived, "c_funptr");

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "flang/Frontend/CodeGenOptions.h"
1515
#include "flang/Frontend/PreprocessorOptions.h"
1616
#include "flang/Frontend/TargetOptions.h"
17+
#include "flang/Optimizer/Passes/CommandLineOpts.h"
1718
#include "flang/Semantics/semantics.h"
1819
#include "flang/Support/Fortran-features.h"
1920
#include "flang/Support/OpenMP-features.h"
@@ -1807,6 +1808,7 @@ void CompilerInvocation::setLoweringOptions() {
18071808
// Lower TRANSPOSE as a runtime call under -O0.
18081809
loweringOpts.setOptimizeTranspose(codegenOpts.OptimizationLevel > 0);
18091810
loweringOpts.setUnderscoring(codegenOpts.Underscoring);
1811+
loweringOpts.setSkipExternalRttiDefinition(skipExternalRttiDefinition);
18101812

18111813
const Fortran::common::LangOptions &langOptions = getLangOpts();
18121814
loweringOpts.setIntegerWrapAround(langOptions.getSignedOverflowBehavior() ==

flang/lib/Lower/Bridge.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ class TypeInfoConverter {
263263
}
264264

265265
void createTypeInfo(Fortran::lower::AbstractConverter &converter) {
266+
createTypeInfoForTypeDescriptorBuiltinType(converter);
266267
while (!registeredTypeInfoA.empty()) {
267268
currentTypeInfoStack = &registeredTypeInfoB;
268269
for (const TypeInfo &info : registeredTypeInfoA)
@@ -278,10 +279,22 @@ class TypeInfoConverter {
278279
private:
279280
void createTypeInfoOpAndGlobal(Fortran::lower::AbstractConverter &converter,
280281
const TypeInfo &info) {
281-
Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get());
282+
if (!converter.getLoweringOptions().getSkipExternalRttiDefinition())
283+
Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get());
282284
createTypeInfoOp(converter, info);
283285
}
284286

287+
void createTypeInfoForTypeDescriptorBuiltinType(
288+
Fortran::lower::AbstractConverter &converter) {
289+
if (registeredTypeInfoA.empty())
290+
return;
291+
auto builtinTypeInfoType = llvm::cast<fir::RecordType>(
292+
converter.genType(registeredTypeInfoA[0].symbol.get()));
293+
converter.getFirOpBuilder().createTypeInfoOp(
294+
registeredTypeInfoA[0].loc, builtinTypeInfoType,
295+
/*parentType=*/fir::RecordType{});
296+
}
297+
285298
void createTypeInfoOp(Fortran::lower::AbstractConverter &converter,
286299
const TypeInfo &info) {
287300
fir::RecordType parentType{};

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -647,13 +647,19 @@ fir::GlobalOp Fortran::lower::defineGlobal(
647647

648648
/// Return linkage attribute for \p var.
649649
static mlir::StringAttr
650-
getLinkageAttribute(fir::FirOpBuilder &builder,
650+
getLinkageAttribute(Fortran::lower::AbstractConverter &converter,
651651
const Fortran::lower::pft::Variable &var) {
652+
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
652653
// Runtime type info for a same derived type is identical in each compilation
653654
// unit. It desired to avoid having to link against module that only define a
654655
// type. Therefore the runtime type info is generated everywhere it is needed
655-
// with `linkonce_odr` LLVM linkage.
656-
if (var.isRuntimeTypeInfoData())
656+
// with `linkonce_odr` LLVM linkage (unless the skipExternalRttiDefinition
657+
// option is set, in which case one will need to link against objects of
658+
// modules defining types). Builtin objects rtti is always generated because
659+
// the builtin module is currently not compiled or part of the runtime.
660+
if (var.isRuntimeTypeInfoData() &&
661+
(!converter.getLoweringOptions().getSkipExternalRttiDefinition() ||
662+
Fortran::semantics::IsFromBuiltinModule(var.getSymbol())))
657663
return builder.createLinkOnceODRLinkage();
658664
if (var.isModuleOrSubmoduleVariable())
659665
return {}; // external linkage
@@ -673,7 +679,7 @@ static void instantiateGlobal(Fortran::lower::AbstractConverter &converter,
673679
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
674680
std::string globalName = converter.mangleName(sym);
675681
mlir::Location loc = genLocation(converter, sym);
676-
mlir::StringAttr linkage = getLinkageAttribute(builder, var);
682+
mlir::StringAttr linkage = getLinkageAttribute(converter, var);
677683
fir::GlobalOp global;
678684
if (var.isModuleOrSubmoduleVariable()) {
679685
// A non-intrinsic module global is defined when lowering the module.
@@ -1265,7 +1271,7 @@ instantiateAggregateStore(Fortran::lower::AbstractConverter &converter,
12651271
if (var.isGlobal()) {
12661272
fir::GlobalOp global;
12671273
auto &aggregate = var.getAggregateStore();
1268-
mlir::StringAttr linkage = getLinkageAttribute(builder, var);
1274+
mlir::StringAttr linkage = getLinkageAttribute(converter, var);
12691275
if (var.isModuleOrSubmoduleVariable()) {
12701276
// A module global was or will be defined when lowering the module. Emit
12711277
// only a declaration if the global does not exist at that point.
@@ -2470,8 +2476,7 @@ void Fortran::lower::defineModuleVariable(
24702476
AbstractConverter &converter, const Fortran::lower::pft::Variable &var) {
24712477
// Use empty linkage for module variables, which makes them available
24722478
// for use in another unit.
2473-
mlir::StringAttr linkage =
2474-
getLinkageAttribute(converter.getFirOpBuilder(), var);
2479+
mlir::StringAttr linkage = getLinkageAttribute(converter, var);
24752480
if (!var.isGlobal())
24762481
fir::emitFatalError(converter.getCurrentLocation(),
24772482
"attempting to lower module variable as local");
@@ -2606,10 +2611,9 @@ void Fortran::lower::createIntrinsicModuleGlobal(
26062611
void Fortran::lower::createRuntimeTypeInfoGlobal(
26072612
Fortran::lower::AbstractConverter &converter,
26082613
const Fortran::semantics::Symbol &typeInfoSym) {
2609-
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
26102614
std::string globalName = converter.mangleName(typeInfoSym);
26112615
auto var = Fortran::lower::pft::Variable(typeInfoSym, /*global=*/true);
2612-
mlir::StringAttr linkage = getLinkageAttribute(builder, var);
2616+
mlir::StringAttr linkage = getLinkageAttribute(converter, var);
26132617
defineGlobal(converter, var, globalName, linkage);
26142618
}
26152619

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,51 @@ genCUFAllocDescriptor(mlir::Location loc,
13321332
.getResult();
13331333
}
13341334

1335+
/// Get the address of the type descriptor global variable that was created by
1336+
/// lowering for derived type \p recType.
1337+
template <typename ModOpTy>
1338+
static mlir::Value
1339+
getTypeDescriptor(ModOpTy mod, mlir::ConversionPatternRewriter &rewriter,
1340+
mlir::Location loc, fir::RecordType recType,
1341+
const fir::FIRToLLVMPassOptions &options) {
1342+
std::string name =
1343+
options.typeDescriptorsRenamedForAssembly
1344+
? fir::NameUniquer::getTypeDescriptorAssemblyName(recType.getName())
1345+
: fir::NameUniquer::getTypeDescriptorName(recType.getName());
1346+
mlir::Type llvmPtrTy = ::getLlvmPtrType(mod.getContext());
1347+
if (auto global = mod.template lookupSymbol<fir::GlobalOp>(name))
1348+
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1349+
global.getSymName());
1350+
// The global may have already been translated to LLVM.
1351+
if (auto global = mod.template lookupSymbol<mlir::LLVM::GlobalOp>(name))
1352+
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1353+
global.getSymName());
1354+
// Type info derived types do not have type descriptors since they are the
1355+
// types defining type descriptors.
1356+
if (options.ignoreMissingTypeDescriptors ||
1357+
fir::NameUniquer::belongsToModule(
1358+
name, Fortran::semantics::typeInfoBuiltinModule))
1359+
return rewriter.create<mlir::LLVM::ZeroOp>(loc, llvmPtrTy);
1360+
1361+
if (!options.skipExternalRttiDefinition)
1362+
fir::emitFatalError(loc,
1363+
"runtime derived type info descriptor was not "
1364+
"generated and skipExternalRttiDefinition and "
1365+
"ignoreMissingTypeDescriptors options are not set");
1366+
1367+
// Rtti for a derived type defined in another compilation unit and for which
1368+
// rtti was not defined in lowering because of the skipExternalRttiDefinition
1369+
// option. Generate the object declaration now.
1370+
auto insertPt = rewriter.saveInsertionPoint();
1371+
rewriter.setInsertionPoint(mod.getBody(), mod.getBody()->end());
1372+
mlir::LLVM::GlobalOp global = rewriter.create<mlir::LLVM::GlobalOp>(
1373+
loc, llvmPtrTy, /*constant=*/true, mlir::LLVM::Linkage::External, name,
1374+
mlir::Attribute());
1375+
rewriter.restoreInsertionPoint(insertPt);
1376+
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1377+
global.getSymName());
1378+
}
1379+
13351380
/// Common base class for embox to descriptor conversion.
13361381
template <typename OP>
13371382
struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
@@ -1444,41 +1489,6 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
14441489
stride);
14451490
}
14461491

1447-
/// Get the address of the type descriptor global variable that was created by
1448-
/// lowering for derived type \p recType.
1449-
template <typename ModOpTy>
1450-
mlir::Value
1451-
getTypeDescriptor(ModOpTy mod, mlir::ConversionPatternRewriter &rewriter,
1452-
mlir::Location loc, fir::RecordType recType) const {
1453-
std::string name =
1454-
this->options.typeDescriptorsRenamedForAssembly
1455-
? fir::NameUniquer::getTypeDescriptorAssemblyName(recType.getName())
1456-
: fir::NameUniquer::getTypeDescriptorName(recType.getName());
1457-
mlir::Type llvmPtrTy = ::getLlvmPtrType(mod.getContext());
1458-
mlir::DataLayout dataLayout(mod);
1459-
if (auto global = mod.template lookupSymbol<fir::GlobalOp>(name)) {
1460-
return replaceWithAddrOfOrASCast(
1461-
rewriter, loc, fir::factory::getGlobalAddressSpace(&dataLayout),
1462-
fir::factory::getProgramAddressSpace(&dataLayout),
1463-
global.getSymName(), llvmPtrTy);
1464-
}
1465-
if (auto global = mod.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1466-
// The global may have already been translated to LLVM.
1467-
return replaceWithAddrOfOrASCast(
1468-
rewriter, loc, global.getAddrSpace(),
1469-
fir::factory::getProgramAddressSpace(&dataLayout),
1470-
global.getSymName(), llvmPtrTy);
1471-
}
1472-
// Type info derived types do not have type descriptors since they are the
1473-
// types defining type descriptors.
1474-
if (!this->options.ignoreMissingTypeDescriptors &&
1475-
!fir::NameUniquer::belongsToModule(
1476-
name, Fortran::semantics::typeInfoBuiltinModule))
1477-
fir::emitFatalError(
1478-
loc, "runtime derived type info descriptor was not generated");
1479-
return rewriter.create<mlir::LLVM::ZeroOp>(loc, llvmPtrTy);
1480-
}
1481-
14821492
template <typename ModOpTy>
14831493
mlir::Value populateDescriptor(mlir::Location loc, ModOpTy mod,
14841494
fir::BaseBoxType boxTy, mlir::Type inputType,
@@ -1543,16 +1553,17 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
15431553
mlir::Type innerType = fir::unwrapInnerType(inputType);
15441554
if (innerType && mlir::isa<fir::RecordType>(innerType)) {
15451555
auto recTy = mlir::dyn_cast<fir::RecordType>(innerType);
1546-
typeDesc = getTypeDescriptor(mod, rewriter, loc, recTy);
1556+
typeDesc =
1557+
getTypeDescriptor(mod, rewriter, loc, recTy, this->options);
15471558
} else {
15481559
// Unlimited polymorphic type descriptor with no record type. Set
15491560
// type descriptor address to a clean state.
15501561
typeDesc = rewriter.create<mlir::LLVM::ZeroOp>(
15511562
loc, ::getLlvmPtrType(mod.getContext()));
15521563
}
15531564
} else {
1554-
typeDesc = getTypeDescriptor(mod, rewriter, loc,
1555-
fir::unwrapIfDerived(boxTy));
1565+
typeDesc = getTypeDescriptor(
1566+
mod, rewriter, loc, fir::unwrapIfDerived(boxTy), this->options);
15561567
}
15571568
}
15581569
if (typeDesc)
@@ -3064,26 +3075,10 @@ struct TypeDescOpConversion : public fir::FIROpConversion<fir::TypeDescOp> {
30643075
assert(mlir::isa<fir::RecordType>(inTy) && "expecting fir.type");
30653076
auto recordType = mlir::dyn_cast<fir::RecordType>(inTy);
30663077
auto module = typeDescOp.getOperation()->getParentOfType<mlir::ModuleOp>();
3067-
std::string typeDescName =
3068-
this->options.typeDescriptorsRenamedForAssembly
3069-
? fir::NameUniquer::getTypeDescriptorAssemblyName(
3070-
recordType.getName())
3071-
: fir::NameUniquer::getTypeDescriptorName(recordType.getName());
3072-
auto llvmPtrTy = ::getLlvmPtrType(typeDescOp.getContext());
3073-
if (auto global = module.lookupSymbol<mlir::LLVM::GlobalOp>(typeDescName)) {
3074-
replaceWithAddrOfOrASCast(rewriter, typeDescOp->getLoc(),
3075-
global.getAddrSpace(),
3076-
getProgramAddressSpace(rewriter),
3077-
global.getSymName(), llvmPtrTy, typeDescOp);
3078-
return mlir::success();
3079-
} else if (auto global = module.lookupSymbol<fir::GlobalOp>(typeDescName)) {
3080-
replaceWithAddrOfOrASCast(rewriter, typeDescOp->getLoc(),
3081-
getGlobalAddressSpace(rewriter),
3082-
getProgramAddressSpace(rewriter),
3083-
global.getSymName(), llvmPtrTy, typeDescOp);
3084-
return mlir::success();
3085-
}
3086-
return mlir::failure();
3078+
mlir::Value typeDesc = getTypeDescriptor(
3079+
module, rewriter, typeDescOp.getLoc(), recordType, this->options);
3080+
rewriter.replaceOp(typeDescOp, typeDesc);
3081+
return mlir::success();
30873082
}
30883083
};
30893084

flang/lib/Optimizer/Passes/CommandLineOpts.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ cl::opt<bool> ignoreMissingTypeDescriptors(
3939
"translating FIR to LLVM"),
4040
cl::init(false), cl::Hidden);
4141

42+
cl::opt<bool> skipExternalRttiDefinition(
43+
"skip-external-rtti-definition", llvm::cl::init(false),
44+
llvm::cl::desc("do not define rtti static objects for types belonging to "
45+
"other compilation units"),
46+
cl::Hidden);
47+
4248
OptimizationLevel defaultOptLevel{OptimizationLevel::O0};
4349

4450
codegenoptions::DebugInfoKind noDebugInfo{codegenoptions::NoDebugInfo};

flang/lib/Optimizer/Passes/Pipelines.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ void addFIRToLLVMPass(mlir::PassManager &pm,
108108
const MLIRToLLVMPassPipelineConfig &config) {
109109
fir::FIRToLLVMPassOptions options;
110110
options.ignoreMissingTypeDescriptors = ignoreMissingTypeDescriptors;
111+
options.skipExternalRttiDefinition = skipExternalRttiDefinition;
111112
options.applyTBAA = config.AliasAnalysis;
112113
options.forceUnifiedTBAATree = useOldAliasTags;
113114
options.typeDescriptorsRenamedForAssembly =

0 commit comments

Comments
 (0)