Index: llvm/include/llvm/Support/YAMLTraits.h =================================================================== --- llvm/include/llvm/Support/YAMLTraits.h +++ llvm/include/llvm/Support/YAMLTraits.h @@ -902,24 +902,7 @@ template <typename T, typename Context> void processKeyWithDefault(const char *Key, Optional<T> &Val, const Optional<T> &DefaultValue, bool Required, - Context &Ctx) { - assert(DefaultValue.hasValue() == false && - "Optional<T> shouldn't have a value!"); - void *SaveInfo; - bool UseDefault = true; - const bool sameAsDefault = outputting() && !Val.hasValue(); - if (!outputting() && !Val.hasValue()) - Val = T(); - if (Val.hasValue() && - this->preflightKey(Key, Required, sameAsDefault, UseDefault, - SaveInfo)) { - yamlize(*this, Val.getValue(), Required, Ctx); - this->postflightKey(SaveInfo); - } else { - if (UseDefault) - Val = DefaultValue; - } - } + Context &Ctx); template <typename T, typename Context> void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue, @@ -1625,6 +1608,40 @@ StringRef PaddingBeforeContainer; }; +template <typename T, typename Context> +void IO::processKeyWithDefault(const char *Key, Optional<T> &Val, + const Optional<T> &DefaultValue, bool Required, + Context &Ctx) { + assert(DefaultValue.hasValue() == false && + "Optional<T> shouldn't have a value!"); + void *SaveInfo; + bool UseDefault = true; + const bool sameAsDefault = outputting() && !Val.hasValue(); + if (!outputting() && !Val.hasValue()) + Val = T(); + if (Val.hasValue() && + this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) { + + // When reading an Optional<X> key from a YAML description, we allow the + // special "<none>" value, which can be used to specify that no value was + // requested, i.e. the DefaultValue will be assigned. The DefaultValue is + // usually None. + bool IsNone = false; + if (!outputting()) + if (auto *Node = dyn_cast<ScalarNode>(((Input *)this)->getCurrentNode())) + IsNone = Node->getRawValue() == "<none>"; + + if (IsNone) + Val = DefaultValue; + else + yamlize(*this, Val.getValue(), Required, Ctx); + this->postflightKey(SaveInfo); + } else { + if (UseDefault) + Val = DefaultValue; + } +} + /// YAML I/O does conversion based on types. But often native data types /// are just a typedef of built in intergral types (e.g. int). But the C++ /// type matching system sees through the typedef and all the typedefed types Index: llvm/test/tools/yaml2obj/ELF/none-value.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/ELF/none-value.yaml @@ -0,0 +1,262 @@ +## We have a special "<none>" value for all keys that are implemented +## as Optional<> in the code. Setting a key to "<none>" means no-op and +## works in the same way as when a value was not set at all. + +# RUN: yaml2obj %s --docnum=1 -o %t-none +# RUN: yaml2obj %s --docnum=2 -o %t-base +# RUN: cmp %t-none %t-base + +## Test all keys for which the "<none>" value is supported. + +## We do not use the TEST macro. It is exist to +## demonstrate the expected use case for the <none> word. +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + EShEntSize: [[TEST=<none>]] + EShOff: [[TEST=<none>]] + EShNum: [[TEST=<none>]] + EShStrNdx: [[TEST=<none>]] + EPhOff: [[TEST=<none>]] + EPhEntSize: [[TEST=<none>]] + EPhNum: [[TEST=<none>]] +Sections: + - Name: .bar + Type: SHT_PROGBITS + Offset: [[TEST=<none>]] + Address: [[TEST=<none>]] + Content: [[TEST=<none>]] + Size: [[TEST=<none>]] + ContentArray: [[TEST=<none>]] + Info: [[TEST=<none>]] + EntSize: [[TEST=<none>]] + ShName: [[TEST=<none>]] + ShOffset: [[TEST=<none>]] + ShSize: [[TEST=<none>]] + ShFlags: [[TEST=<none>]] + - Type: Fill + Pattern: [[TEST=<none>]] + Size: 0x3 + - Name: .cgp + Type: SHT_LLVM_CALL_GRAPH_PROFILE + Content: [[TEST=<none>]] + Entries: [[TEST=<none>]] + - Name: .dynamic + Type: SHT_DYNAMIC + Content: [[TEST=<none>]] +## Note: for SHT_NOTE sections, one of "Content", "Size" or "Notes" must be specified. + - Name: .note.1 + Type: SHT_NOTE + Content: [[TEST=<none>]] + Size: 1 + Notes: [[TEST=<none>]] + - Name: .note.2 + Type: SHT_NOTE + Content: "1122" + Size: [[TEST=<none>]] +## Note: for SHT_HASH sections, one of "Content", "Size", "Bucket" or "Chain" must be specified. + - Name: .hash.1 + Type: SHT_HASH + Content: [[TEST=<none>]] + Size: 1 + Bucket: [[TEST=<none>]] + Chain: [[TEST=<none>]] + NBucket: [[TEST=<none>]] + NChain: [[TEST=<none>]] + - Name: .hash.2 + Type: SHT_HASH + Content: "1122" + Size: [[TEST=<none>]] +## Note: for SHT_GNU_HASH sections either "Content" or "Header", "BloomFilter", "HashBuckets" and +## "HashBuckets" must be specified. + - Name: .gnu.hash.1 + Type: SHT_GNU_HASH + Content: "00" + Header: [[TEST=<none>]] + BloomFilter: [[TEST=<none>]] + HashBuckets: [[TEST=<none>]] + HashValues: [[TEST=<none>]] + - Name: .gnu.hash.2 + Type: SHT_GNU_HASH + Content: [[TEST=<none>]] + BloomFilter: [] + HashBuckets: [] + HashValues: [] + Header: + SymNdx: 0x0 + Shift2: 0x0 + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Info: 0x0 + Dependencies: [[TEST=<none>]] + Content: [[TEST=<none>]] + - Name: .gnu.version_d + Info: 0x0 + Type: SHT_GNU_verdef + Entries: [[TEST=<none>]] + Content: [[TEST=<none>]] +## Note: for SHT_LLVM_ADDRSIG sections one of "Content", "Size" or "Symbols" must be specified. + - Name: .llvm_addrsig.1 + Type: SHT_LLVM_ADDRSIG + Content: "1122" + Size: [[TEST=<none>]] + Symbols: [[TEST=<none>]] + - Name: .llvm_addrsig.2 + Type: SHT_LLVM_ADDRSIG + Content: [[TEST=<none>]] + Size: 1 + - Name: .linker-options + Type: SHT_LLVM_LINKER_OPTIONS + Content: [[TEST=<none>]] + Options: [[TEST=<none>]] + - Name: .deplibs + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [[TEST=<none>]] + Content: [[TEST=<none>]] + - Name: .group + Type: SHT_GROUP + Info: [[TEST=<none>]] + Members: [] + - Name: .rela + Type: SHT_RELA + Relocations: + - Type: R_X86_64_NONE + Symbol: [[TEST=<none>]] + - Name: .relr + Type: SHT_RELR + Entries: [[TEST=<none>]] + Content: [[TEST=<none>]] +ProgramHeaders: + - Type: PT_LOAD + Align: [[TEST=<none>]] + FileSize: [[TEST=<none>]] + MemSize: [[TEST=<none>]] + Offset: [[TEST=<none>]] +Symbols: + - Name: foo + Other: [[TEST=<none>]] + StName: [[TEST=<none>]] +SectionHeaderTable: + Sections: + - Name: .bar + - Name: .cgp + - Name: .symtab + - Name: .strtab + - Name: .shstrtab + - Name: .dynamic + - Name: .note.1 + - Name: .note.2 + - Name: .hash.1 + - Name: .hash.2 + - Name: .gnu.hash.1 + - Name: .gnu.hash.2 + - Name: .gnu.version_r + - Name: .gnu.version_d + - Name: .llvm_addrsig.1 + - Name: .llvm_addrsig.2 + - Name: .linker-options + - Name: .deplibs + - Name: .group + - Name: .rela + - Name: .relr + NoHeaders: [[TEST=<none>]] + +## The same document, but all fields that were set to <none> are removed. +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .bar + Type: SHT_PROGBITS + - Type: Fill + Size: 0x3 + - Name: .cgp + Type: SHT_LLVM_CALL_GRAPH_PROFILE + - Name: .dynamic + Type: SHT_DYNAMIC +## Note: for SHT_NOTE sections, one of "Content", "Size" or "Notes" must be specified. + - Name: .note.1 + Type: SHT_NOTE + Size: 1 + - Name: .note.2 + Type: SHT_NOTE + Content: "1122" +## Note: for SHT_HASH sections, one of "Content", "Size", "Bucket" or "Chain" must be specified. + - Name: .hash.1 + Type: SHT_HASH + Size: 1 + - Name: .hash.2 + Type: SHT_HASH + Content: "1122" +## Note: for SHT_GNU_HASH sections either "Content" or "Header", "BloomFilter", "HashBuckets" and +## "HashBuckets" must be specified. + - Name: .gnu.hash.1 + Type: SHT_GNU_HASH + Content: "00" + - Name: .gnu.hash.2 + Type: SHT_GNU_HASH + BloomFilter: [] + HashBuckets: [] + HashValues: [] + Header: + SymNdx: 0x0 + Shift2: 0x0 + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Info: 0x0 + - Name: .gnu.version_d + Info: 0x0 + Type: SHT_GNU_verdef +## Note: for SHT_LLVM_ADDRSIG sections one of "Content", "Size" or "Symbols" must be specified. + - Name: .llvm_addrsig.1 + Type: SHT_LLVM_ADDRSIG + Content: "1122" + - Name: .llvm_addrsig.2 + Type: SHT_LLVM_ADDRSIG + Size: 1 + - Name: .linker-options + Type: SHT_LLVM_LINKER_OPTIONS + - Name: .deplibs + Type: SHT_LLVM_DEPENDENT_LIBRARIES + - Name: .group + Type: SHT_GROUP + Members: [] + - Name: .rela + Type: SHT_RELA + Relocations: + - Type: R_X86_64_NONE + - Name: .relr + Type: SHT_RELR +ProgramHeaders: + - Type: PT_LOAD +Symbols: + - Name: foo +SectionHeaderTable: + Sections: + - Name: .bar + - Name: .cgp + - Name: .symtab + - Name: .strtab + - Name: .shstrtab + - Name: .dynamic + - Name: .note.1 + - Name: .note.2 + - Name: .hash.1 + - Name: .hash.2 + - Name: .gnu.hash.1 + - Name: .gnu.hash.2 + - Name: .gnu.version_r + - Name: .gnu.version_d + - Name: .llvm_addrsig.1 + - Name: .llvm_addrsig.2 + - Name: .linker-options + - Name: .deplibs + - Name: .group + - Name: .rela + - Name: .relr