teak-llvm/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
Zachary Turner 38d2edd60d [MS Demangler] Add output flags to all function calls.
Previously we had a FunctionSigFlags, but it's more flexible
to just have one set of output flags that apply to the entire
process and just pipe the entire set of flags through the
output process.

This will be useful when we start allowing the user to customize
the outputting behavior.

llvm-svn: 340894
2018-08-29 03:59:17 +00:00

604 lines
20 KiB
C++

//===- MicrosoftDemangle.cpp ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a demangler for MSVC-style mangled symbols.
//
//===----------------------------------------------------------------------===//
#include "MicrosoftDemangleNodes.h"
#include "llvm/Demangle/Compiler.h"
#include "llvm/Demangle/Utility.h"
#include <cctype>
using namespace llvm;
using namespace ms_demangle;
#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
case Enum::Value: \
OS << Desc; \
break;
// Writes a space if the last token does not end with a punctuation.
static void outputSpaceIfNecessary(OutputStream &OS) {
if (OS.empty())
return;
char C = OS.back();
if (std::isalnum(C) || C == '>')
OS << " ";
}
static bool outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
switch (Q) {
case Q_Const:
OS << "const";
return true;
case Q_Volatile:
OS << "volatile";
return true;
case Q_Restrict:
OS << "__restrict";
return true;
default:
break;
}
return false;
}
static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
Qualifiers Mask, bool NeedSpace) {
if (!(Q & Mask))
return NeedSpace;
if (NeedSpace)
OS << " ";
outputSingleQualifier(OS, Mask);
return true;
}
static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
bool SpaceAfter) {
if (Q == Q_None)
return;
size_t Pos1 = OS.getCurrentPosition();
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
size_t Pos2 = OS.getCurrentPosition();
if (SpaceAfter && Pos2 > Pos1)
OS << " ";
}
static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
outputSpaceIfNecessary(OS);
switch (CC) {
case CallingConv::Cdecl:
OS << "__cdecl";
break;
case CallingConv::Fastcall:
OS << "__fastcall";
break;
case CallingConv::Pascal:
OS << "__pascal";
break;
case CallingConv::Regcall:
OS << "__regcall";
break;
case CallingConv::Stdcall:
OS << "__stdcall";
break;
case CallingConv::Thiscall:
OS << "__thiscall";
break;
case CallingConv::Eabi:
OS << "__eabi";
break;
case CallingConv::Vectorcall:
OS << "__vectorcall";
break;
case CallingConv::Clrcall:
OS << "__clrcall";
break;
default:
break;
}
}
void TypeNode::outputQuals(bool SpaceBefore, bool SpaceAfter) const {}
void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
switch (PrimKind) {
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
}
outputQualifiers(OS, Quals, true, false);
}
void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
output(OS, Flags, ", ");
}
void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
StringView Separator) const {
if (Count == 0)
return;
if (Nodes[0])
Nodes[0]->output(OS, Flags);
for (size_t I = 1; I < Count; ++I) {
OS << Separator;
Nodes[I]->output(OS, Flags);
}
}
void EncodedStringLiteralNode::output(OutputStream &OS,
OutputFlags Flags) const {
switch (Char) {
case CharKind::Wchar:
OS << "const wchar_t * {L\"";
break;
case CharKind::Char:
OS << "const char * {\"";
break;
case CharKind::Char16:
OS << "const char16_t * {u\"";
break;
case CharKind::Char32:
OS << "const char32_t * {U\"";
break;
}
OS << DecodedString << "\"";
if (IsTruncated)
OS << "...";
OS << "}";
}
void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
if (IsNegative)
OS << '-';
OS << Value;
}
void TemplateParameterReferenceNode::output(OutputStream &OS,
OutputFlags Flags) const {
if (ThunkOffsetCount > 0)
OS << "{";
else if (Affinity == PointerAffinity::Pointer)
OS << "&";
if (Symbol) {
Symbol->output(OS, Flags);
if (ThunkOffsetCount > 0)
OS << ", ";
}
if (ThunkOffsetCount > 0)
OS << ThunkOffsets[0];
for (int I = 1; I < ThunkOffsetCount; ++I) {
OS << ", " << ThunkOffsets[I];
}
if (ThunkOffsetCount > 0)
OS << "}";
}
void IdentifierNode::outputTemplateParameters(OutputStream &OS,
OutputFlags Flags) const {
if (!TemplateParams)
return;
OS << "<";
TemplateParams->output(OS, Flags);
OS << ">";
}
void DynamicStructorIdentifierNode::output(OutputStream &OS,
OutputFlags Flags) const {
if (IsDestructor)
OS << "`dynamic atexit destructor for ";
else
OS << "`dynamic initializer for ";
OS << "'";
Name->output(OS, Flags);
OS << "''";
}
void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
OS << Name;
outputTemplateParameters(OS, Flags);
}
void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
OutputFlags Flags) const {
switch (Operator) {
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
"operator[]");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
"operator->*");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
"operator>=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
"operator&=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
"operator|=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
"operator^=");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
"`vector deleting dtor'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
"`default ctor closure'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
"`scalar deleting dtor'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
"`vector ctor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
"`vector dtor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
"`vector vbase ctor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
"`virtual displacement map'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
"`eh vector ctor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
"`eh vector dtor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
"`eh vector vbase ctor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
"`copy ctor closure'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
"`local vftable ctor closure'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
"operator delete[]");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
"`managed vector ctor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
"`managed vector dtor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
"`EH vector copy ctor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
"`EH vector vbase copy ctor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
"`vector copy ctor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
"`vector vbase copy constructor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
"`managed vector vbase copy constructor iterator'");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait, "co_await");
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator <=>");
case IntrinsicFunctionKind::MaxIntrinsic:
case IntrinsicFunctionKind::None:
break;
}
outputTemplateParameters(OS, Flags);
}
void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
OutputFlags Flags) const {
OS << "`local static guard'";
if (ScopeIndex > 0)
OS << "{" << ScopeIndex << "}";
}
void ConversionOperatorIdentifierNode::output(OutputStream &OS,
OutputFlags Flags) const {
OS << "operator";
outputTemplateParameters(OS, Flags);
OS << " ";
TargetType->output(OS, Flags);
}
void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
if (IsDestructor)
OS << "~";
Class->output(OS, Flags);
outputTemplateParameters(OS, Flags);
}
void LiteralOperatorIdentifierNode::output(OutputStream &OS,
OutputFlags Flags) const {
OS << "operator \"\"" << Name;
outputTemplateParameters(OS, Flags);
}
void FunctionSignatureNode::outputPre(OutputStream &OS,
OutputFlags Flags) const {
if (!(FunctionClass & FC_Global)) {
if (FunctionClass & FC_Static)
OS << "static ";
}
if (FunctionClass & FC_ExternC)
OS << "extern \"C\" ";
if (FunctionClass & FC_Virtual)
OS << "virtual ";
if (ReturnType) {
ReturnType->outputPre(OS, Flags);
OS << " ";
}
if (!(Flags & OF_NoCallingConvention))
outputCallingConvention(OS, CallConvention);
}
void FunctionSignatureNode::outputPost(OutputStream &OS,
OutputFlags Flags) const {
if (!(FunctionClass & FC_NoParameterList)) {
OS << "(";
if (Params)
Params->output(OS, Flags);
else
OS << "void";
OS << ")";
}
if (Quals & Q_Const)
OS << " const";
if (Quals & Q_Volatile)
OS << " volatile";
if (Quals & Q_Restrict)
OS << " __restrict";
if (Quals & Q_Unaligned)
OS << " __unaligned";
if (RefQualifier == FunctionRefQualifier::Reference)
OS << " &";
else if (RefQualifier == FunctionRefQualifier::RValueReference)
OS << " &&";
if (ReturnType)
ReturnType->outputPost(OS, Flags);
}
void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
OS << "[thunk]: ";
FunctionSignatureNode::outputPre(OS, Flags);
}
void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
if (FunctionClass & FC_StaticThisAdjust) {
OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
} else if (FunctionClass & FC_VirtualThisAdjust) {
if (FunctionClass & FC_VirtualThisAdjustEx) {
OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
<< ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
<< ", " << ThisAdjust.StaticOffset << "}'";
} else {
OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
<< ThisAdjust.StaticOffset << "}'";
}
}
FunctionSignatureNode::outputPost(OS, Flags);
}
void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
if (Pointee->kind() == NodeKind::FunctionSignature) {
// If this is a pointer to a function, don't output the calling convention.
// It needs to go inside the parentheses.
const FunctionSignatureNode *Sig =
static_cast<const FunctionSignatureNode *>(Pointee);
Sig->outputPre(OS, OF_NoCallingConvention);
} else
Pointee->outputPre(OS, Flags);
outputSpaceIfNecessary(OS);
if (Quals & Q_Unaligned)
OS << "__unaligned ";
if (Pointee->kind() == NodeKind::ArrayType) {
OS << "(";
} else if (Pointee->kind() == NodeKind::FunctionSignature) {
OS << "(";
const FunctionSignatureNode *Sig =
static_cast<const FunctionSignatureNode *>(Pointee);
outputCallingConvention(OS, Sig->CallConvention);
OS << " ";
}
if (ClassParent) {
ClassParent->output(OS, Flags);
OS << "::";
}
switch (Affinity) {
case PointerAffinity::Pointer:
OS << "*";
break;
case PointerAffinity::Reference:
OS << "&";
break;
case PointerAffinity::RValueReference:
OS << "&&";
break;
default:
assert(false);
}
outputQualifiers(OS, Quals, false, false);
}
void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
if (Pointee->kind() == NodeKind::ArrayType ||
Pointee->kind() == NodeKind::FunctionSignature)
OS << ")";
Pointee->outputPost(OS, Flags);
}
void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
switch (Tag) {
OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct");
OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
}
OS << " ";
QualifiedName->output(OS, Flags);
outputQualifiers(OS, Quals, true, false);
}
void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
ElementType->outputPre(OS, Flags);
outputQualifiers(OS, Quals, true, false);
}
void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
Node *N) const {
assert(N->kind() == NodeKind::IntegerLiteral);
IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
if (ILN->Value != 0)
ILN->output(OS, Flags);
}
void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
OutputFlags Flags) const {
if (Dimensions->Count == 0)
return;
outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
for (size_t I = 1; I < Dimensions->Count; ++I) {
OS << "][";
outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
}
}
void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
OS << "[";
outputDimensionsImpl(OS, Flags);
OS << "]";
ElementType->outputPost(OS, Flags);
}
void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
Name->output(OS, Flags);
}
void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
Signature->outputPre(OS, Flags);
outputSpaceIfNecessary(OS);
Name->output(OS, Flags);
Signature->outputPost(OS, Flags);
}
void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
switch (SC) {
case StorageClass::PrivateStatic:
case StorageClass::PublicStatic:
case StorageClass::ProtectedStatic:
OS << "static ";
default:
break;
}
if (Type) {
Type->outputPre(OS, Flags);
outputSpaceIfNecessary(OS);
}
Name->output(OS, Flags);
if (Type)
Type->outputPost(OS, Flags);
}
void CustomNode::output(OutputStream &OS, OutputFlags Flags) const {
OS << Name;
}
void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
Components->output(OS, Flags, "::");
}
void RttiBaseClassDescriptorNode::output(OutputStream &OS,
OutputFlags Flags) const {
OS << "`RTTI Base Class Descriptor at (";
OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
<< this->Flags;
OS << ")'";
}
void LocalStaticGuardVariableNode::output(OutputStream &OS,
OutputFlags Flags) const {
Name->output(OS, Flags);
}
void VcallThunkIdentifierNode::output(OutputStream &OS,
OutputFlags Flags) const {
OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
}
void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
outputQualifiers(OS, Quals, false, true);
Name->output(OS, Flags);
if (TargetName) {
OS << "{for `";
TargetName->output(OS, Flags);
OS << "'}";
}
return;
}