Skip to content

Commit

Permalink
Add CFI integer types normalization
Browse files Browse the repository at this point in the history
This commit adds a new option (i.e.,
`-fsanitize-cfi-icall-normalize-integers`) for normalizing integer types
as vendor extended types for cross-language LLVM CFI/KCFI support with
other languages that can't represent and encode C/C++ integer types.

Specifically, integer types are encoded as their defined representations
(e.g., 8-bit signed integer, 16-bit signed integer, 32-bit signed
integer, ...) for compatibility with languages that define
explicitly-sized integer types (e.g., i8, i16, i32, ..., in Rust).

``-fsanitize-cfi-icall-normalize-integers`` is compatible with
``-fsanitize-cfi-icall-generalize-pointers``.

This helps with providing cross-language CFI support with the Rust
compiler and is an alternative solution for the issue described and
alternatives proposed in the RFC
rust-lang/rfcs#3296.

For more information about LLVM CFI/KCFI and cross-language LLVM
CFI/KCFI support for the Rust compiler, see the design document in the
tracking issue rust-lang/rust#89653.

Relands b1e9ab7 with fixes.

Reviewed By: pcc, samitolvanen

Differential Revision: https://reviews.llvm.org/D139395
  • Loading branch information
rcvalle authored and veselypeta committed Aug 15, 2024
2 parents 556a958 + 71c7313 commit 84955ae
Show file tree
Hide file tree
Showing 13 changed files with 300 additions and 16 deletions.
19 changes: 19 additions & 0 deletions clang/docs/ControlFlowIntegrity.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,25 @@ long as the qualifiers for the type they point to match. For example, ``char*``,
``-fsanitize-cfi-icall-generalize-pointers`` is not compatible with
``-fsanitize-cfi-cross-dso``.

.. _cfi-icall-experimental-normalize-integers:

``-fsanitize-cfi-icall-experimental-normalize-integers``
--------------------------------------------------------

This option enables normalizing integer types as vendor extended types for
cross-language LLVM CFI/KCFI support with other languages that can't represent
and encode C/C++ integer types.

Specifically, integer types are encoded as their defined representations (e.g.,
8-bit signed integer, 16-bit signed integer, 32-bit signed integer, ...) for
compatibility with languages that define explicitly-sized integer types (e.g.,
i8, i16, i32, ..., in Rust).

``-fsanitize-cfi-icall-experimental-normalize-integers`` is compatible with
``-fsanitize-cfi-icall-generalize-pointers``.

This option is currently experimental.

.. _cfi-canonical-jump-tables:

``-fsanitize-cfi-canonical-jump-tables``
Expand Down
8 changes: 8 additions & 0 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1992,6 +1992,14 @@ are listed below.
checked by Control Flow Integrity indirect call checking. See
:doc:`ControlFlowIntegrity` for more details.

.. option:: -fsanitize-cfi-icall-experimental-normalize-integers

Normalize integers in return and argument types in function type signatures
checked by Control Flow Integrity indirect call checking. See
:doc:`ControlFlowIntegrity` for more details.

This option is currently experimental.

.. option:: -fstrict-vtable-pointers

Enable optimizations based on the strict rules for overwriting polymorphic
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/AST/Mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ class MangleContext {
unsigned ManglingNumber,
raw_ostream &) = 0;
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
virtual void mangleCXXRTTIName(QualType T, raw_ostream &,
bool NormalizeIntegers = false) = 0;
virtual void mangleStringLiteral(const StringLiteral *SL, raw_ostream &) = 0;
virtual void mangleMSGuidDecl(const MSGuidDecl *GD, raw_ostream&);

