diff options
author | Eli Bendersky <eliben@chromium.org> | 2013-07-15 16:08:08 -0700 |
---|---|---|
committer | Eli Bendersky <eliben@chromium.org> | 2013-07-15 16:08:08 -0700 |
commit | e789858899a7b36caf11b371a97411a1582a482b (patch) | |
tree | e8c28b178b32010f73b477b3c65b5ff74437530c /lib/AST/MicrosoftMangle.cpp | |
parent | 99a5501f5ae5b75017dfc386d4abf648234e85df (diff) | |
parent | 20c7d45a4da9f58ad805ad1d37f92fe7dc232ec8 (diff) |
Merge commit '20c7d45a4da9f58ad805ad1d37f92fe7dc232ec8'
Conflicts:
lib/CodeGen/ItaniumCXXABI.cpp
Diffstat (limited to 'lib/AST/MicrosoftMangle.cpp')
-rw-r--r-- | lib/AST/MicrosoftMangle.cpp | 300 |
1 files changed, 156 insertions, 144 deletions
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 8c31e57578..1785063d7b 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -59,6 +59,8 @@ class MicrosoftCXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } public: + enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result }; + MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) : Context(C), Out(Out_), Structor(0), StructorType(-1), @@ -78,7 +80,8 @@ public: void mangleVariableEncoding(const VarDecl *VD); void mangleNumber(int64_t Number); void mangleNumber(const llvm::APSInt &Value); - void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true); + void mangleType(QualType T, SourceRange Range, + QualifierMangleMode QMM = QMM_Mangle); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -95,7 +98,7 @@ private: void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleTemplateInstantiationName(const TemplateDecl *TD, - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs); + const TemplateArgumentList &TemplateArgs); void mangleObjCMethodName(const ObjCMethodDecl *MD); void mangleLocalName(const FunctionDecl *FD); @@ -112,18 +115,18 @@ private: #undef TYPE void mangleType(const TagType*); - void mangleType(const FunctionType *T, const FunctionDecl *D, - bool IsStructor, bool IsInstMethod); - void mangleType(const ArrayType *T, bool IsGlobal); - void mangleExtraDimensions(QualType T); + void mangleFunctionType(const FunctionType *T, const FunctionDecl *D, + bool IsStructor, bool IsInstMethod); + void mangleDecayedArrayType(const ArrayType *T, bool IsGlobal); + void mangleArrayType(const ArrayType *T, Qualifiers Quals); void mangleFunctionClass(const FunctionDecl *FD); void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); void mangleExpression(const Expr *E); void mangleThrowSpecification(const FunctionProtoType *T); - void mangleTemplateArgs( - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs); + void mangleTemplateArgs(const TemplateDecl *TD, + const TemplateArgumentList &TemplateArgs); }; @@ -264,7 +267,7 @@ void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // First, the function class. mangleFunctionClass(FD); - mangleType(FT, FD, InStructor, InInstMethod); + mangleFunctionType(FT, FD, InStructor, InInstMethod); } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { @@ -297,14 +300,17 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc(); QualType Ty = TL.getType(); if (Ty->isPointerType() || Ty->isReferenceType()) { - mangleType(Ty, TL.getSourceRange()); + mangleType(Ty, TL.getSourceRange(), QMM_Drop); mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { // Global arrays are funny, too. - mangleType(AT, true); - mangleQualifiers(Ty.getQualifiers(), false); + mangleDecayedArrayType(AT, true); + if (AT->getElementType()->isArrayType()) + Out << 'A'; + else + mangleQualifiers(Ty.getQualifiers(), false); } else { - mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange()); + mangleType(Ty, TL.getSourceRange(), QMM_Drop); mangleQualifiers(Ty.getLocalQualifiers(), false); } } @@ -367,47 +373,19 @@ void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { } static const TemplateDecl * -isTemplate(const NamedDecl *ND, - SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { +isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { // Check if we have a function template. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){ if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { - if (FD->getTemplateSpecializationArgsAsWritten()) { - const ASTTemplateArgumentListInfo *ArgList = - FD->getTemplateSpecializationArgsAsWritten(); - TemplateArgs.append(ArgList->getTemplateArgs(), - ArgList->getTemplateArgs() + - ArgList->NumTemplateArgs); - } else { - const TemplateArgumentList *ArgList = - FD->getTemplateSpecializationArgs(); - TemplateArgumentListInfo LI; - for (unsigned i = 0, e = ArgList->size(); i != e; ++i) - TemplateArgs.push_back(TemplateArgumentLoc(ArgList->get(i), - FD->getTypeSourceInfo())); - } + TemplateArgs = FD->getTemplateSpecializationArgs(); return TD; } } // Check if we have a class template. if (const ClassTemplateSpecializationDecl *Spec = - dyn_cast<ClassTemplateSpecializationDecl>(ND)) { - TypeSourceInfo *TSI = Spec->getTypeAsWritten(); - if (TSI) { - TemplateSpecializationTypeLoc TSTL = - TSI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>(); - TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc()); - for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i) - TemplateArgs.push_back(TSTL.getArgLoc(i)); - } else { - TemplateArgumentListInfo LI; - const TemplateArgumentList &ArgList = - Spec->getTemplateArgs(); - for (unsigned i = 0, e = ArgList.size(); i != e; ++i) - TemplateArgs.push_back(TemplateArgumentLoc(ArgList[i], - TemplateArgumentLocInfo())); - } + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); return Spec->getSpecializedTemplate(); } @@ -421,8 +399,9 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // ::= <ctor-dtor-name> // ::= <source-name> // ::= <template-name> - SmallVector<TemplateArgumentLoc, 2> TemplateArgs; + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { // We have a template. // Here comes the tricky thing: if we need to mangle something like @@ -452,7 +431,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, Found = NameBackReferences.find(BackReferenceKey); } if (!UseNameBackReferences || Found == NameBackReferences.end()) { - mangleTemplateInstantiationName(TD, TemplateArgs); + mangleTemplateInstantiationName(TD, *TemplateArgs); if (UseNameBackReferences && NameBackReferences.size() < 10) { size_t Size = NameBackReferences.size(); NameBackReferences[BackReferenceKey] = Size; @@ -786,7 +765,7 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) { void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( const TemplateDecl *TD, - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { + const TemplateArgumentList &TemplateArgs) { // <template-name> ::= <unscoped-template-name> <template-args> // ::= <substitution> // Always start with the unqualified name. @@ -798,7 +777,7 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( TypeBackReferences.swap(OuterArgsContext); mangleUnscopedTemplateName(TD); - mangleTemplateArgs(TemplateArgs); + mangleTemplateArgs(TD, TemplateArgs); // Restore the previous back reference contexts. NameBackReferences.swap(OuterTemplateContext); @@ -842,18 +821,22 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) { } void -MicrosoftCXXNameMangler::mangleTemplateArgs( - const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { +MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD, + const TemplateArgumentList &TemplateArgs) { // <template-args> ::= {<type> | <integer-literal>}+ @ unsigned NumTemplateArgs = TemplateArgs.size(); for (unsigned i = 0; i < NumTemplateArgs; ++i) { - const TemplateArgumentLoc &TAL = TemplateArgs[i]; - const TemplateArgument &TA = TAL.getArgument(); + const TemplateArgument &TA = TemplateArgs[i]; switch (TA.getKind()) { case TemplateArgument::Null: llvm_unreachable("Can't mangle null template arguments!"); - case TemplateArgument::Type: - mangleType(TA.getAsType(), TAL.getSourceRange()); + case TemplateArgument::Type: { + QualType T = TA.getAsType(); + mangleType(T, SourceRange(), QMM_Escape); + break; + } + case TemplateArgument::Declaration: + mangle(cast<NamedDecl>(TA.getAsDecl()), "$1?"); break; case TemplateArgument::Integral: mangleIntegerLiteral(TA.getAsIntegral(), @@ -864,18 +847,18 @@ MicrosoftCXXNameMangler::mangleTemplateArgs( break; case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - case TemplateArgument::Declaration: case TemplateArgument::NullPtr: case TemplateArgument::Pack: { // Issue a diagnostic. DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|" - "integral|template|template pack expansion|ERROR|parameter pack}0 " - "template argument yet"); - Diags.Report(TAL.getLocation(), DiagID) + "cannot mangle template argument %0 of kind %select{ERROR|ERROR|" + "pointer/reference|nullptr|integral|template|template pack expansion|" + "ERROR|parameter pack}1 yet"); + Diags.Report(TD->getLocation(), DiagID) + << i + 1 << TA.getKind() - << TAL.getSourceRange(); + << TD->getSourceRange(); } } } @@ -989,7 +972,14 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, if (Found == TypeBackReferences.end()) { size_t OutSizeBefore = Out.GetNumBytesInBuffer(); - mangleType(T, Range, false); + if (const ArrayType *AT = getASTContext().getAsArrayType(T)) { + mangleDecayedArrayType(AT, false); + } else if (const FunctionType *FT = T->getAs<FunctionType>()) { + Out << "P6"; + mangleFunctionType(FT, 0, false, false); + } else { + mangleType(T, Range, QMM_Drop); + } // See if it's worth creating a back reference. // Only types longer than 1 character are considered @@ -1005,28 +995,53 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, } void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, - bool MangleQualifiers) { + QualifierMangleMode QMM) { // Only operate on the canonical type! T = getASTContext().getCanonicalType(T); - Qualifiers Quals = T.getLocalQualifiers(); - // We have to mangle these now, while we still have enough information. - if (T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType()) { - manglePointerQualifiers(Quals); - } else if (Quals && MangleQualifiers) { - mangleQualifiers(Quals, false); + + if (const ArrayType *AT = dyn_cast<ArrayType>(T)) { + if (QMM == QMM_Mangle) + Out << 'A'; + else if (QMM == QMM_Escape || QMM == QMM_Result) + Out << "$$B"; + mangleArrayType(AT, Quals); + return; } - SplitQualType split = T.split(); - const Type *ty = split.Ty; + bool IsPointer = T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType(); - // If we're mangling a qualified array type, push the qualifiers to - // the element type. - if (split.Quals && isa<ArrayType>(T)) { - ty = Context.getASTContext().getAsArrayType(T); + switch (QMM) { + case QMM_Drop: + break; + case QMM_Mangle: + if (const FunctionType *FT = dyn_cast<FunctionType>(T)) { + Out << '6'; + mangleFunctionType(FT, 0, false, false); + return; + } + mangleQualifiers(Quals, false); + break; + case QMM_Escape: + if (!IsPointer && Quals) { + Out << "$$C"; + mangleQualifiers(Quals, false); + } + break; + case QMM_Result: + if ((!IsPointer && Quals) || isa<TagType>(T)) { + Out << '?'; + mangleQualifiers(Quals, false); + } + break; } + // We have to mangle these now, while we still have enough information. + if (IsPointer) + manglePointerQualifiers(Quals); + const Type *ty = T.getTypePtr(); + switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ @@ -1136,17 +1151,17 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, // structor type. // FIXME: This may not be lambda-friendly. Out << "$$A6"; - mangleType(T, NULL, false, false); + mangleFunctionType(T, NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, SourceRange) { llvm_unreachable("Can't mangle K&R function prototypes"); } -void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, - const FunctionDecl *D, - bool IsStructor, - bool IsInstMethod) { +void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, + const FunctionDecl *D, + bool IsStructor, + bool IsInstMethod) { // <function-type> ::= <this-cvr-qualifiers> <calling-convention> // <return-type> <argument-list> <throw-spec> const FunctionProtoType *Proto = cast<FunctionProtoType>(T); @@ -1172,21 +1187,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, } Out << '@'; } else { - QualType Result = Proto->getResultType(); - const Type* RT = Result.getTypePtr(); - if (!RT->isAnyPointerType() && !RT->isReferenceType()) { - if (Result.hasQualifiers() || !RT->isBuiltinType()) - Out << '?'; - if (!RT->isBuiltinType() && !Result.hasQualifiers()) { - // Lack of qualifiers for user types is mangled as 'A'. - Out << 'A'; - } - } - - // FIXME: Get the source range for the result type. Or, better yet, - // implement the unimplemented stuff so we don't need accurate source - // location info anymore :). - mangleType(Result, SourceRange()); + mangleType(Proto->getResultType(), SourceRange(), QMM_Result); } // <argument-list> ::= X # void @@ -1381,7 +1382,8 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { // It's supposed to be the other way around, but for some strange reason, it // isn't. Today this behavior is retained for the sole purpose of backwards // compatibility. -void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { +void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T, + bool IsGlobal) { // This isn't a recursive mangling, so now we have to do it all in this // one call. if (IsGlobal) { @@ -1389,25 +1391,27 @@ void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { } else { Out << 'Q'; } - mangleExtraDimensions(T->getElementType()); + mangleType(T->getElementType(), SourceRange()); } void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } -void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { +void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T, + Qualifiers Quals) { + QualType ElementTy(T, 0); SmallVector<llvm::APInt, 3> Dimensions; for (;;) { if (const ConstantArrayType *CAT = @@ -1433,20 +1437,20 @@ void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID) << DSAT->getBracketsRange(); return; - } else if (ElementTy->isIncompleteArrayType()) continue; - else break; - } - mangleQualifiers(ElementTy.getQualifiers(), false); - // If there are any additional dimensions, mangle them now. - if (Dimensions.size() > 0) { - Out << 'Y'; - // <dimension-count> ::= <number> # number of extra dimensions - mangleNumber(Dimensions.size()); - for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) { - mangleNumber(Dimensions[Dim].getLimitedValue()); + } else if (const IncompleteArrayType *IAT = + getASTContext().getAsIncompleteArrayType(ElementTy)) { + Dimensions.push_back(llvm::APInt(32, 0)); + ElementTy = IAT->getElementType(); } + else break; } - mangleType(ElementTy.getLocalUnqualifiedType(), SourceRange()); + Out << 'Y'; + // <dimension-count> ::= <number> # number of extra dimensions + mangleNumber(Dimensions.size()); + for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) + mangleNumber(Dimensions[Dim].getLimitedValue()); + mangleType(getASTContext().getQualifiedType(ElementTy.getTypePtr(), Quals), + SourceRange(), QMM_Escape); } // <type> ::= <pointer-to-member-type> @@ -1458,11 +1462,11 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) { Out << '8'; mangleName(T->getClass()->castAs<RecordType>()->getDecl()); - mangleType(FPT, NULL, false, true); + mangleFunctionType(FPT, NULL, false, true); } else { mangleQualifiers(PointeeType.getQualifiers(), true); mangleName(T->getClass()->castAs<RecordType>()->getDecl()); - mangleType(PointeeType.getLocalUnqualifiedType(), Range); + mangleType(PointeeType, Range, QMM_Drop); } } @@ -1490,17 +1494,7 @@ void MicrosoftCXXNameMangler::mangleType( void MicrosoftCXXNameMangler::mangleType(const PointerType *T, SourceRange Range) { QualType PointeeTy = T->getPointeeType(); - if (PointeeTy->isArrayType()) { - // Pointers to arrays are mangled like arrays. - mangleExtraDimensions(PointeeTy); - } else if (const FunctionType *FT = PointeeTy->getAs<FunctionType>()) { - // Function pointers are special. - Out << '6'; - mangleType(FT, NULL, false, false); - } else { - mangleQualifiers(PointeeTy.getQualifiers(), false); - mangleType(PointeeTy, Range, false); - } + mangleType(PointeeTy, Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, SourceRange Range) { @@ -1514,11 +1508,7 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, SourceRange Range) { Out << 'A'; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleType(T->getPointeeType(), Range); } // <type> ::= <r-value-reference-type> @@ -1526,11 +1516,7 @@ void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, SourceRange Range) { Out << "$$Q"; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleType(T->getPointeeType(), Range); } void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, @@ -1544,12 +1530,38 @@ void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, void MicrosoftCXXNameMangler::mangleType(const VectorType *T, SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this vector type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; + const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>(); + assert(ET && "vectors with non-builtin elements are unsupported"); + uint64_t Width = getASTContext().getTypeSize(T); + // Pattern match exactly the typedefs in our intrinsic headers. Anything that + // doesn't match the Intel types uses a custom mangling below. + bool IntelVector = true; + if (Width == 64 && ET->getKind() == BuiltinType::LongLong) { + Out << "T__m64"; + } else if (Width == 128 || Width == 256) { + if (ET->getKind() == BuiltinType::Float) + Out << "T__m" << Width; + else if (ET->getKind() == BuiltinType::LongLong) + Out << "T__m" << Width << 'i'; + else if (ET->getKind() == BuiltinType::Double) + Out << "U__m" << Width << 'd'; + else + IntelVector = false; + } else { + IntelVector = false; + } + + if (!IntelVector) { + // The MS ABI doesn't have a special mangling for vector types, so we define + // our own mangling to handle uses of __vector_size__ on user-specified + // types, and for extensions like __v4sf. + Out << "T__clang_vec" << T->getNumElements() << '_'; + mangleType(ET, Range); + } + + Out << "@@"; } + void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); @@ -1586,7 +1598,7 @@ void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, Out << "_E"; QualType pointee = T->getPointeeType(); - mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false); + mangleFunctionType(pointee->castAs<FunctionProtoType>(), NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T, |