From: Francis Visoiu Mistrih Date: Mon, 18 Dec 2017 17:38:03 +0000 (+0000) Subject: [YAML] Add support for non-printable characters X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b213b27ee3cba7d0b7ad2a45c8cbd42e59510220;p=platform%2Fupstream%2Fllvm.git [YAML] Add support for non-printable characters LLVM IR function names which disable mangling start with '\01' (https://www.llvm.org/docs/LangRef.html#identifiers). When an identifier like "\01@abc@" gets dumped to MIR, it is quoted, but only with single quotes. http://www.yaml.org/spec/1.2/spec.html#id2770814: "The allowed character range explicitly excludes the C0 control block allowed), the surrogate block #xD800-#xDFFF, #xFFFE, and #xFFFF." http://www.yaml.org/spec/1.2/spec.html#id2776092: "All non-printable characters must be escaped. [...] Note that escape sequences are only interpreted in double-quoted scalars." This patch adds support for printing escaped non-printable characters between double quotes if needed. Should also fix PR31743. Differential Revision: https://reviews.llvm.org/D41290 llvm-svn: 320996 --- diff --git a/llvm/docs/YamlIO.rst b/llvm/docs/YamlIO.rst index 0b728ed..4c07820 100644 --- a/llvm/docs/YamlIO.rst +++ b/llvm/docs/YamlIO.rst @@ -466,7 +466,7 @@ looks like: return StringRef(); } // Determine if this scalar needs quotes. - static bool mustQuote(StringRef) { return true; } + static QuotingType mustQuote(StringRef) { return QuotingType::Single; } }; Block Scalars diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h index a8ea140..ba40e52 100644 --- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h +++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h @@ -56,7 +56,7 @@ template <> struct ScalarTraits { return ""; } - static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); } + static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } }; struct FlowStringValue : StringValue { @@ -73,7 +73,7 @@ template <> struct ScalarTraits { return ScalarTraits::input(Scalar, Ctx, S); } - static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); } + static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } }; struct BlockStringValue { @@ -120,7 +120,7 @@ template <> struct ScalarTraits { return ScalarTraits::input(Scalar, Ctx, Value.Value); } - static bool mustQuote(StringRef Scalar) { + static QuotingType mustQuote(StringRef Scalar) { return ScalarTraits::mustQuote(Scalar); } }; diff --git a/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypeHashing.h b/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypeHashing.h index 50a1160..4f0d9ef 100644 --- a/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypeHashing.h +++ b/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypeHashing.h @@ -56,7 +56,7 @@ ArrayRef toDebugH(const DebugHSection &DebugH, } // end namespace llvm LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::DebugHSection) -LLVM_YAML_DECLARE_SCALAR_TRAITS(CodeViewYAML::GlobalHash, false) +LLVM_YAML_DECLARE_SCALAR_TRAITS(CodeViewYAML::GlobalHash, QuotingType::None) LLVM_YAML_IS_SEQUENCE_VECTOR(CodeViewYAML::GlobalHash) #endif // LLVM_OBJECTYAML_CODEVIEWYAMLTYPES_H diff --git a/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypes.h b/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypes.h index 1128ac9..bc3b556 100644 --- a/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypes.h +++ b/llvm/include/llvm/ObjectYAML/CodeViewYAMLTypes.h @@ -58,7 +58,7 @@ ArrayRef toDebugT(ArrayRef, BumpPtrAllocator &Alloc); } // end namespace llvm -LLVM_YAML_DECLARE_SCALAR_TRAITS(codeview::GUID, true) +LLVM_YAML_DECLARE_SCALAR_TRAITS(codeview::GUID, QuotingType::Single) LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::LeafRecord) LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::MemberRecord) diff --git a/llvm/include/llvm/ObjectYAML/MachOYAML.h b/llvm/include/llvm/ObjectYAML/MachOYAML.h index b84c093..1fa8f92 100644 --- a/llvm/include/llvm/ObjectYAML/MachOYAML.h +++ b/llvm/include/llvm/ObjectYAML/MachOYAML.h @@ -261,7 +261,7 @@ using char_16 = char[16]; template <> struct ScalarTraits { static void output(const char_16 &Val, void *, raw_ostream &Out); static StringRef input(StringRef Scalar, void *, char_16 &Val); - static bool mustQuote(StringRef S); + static QuotingType mustQuote(StringRef S); }; // This trait is used for UUIDs. It reads and writes them matching otool's @@ -271,7 +271,7 @@ using uuid_t = raw_ostream::uuid_t; template <> struct ScalarTraits { static void output(const uuid_t &Val, void *, raw_ostream &Out); static StringRef input(StringRef Scalar, void *, uuid_t &Val); - static bool mustQuote(StringRef S); + static QuotingType mustQuote(StringRef S); }; // Load Command struct mapping traits diff --git a/llvm/include/llvm/ObjectYAML/YAML.h b/llvm/include/llvm/ObjectYAML/YAML.h index 29151a2..93266dd 100644 --- a/llvm/include/llvm/ObjectYAML/YAML.h +++ b/llvm/include/llvm/ObjectYAML/YAML.h @@ -107,7 +107,7 @@ inline bool operator==(const BinaryRef &LHS, const BinaryRef &RHS) { template <> struct ScalarTraits { static void output(const BinaryRef &, void *, raw_ostream &); static StringRef input(StringRef, void *, BinaryRef &); - static bool mustQuote(StringRef S) { return needsQuotes(S); } + static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } }; } // end namespace yaml diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h index 71fdf47..83b097a 100644 --- a/llvm/include/llvm/Support/YAMLTraits.h +++ b/llvm/include/llvm/Support/YAMLTraits.h @@ -12,6 +12,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -117,6 +118,11 @@ struct ScalarBitSetTraits { // static void bitset(IO &io, T &value); }; +/// Describe which type of quotes should be used when quoting is necessary. +/// Some non-printable characters need to be double-quoted, while some others +/// are fine with simple-quoting, and some don't need any quoting. +enum class QuotingType { None, Single, Double }; + /// This class should be specialized by type that requires custom conversion /// to/from a yaml scalar. For example: /// @@ -131,7 +137,7 @@ struct ScalarBitSetTraits { /// // return empty string on success, or error string /// return StringRef(); /// } -/// static bool mustQuote(StringRef) { return true; } +/// static QuotingType mustQuote(StringRef) { return QuotingType::Single; } /// }; template struct ScalarTraits { @@ -145,7 +151,7 @@ struct ScalarTraits { //static StringRef input(StringRef scalar, void *ctxt, T &value); // // Function to determine if the value should be quoted. - //static bool mustQuote(StringRef); + //static QuotingType mustQuote(StringRef); }; /// This class should be specialized by type that requires custom conversion @@ -270,7 +276,7 @@ struct has_ScalarTraits { using Signature_input = StringRef (*)(StringRef, void*, T&); using Signature_output = void (*)(const T&, void*, raw_ostream&); - using Signature_mustQuote = bool (*)(StringRef); + using Signature_mustQuote = QuotingType (*)(StringRef); template static char test(SameType *, @@ -495,28 +501,66 @@ inline bool isBool(StringRef S) { S.equals("false") || S.equals("False") || S.equals("FALSE"); } -inline bool needsQuotes(StringRef S) { +// 5.1. Character Set +// The allowed character range explicitly excludes the C0 control block #x0-#x1F +// (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1 +// control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate +// block #xD800-#xDFFF, #xFFFE, and #xFFFF. +inline QuotingType needsQuotes(StringRef S) { if (S.empty()) - return true; + return QuotingType::Single; if (isspace(S.front()) || isspace(S.back())) - return true; + return QuotingType::Single; if (S.front() == ',') - return true; - - static const char ScalarSafeChars[] = - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t"; - if (S.find_first_not_of(ScalarSafeChars) != StringRef::npos) - return true; - + return QuotingType::Single; if (isNull(S)) - return true; + return QuotingType::Single; if (isBool(S)) - return true; + return QuotingType::Single; if (isNumeric(S)) - return true; + return QuotingType::Single; + + QuotingType MaxQuotingNeeded = QuotingType::None; + for (unsigned char C : S) { + // Alphanum is safe. + if (isAlnum(C)) + continue; + + switch (C) { + // Safe scalar characters. + case '_': + case '-': + case '/': + case '^': + case '.': + case ',': + case ' ': + // TAB (0x9), LF (0xA), CR (0xD) and NEL (0x85) are allowed. + case 0x9: + case 0xA: + case 0xD: + case 0x85: + continue; + // DEL (0x7F) are excluded from the allowed character range. + case 0x7F: + return QuotingType::Double; + default: { + // C0 control block (0x0 - 0x1F) is excluded from the allowed character + // range. + if (C <= 0x1F) + return QuotingType::Double; + // C1 control block (0x80 - 0x9F) is excluded from the allowed character + // range. + if (C >= 0x80 && C <= 0x9F) + return QuotingType::Double; + + // The character is not safe, at least simple quoting needed. + MaxQuotingNeeded = QuotingType::Single; + } + } + } - return false; + return MaxQuotingNeeded; } template @@ -581,7 +625,7 @@ public: virtual bool bitSetMatch(const char*, bool) = 0; virtual void endBitSetScalar() = 0; - virtual void scalarString(StringRef &, bool) = 0; + virtual void scalarString(StringRef &, QuotingType) = 0; virtual void blockScalarString(StringRef &) = 0; virtual void setError(const Twine &) = 0; @@ -911,91 +955,91 @@ template<> struct ScalarTraits { static void output(const bool &, void* , raw_ostream &); static StringRef input(StringRef, void *, bool &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const StringRef &, void *, raw_ostream &); static StringRef input(StringRef, void *, StringRef &); - static bool mustQuote(StringRef S) { return needsQuotes(S); } + static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } }; template<> struct ScalarTraits { static void output(const std::string &, void *, raw_ostream &); static StringRef input(StringRef, void *, std::string &); - static bool mustQuote(StringRef S) { return needsQuotes(S); } + static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } }; template<> struct ScalarTraits { static void output(const uint8_t &, void *, raw_ostream &); static StringRef input(StringRef, void *, uint8_t &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const uint16_t &, void *, raw_ostream &); static StringRef input(StringRef, void *, uint16_t &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const uint32_t &, void *, raw_ostream &); static StringRef input(StringRef, void *, uint32_t &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const uint64_t &, void *, raw_ostream &); static StringRef input(StringRef, void *, uint64_t &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const int8_t &, void *, raw_ostream &); static StringRef input(StringRef, void *, int8_t &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const int16_t &, void *, raw_ostream &); static StringRef input(StringRef, void *, int16_t &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const int32_t &, void *, raw_ostream &); static StringRef input(StringRef, void *, int32_t &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const int64_t &, void *, raw_ostream &); static StringRef input(StringRef, void *, int64_t &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const float &, void *, raw_ostream &); static StringRef input(StringRef, void *, float &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const double &, void *, raw_ostream &); static StringRef input(StringRef, void *, double &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; // For endian types, we just use the existing ScalarTraits for the underlying @@ -1019,7 +1063,7 @@ struct ScalarTraits::mustQuote(Str); } }; @@ -1148,7 +1192,7 @@ private: bool beginBitSetScalar(bool &) override; bool bitSetMatch(const char *, bool ) override; void endBitSetScalar() override; - void scalarString(StringRef &, bool) override; + void scalarString(StringRef &, QuotingType) override; void blockScalarString(StringRef &) override; void setError(const Twine &message) override; bool canElideEmptySequence() override; @@ -1293,7 +1337,7 @@ public: bool beginBitSetScalar(bool &) override; bool bitSetMatch(const char *, bool ) override; void endBitSetScalar() override; - void scalarString(StringRef &, bool) override; + void scalarString(StringRef &, QuotingType) override; void blockScalarString(StringRef &) override; void setError(const Twine &message) override; bool canElideEmptySequence() override; @@ -1371,28 +1415,28 @@ template<> struct ScalarTraits { static void output(const Hex8 &, void *, raw_ostream &); static StringRef input(StringRef, void *, Hex8 &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const Hex16 &, void *, raw_ostream &); static StringRef input(StringRef, void *, Hex16 &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const Hex32 &, void *, raw_ostream &); static StringRef input(StringRef, void *, Hex32 &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template<> struct ScalarTraits { static void output(const Hex64 &, void *, raw_ostream &); static StringRef input(StringRef, void *, Hex64 &); - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; // Define non-member operator>> so that Input can stream in a document list. @@ -1681,7 +1725,7 @@ template struct StdMapStringCustomMappingTraitsImpl { template <> struct ScalarTraits { \ static void output(const Type &Value, void *ctx, raw_ostream &Out); \ static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \ - static bool mustQuote(StringRef) { return MustQuote; } \ + static QuotingType mustQuote(StringRef) { return MustQuote; } \ }; \ } \ } diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp index 60b0ea2..6debd8a 100644 --- a/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp +++ b/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp @@ -66,7 +66,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport) LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport) LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData) -LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, false) +LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, QuotingType::None) LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind) LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind) LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags) diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp index dbe4e2a..199a65a 100644 --- a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp +++ b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp @@ -42,8 +42,8 @@ using namespace llvm::yaml; LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(TypeIndex) // We only need to declare these, the definitions are in CodeViewYAMLTypes.cpp -LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, false) -LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, false) +LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, QuotingType::None) +LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, QuotingType::None) LLVM_YAML_DECLARE_ENUM_TRAITS(SymbolKind) LLVM_YAML_DECLARE_ENUM_TRAITS(FrameCookieKind) @@ -62,7 +62,7 @@ LLVM_YAML_DECLARE_ENUM_TRAITS(ThunkOrdinal) LLVM_YAML_STRONG_TYPEDEF(StringRef, TypeName) -LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeName, true) +LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeName, QuotingType::Single) StringRef ScalarTraits::input(StringRef S, void *V, TypeName &T) { return ScalarTraits::input(S, V, T.value); diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp index 887328c..ba4ad93 100644 --- a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp +++ b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp @@ -48,8 +48,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(OneMethodRecord) LLVM_YAML_IS_SEQUENCE_VECTOR(VFTableSlotKind) LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(TypeIndex) -LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, false) -LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, false) +LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, QuotingType::None) +LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, QuotingType::None) LLVM_YAML_DECLARE_ENUM_TRAITS(TypeLeafKind) LLVM_YAML_DECLARE_ENUM_TRAITS(PointerToMemberRepresentation) diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp index 85079f2..e00a4ea 100644 --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -52,7 +52,9 @@ StringRef ScalarTraits::input(StringRef Scalar, void *, char_16 &Val) { return StringRef(); } -bool ScalarTraits::mustQuote(StringRef S) { return needsQuotes(S); } +QuotingType ScalarTraits::mustQuote(StringRef S) { + return needsQuotes(S); +} void ScalarTraits::output(const uuid_t &Val, void *, raw_ostream &Out) { Out.write_uuid(Val); @@ -75,7 +77,9 @@ StringRef ScalarTraits::input(StringRef Scalar, void *, uuid_t &Val) { return StringRef(); } -bool ScalarTraits::mustQuote(StringRef S) { return needsQuotes(S); } +QuotingType ScalarTraits::mustQuote(StringRef S) { + return needsQuotes(S); +} void MappingTraits::mapping( IO &IO, MachOYAML::FileHeader &FileHdr) { diff --git a/llvm/lib/Support/Statistic.cpp b/llvm/lib/Support/Statistic.cpp index 23718bb..544ae2d 100644 --- a/llvm/lib/Support/Statistic.cpp +++ b/llvm/lib/Support/Statistic.cpp @@ -168,9 +168,10 @@ void llvm::PrintStatisticsJSON(raw_ostream &OS) { const char *delim = ""; for (const Statistic *Stat : Stats.Stats) { OS << delim; - assert(!yaml::needsQuotes(Stat->getDebugType()) && + assert(yaml::needsQuotes(Stat->getDebugType()) == yaml::QuotingType::None && "Statistic group/type name is simple."); - assert(!yaml::needsQuotes(Stat->getName()) && "Statistic name is simple"); + assert(yaml::needsQuotes(Stat->getName()) == yaml::QuotingType::None && + "Statistic name is simple"); OS << "\t\"" << Stat->getDebugType() << '.' << Stat->getName() << "\": " << Stat->getValue(); delim = ",\n"; diff --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp index 3386f26..0c85fae 100644 --- a/llvm/lib/Support/Timer.cpp +++ b/llvm/lib/Support/Timer.cpp @@ -362,8 +362,10 @@ void TimerGroup::printAll(raw_ostream &OS) { void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R, const char *suffix, double Value) { - assert(!yaml::needsQuotes(Name) && "TimerGroup name needs no quotes"); - assert(!yaml::needsQuotes(R.Name) && "Timer name needs no quotes"); + assert(yaml::needsQuotes(Name) == yaml::QuotingType::None && + "TimerGroup name needs no quotes"); + assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None && + "Timer name needs no quotes"); OS << "\t\"time." << Name << '.' << R.Name << suffix << "\": " << Value; } diff --git a/llvm/lib/Support/YAMLTraits.cpp b/llvm/lib/Support/YAMLTraits.cpp index a80adfd..05ca40f 100644 --- a/llvm/lib/Support/YAMLTraits.cpp +++ b/llvm/lib/Support/YAMLTraits.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Unicode.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" #include @@ -330,7 +331,7 @@ void Input::endBitSetScalar() { } } -void Input::scalarString(StringRef &S, bool) { +void Input::scalarString(StringRef &S, QuotingType) { if (ScalarHNode *SN = dyn_cast(CurrentNode)) { S = SN->value(); } else { @@ -338,7 +339,7 @@ void Input::scalarString(StringRef &S, bool) { } } -void Input::blockScalarString(StringRef &S) { scalarString(S, false); } +void Input::blockScalarString(StringRef &S) { scalarString(S, QuotingType::None); } void Input::setError(HNode *hnode, const Twine &message) { assert(hnode && "HNode must not be NULL"); @@ -617,7 +618,7 @@ void Output::endBitSetScalar() { this->outputUpToEndOfLine(" ]"); } -void Output::scalarString(StringRef &S, bool MustQuote) { +void Output::scalarString(StringRef &S, QuotingType MustQuote) { this->newLineCheck(); if (S.empty()) { // Print '' for the empty string because leaving the field empty is not @@ -625,27 +626,52 @@ void Output::scalarString(StringRef &S, bool MustQuote) { this->outputUpToEndOfLine("''"); return; } - if (!MustQuote) { + if (MustQuote == QuotingType::None) { // Only quote if we must. this->outputUpToEndOfLine(S); return; } + unsigned i = 0; unsigned j = 0; unsigned End = S.size(); - output("'"); // Starting single quote. const char *Base = S.data(); + + const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\""; + const char QuoteChar = MustQuote == QuotingType::Single ? '\'' : '"'; + + output(Quote); // Starting quote. + + // When using single-quoted strings, any single quote ' must be doubled to be + // escaped. + // When using double-quoted strings, print \x + hex for non-printable ASCII + // characters, and escape double quotes. while (j < End) { - // Escape a single quote by doubling it. - if (S[j] == '\'') { - output(StringRef(&Base[i], j - i + 1)); - output("'"); + if (S[j] == QuoteChar) { // Escape quotes. + output(StringRef(&Base[i], j - i)); // "flush". + if (MustQuote == QuotingType::Double) { // Print it as \" + output(StringLiteral("\\")); + output(StringRef(Quote, 1)); + } else { // Single + output(StringLiteral("''")); // Print it as '' + } + i = j + 1; + } else if (MustQuote == QuotingType::Double && + !sys::unicode::isPrintable(S[j])) { + output(StringRef(&Base[i], j - i)); // "flush" + output(StringLiteral("\\x")); + + // Output the byte 0x0F as \x0f. + auto FormattedHex = format_hex_no_prefix(S[j], 2); + Out << FormattedHex; + Column += 4; // one for the '\', one for the 'x', and two for the hex + i = j + 1; } ++j; } output(StringRef(&Base[i], j - i)); - this->outputUpToEndOfLine("'"); // Ending single quote. + this->outputUpToEndOfLine(Quote); // Ending quote. } void Output::blockScalarString(StringRef &S) { diff --git a/llvm/test/CodeGen/MIR/X86/escape-function-name.ll b/llvm/test/CodeGen/MIR/X86/escape-function-name.ll new file mode 100644 index 0000000..8ef6874 --- /dev/null +++ b/llvm/test/CodeGen/MIR/X86/escape-function-name.ll @@ -0,0 +1,6 @@ +; RUN: llc -mtriple=x86_64-unknown-unknown -stop-after branch-folder -o - %s 2>&1 | FileCheck %s + +define void @"\01?f@@YAXXZ"() { +; CHECK: name: "\x01?f@@YAXXZ" + ret void +} diff --git a/llvm/tools/dsymutil/DebugMap.h b/llvm/tools/dsymutil/DebugMap.h index 2bdd333..3b5b437 100644 --- a/llvm/tools/dsymutil/DebugMap.h +++ b/llvm/tools/dsymutil/DebugMap.h @@ -232,7 +232,7 @@ template <> struct MappingTraits { template <> struct ScalarTraits { static void output(const Triple &val, void *, raw_ostream &out); static StringRef input(StringRef scalar, void *, Triple &value); - static bool mustQuote(StringRef) { return true; } + static QuotingType mustQuote(StringRef) { return QuotingType::Single; } }; template <> diff --git a/llvm/unittests/Support/YAMLIOTest.cpp b/llvm/unittests/Support/YAMLIOTest.cpp index 120773a..9caff85 100644 --- a/llvm/unittests/Support/YAMLIOTest.cpp +++ b/llvm/unittests/Support/YAMLIOTest.cpp @@ -860,7 +860,7 @@ namespace yaml { return "malformed by"; } } - static bool mustQuote(StringRef) { return true; } + static QuotingType mustQuote(StringRef) { return QuotingType::Single; } }; } } @@ -1064,7 +1064,7 @@ namespace yaml { return StringRef(); } - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template <> struct ScalarTraits { @@ -1075,7 +1075,9 @@ namespace yaml { static StringRef input(StringRef S, void *Ctx, MyString &V) { return Impl::input(S, Ctx, V.value); } - static bool mustQuote(StringRef S) { return Impl::mustQuote(S); } + static QuotingType mustQuote(StringRef S) { + return Impl::mustQuote(S); + } }; } } @@ -2232,7 +2234,7 @@ struct ScalarTraits { return ""; } - static bool mustQuote(StringRef S) { return false; } + static QuotingType mustQuote(StringRef S) { return QuotingType::None; } }; } } @@ -2455,3 +2457,87 @@ TEST(YAMLIO, InvalidInput) { yin >> Data; EXPECT_TRUE((bool)yin.error()); } + +TEST(YAMLIO, TestEscapedSingleQuote) { + std::string Id = "@abc@"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("'@abc@'", out); +} + +TEST(YAMLIO, TestEscapedNoQuote) { + std::string Id = "abc/"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("abc/", out); +} + +TEST(YAMLIO, TestEscapedDoubleQuoteNonPrintable) { + std::string Id = "\01@abc@"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("\"\\x01@abc@\"", out); +} + +TEST(YAMLIO, TestEscapedDoubleQuoteInsideSingleQuote) { + std::string Id = "abc\"fdf"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("'abc\"fdf'", out); +} + +TEST(YAMLIO, TestEscapedDoubleQuoteInsideDoubleQuote) { + std::string Id = "\01bc\"fdf"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("\"\\x01bc\\\"fdf\"", out); +} + +TEST(YAMLIO, TestEscapedSingleQuoteInsideSingleQuote) { + std::string Id = "abc'fdf"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("'abc''fdf'", out); +}