Expand Down Expand Up @@ -177,7 +178,8 @@ class MangleContext {
/// or type uniquing.
/// TODO: Extend this to internal types by generating names that are unique
/// across translation units so it can be used with LTO.
virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
virtual void mangleTypeName(QualType T, raw_ostream &,
bool NormalizeIntegers = false) = 0;

/// @}
};
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime f
///< diagnostics.
CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in
///< CFI icall function signatures
CODEGENOPT(SanitizeCfiICallNormalizeIntegers, 1, 0) ///< Normalize integer types in
///< CFI icall function signatures
CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical
///< instead of creating a local jump table.
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,10 @@ def fsanitize_cfi_icall_generalize_pointers : Flag<["-"], "fsanitize-cfi-icall-g
Group<f_clang_Group>,
HelpText<"Generalize pointers in CFI indirect call type signature checks">,
MarshallingInfoFlag<CodeGenOpts<"SanitizeCfiICallGeneralizePointers">>;
def fsanitize_cfi_icall_normalize_integers : Flag<["-"], "fsanitize-cfi-icall-experimental-normalize-integers">,
Group<f_clang_Group>,
HelpText<"Normalize integers in CFI indirect call type signature checks">,
MarshallingInfoFlag<CodeGenOpts<"SanitizeCfiICallNormalizeIntegers">>;
defm sanitize_cfi_canonical_jump_tables : BoolOption<"f", "sanitize-cfi-canonical-jump-tables",
CodeGenOpts<"SanitizeCfiCanonicalJumpTables">, DefaultFalse,
PosFlag<SetTrue, [], "Make">, NegFlag<SetFalse, [CoreOption, NoXarchOption], "Do not make">,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Driver/SanitizerArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class SanitizerArgs {
bool MsanParamRetval = true;
bool CfiCrossDso = false;
bool CfiICallGeneralizePointers = false;
bool CfiICallNormalizeIntegers = false;
bool CfiCanonicalJumpTables = false;
int AsanFieldPadding = 0;
bool SharedRuntime = false;
Expand Down
104 changes: 97 additions & 7 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type, raw_ostream &) override;
void mangleCXXRTTI(QualType T, raw_ostream &) override;
void mangleCXXRTTIName(QualType T, raw_ostream &) override;
void mangleTypeName(QualType T, raw_ostream &) override;
void mangleCXXRTTIName(QualType T, raw_ostream &,
bool NormalizeIntegers) override;
void mangleTypeName(QualType T, raw_ostream &,
bool NormalizeIntegers) override;

void mangleCXXCtorComdat(const CXXConstructorDecl *D, raw_ostream &) override;
void mangleCXXDtorComdat(const CXXDestructorDecl *D, raw_ostream &) override;
Expand Down Expand Up @@ -221,6 +223,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
class CXXNameMangler {
ItaniumMangleContextImpl &Context;
raw_ostream &Out;
/// Normalize integer types for cross-language CFI support with other
/// languages that can't represent and encode C/C++ integer types.
bool NormalizeIntegers = false;

bool NullOut = false;
/// In the "DisableDerivedAbiTags" mode derived ABI tags are not calculated.
/// This mode is used when mangler creates another mangler recursively to
Expand Down Expand Up @@ -419,6 +425,10 @@ class CXXNameMangler {
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
AbiTagsRoot(AbiTags) {}

CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
bool NormalizeIntegers_)
: Context(C), Out(Out_), NormalizeIntegers(NormalizeIntegers_),
NullOut(false), Structor(nullptr), AbiTagsRoot(AbiTags) {}
CXXNameMangler(CXXNameMangler &Outer, raw_ostream &Out_)
: Context(Outer.Context), Out(Out_), Structor(Outer.Structor),
StructorType(Outer.StructorType), SeqID(Outer.SeqID),
Expand Down Expand Up @@ -2944,6 +2954,85 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
// ::= u <source-name> # vendor extended type
std::string type_name;
// Normalize integer types as vendor extended types:
// u<length>i<type size>
// u<length>u<type size>
if (NormalizeIntegers && T->isInteger()) {
if (T->isSignedInteger()) {
switch (getASTContext().getTypeSize(T)) {
case 8:
// Pick a representative for each integer size in the substitution
// dictionary. (Its actual defined size is not relevant.)
if (mangleSubstitution(BuiltinType::SChar))
break;
Out << "u2i8";
addSubstitution(BuiltinType::SChar);
break;
case 16:
if (mangleSubstitution(BuiltinType::Short))
break;
Out << "u3i16";
addSubstitution(BuiltinType::Short);
break;
case 32:
if (mangleSubstitution(BuiltinType::Int))
break;
Out << "u3i32";
addSubstitution(BuiltinType::Int);
break;
case 64:
if (mangleSubstitution(BuiltinType::Long))
break;
Out << "u3i64";
addSubstitution(BuiltinType::Long);
break;
case 128:
if (mangleSubstitution(BuiltinType::Int128))
break;
Out << "u4i128";
addSubstitution(BuiltinType::Int128);
break;
default:
llvm_unreachable("Unknown integer size for normalization");
}
} else {
switch (getASTContext().getTypeSize(T)) {
case 8:
if (mangleSubstitution(BuiltinType::UChar))
break;
Out << "u2u8";
addSubstitution(BuiltinType::UChar);
break;
case 16:
if (mangleSubstitution(BuiltinType::UShort))
break;
Out << "u3u16";
addSubstitution(BuiltinType::UShort);
break;
case 32:
if (mangleSubstitution(BuiltinType::UInt))
break;
Out << "u3u32";
addSubstitution(BuiltinType::UInt);
break;
case 64:
if (mangleSubstitution(BuiltinType::ULong))
break;
Out << "u3u64";
addSubstitution(BuiltinType::ULong);
break;
case 128:
if (mangleSubstitution(BuiltinType::UInt128))
break;
Out << "u4u128";
addSubstitution(BuiltinType::UInt128);
break;
default:
llvm_unreachable("Unknown integer size for normalization");
}
}
return;
}
switch (T->getKind()) {
case BuiltinType::Void:
Out << 'v';
Expand Down Expand Up @@ -6552,16 +6641,17 @@ void ItaniumMangleContextImpl::mangleCXXRTTI(QualType Ty, raw_ostream &Out) {
Mangler.mangleType(Ty);
}

void ItaniumMangleContextImpl::mangleCXXRTTIName(QualType Ty,
raw_ostream &Out) {
void ItaniumMangleContextImpl::mangleCXXRTTIName(
QualType Ty, raw_ostream &Out, bool NormalizeIntegers = false) {
// <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
CXXNameMangler Mangler(*this, Out);
CXXNameMangler Mangler(*this, Out, NormalizeIntegers);
Mangler.getStream() << "_ZTS";
Mangler.mangleType(Ty);
}

void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) {
mangleCXXRTTIName(Ty, Out);
void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out,
bool NormalizeIntegers = false) {
mangleCXXRTTIName(Ty, Out, NormalizeIntegers);
}

void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_ostream &) {
Expand Down
13 changes: 8 additions & 5 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
int32_t VBPtrOffset, uint32_t VBIndex,
raw_ostream &Out) override;
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIName(QualType T, raw_ostream &Out,
bool NormalizeIntegers) override;
void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBTableOffset, uint32_t Flags,
Expand All @@ -193,7 +194,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
mangleCXXRTTICompleteObjectLocator(const CXXRecordDecl *Derived,
ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) override;
void mangleTypeName(QualType T, raw_ostream &) override;
void mangleTypeName(QualType T, raw_ostream &,
bool NormalizeIntegers) override;
void mangleReferenceTemporary(const VarDecl *, unsigned ManglingNumber,
raw_ostream &) override;
void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out) override;
Expand Down Expand Up @@ -3597,8 +3599,8 @@ void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &Out) {
Mangler.getStream() << "@8";
}

void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T,
raw_ostream &Out) {
void MicrosoftMangleContextImpl::mangleCXXRTTIName(
QualType T, raw_ostream &Out, bool NormalizeIntegers = false) {
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << '.';
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
Expand Down Expand Up @@ -3765,7 +3767,8 @@ void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(
Mangler.mangleName(EnclosingDecl);
}

void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
void MicrosoftMangleContextImpl::mangleTypeName(
QualType T, raw_ostream &Out, bool NormalizeIntegers = false) {
// This is just a made up unique string for the purposes of tbaa. undname
// does *not* know how to demangle it.
MicrosoftCXXNameMangler Mangler(*this, Out);
Expand Down
13 changes: 11 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1820,7 +1820,11 @@ llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T) {

std::string OutName;
llvm::raw_string_ostream Out(OutName);
getCXXABI().getMangleContext().mangleTypeName(T, Out);
getCXXABI().getMangleContext().mangleTypeName(
T, Out, getCodeGenOpts().SanitizeCfiICallNormalizeIntegers);

if (getCodeGenOpts().SanitizeCfiICallNormalizeIntegers)
Out << ".normalized";

return llvm::ConstantInt::get(Int32Ty,
static_cast<uint32_t>(llvm::xxHash64(OutName)));
Expand Down Expand Up @@ -7057,7 +7061,12 @@ CodeGenModule::CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
if (isExternallyVisible(T->getLinkage())) {
std::string OutName;
llvm::raw_string_ostream Out(OutName);
getCXXABI().getMangleContext().mangleTypeName(T, Out);
getCXXABI().getMangleContext().mangleTypeName(
T, Out, getCodeGenOpts().SanitizeCfiICallNormalizeIntegers);

if (getCodeGenOpts().SanitizeCfiICallNormalizeIntegers)
Out << ".normalized";

Out << Suffix;

InternalId = llvm::MDString::get(getLLVMContext(), Out.str());
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
CfiICallGeneralizePointers =
Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);

CfiICallNormalizeIntegers =
Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);

if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< "-fsanitize-cfi-cross-dso"
Expand Down Expand Up @@ -1218,6 +1221,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (CfiICallGeneralizePointers)
CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");

if (CfiICallNormalizeIntegers)
CmdArgs.push_back("-fsanitize-cfi-icall-experimental-normalize-integers");

if (CfiCanonicalJumpTables)
CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables");

Expand Down
78 changes: 78 additions & 0 deletions clang/test/CodeGen/cfi-icall-normalize.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fsanitize-cfi-icall-experimental-normalize-integers -emit-llvm -o - %s | FileCheck %s

// Test that integer types are normalized for cross-language CFI support with
// other languages that can't represent and encode C/C++ integer types.

void foo0(char arg) { }
// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}}
void foo1(char arg1, signed char arg2) { }
// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
void foo2(char arg1, signed char arg2, signed char arg3) { }
// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
void foo3(int arg) { }
// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
void foo4(int arg1, int arg2) { }
// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}}
void foo5(int arg1, int arg2, int arg3) { }
// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}}
void foo6(long arg) { }
// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}}
void foo7(long arg1, long long arg2) { }
// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}}
void foo8(long arg1, long long arg2, long long arg3) { }
// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}}
void foo9(short arg) { }
// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}}
void foo10(short arg1, short arg2) { }
// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}}
void foo11(short arg1, short arg2, short arg3) { }
// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}}
void foo12(unsigned char arg) { }
// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}}
void foo13(unsigned char arg1, unsigned char arg2) { }
// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}}
void foo14(unsigned char arg1, unsigned char arg2, unsigned char arg3) { }
// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}}
void foo15(unsigned int arg) { }
// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}}
void foo16(unsigned int arg1, unsigned int arg2) { }
// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}}
void foo17(unsigned int arg1, unsigned int arg2, unsigned int arg3) { }
// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}}
void foo18(unsigned long arg) { }
// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}}
void foo19(unsigned long arg1, unsigned long long arg2) { }
// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}}
void foo20(unsigned long arg1, unsigned long long arg2, unsigned long long arg3) { }
// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}}
void foo21(unsigned short arg) { }
// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}}
void foo22(unsigned short arg1, unsigned short arg2) { }
// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}}
void foo23(unsigned short arg1, unsigned short arg2, unsigned short arg3) { }
// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}}

// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvu2i8E.normalized"}
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu2i8S_E.normalized"}
// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu2i8S_S_E.normalized"}
// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3i32E.normalized"}
// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3i32S_E.normalized"}
// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3i32S_S_E.normalized"}
// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3i64E.normalized"}
// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3i64S_E.normalized"}
// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3i64S_S_E.normalized"}
// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3i16E.normalized"}
// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3i16S_E.normalized"}
// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3i16S_S_E.normalized"}
// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu2u8E.normalized"}
// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2u8S_E.normalized"}
// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2u8S_S_E.normalized"}
// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3u32E.normalized"}
// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3u32S_E.normalized"}
// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3u32S_S_E.normalized"}
// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3u64E.normalized"}
// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3u64S_E.normalized"}
// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3u64S_S_E.normalized"}
// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3u16E.normalized"}
// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3u16S_E.normalized"}
// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3u16S_S_E.normalized"}
Loading

0 comments on commit 84955ae

Please sign in to comment.