[llvm] r311215 - llvm-mt: Merge manifest namespaces.

Eric Beckmann via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 18 17:37:42 PDT 2017


Author: ecbeckmann
Date: Fri Aug 18 17:37:41 2017
New Revision: 311215

URL: http://llvm.org/viewvc/llvm-project?rev=311215&view=rev
Log:
llvm-mt: Merge manifest namespaces.

mt.exe performs a tree merge where certain element nodes are combined
into one.  This introduces the possibility of xml namespaces conflicting
with each other.  The original mt.exe has a hierarchy whereby certain
namespace names can override others, and nodes that would then end up in
ambigious namespaces have their namespaces explicitly defined.  This
namespace handles this merging process.

Added:
    llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest
    llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest
    llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest
    llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest
    llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest
    llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest
    llvm/trunk/test/tools/llvm-mt/big_merge.test
Modified:
    llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h
    llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp
    llvm/trunk/test/tools/llvm-mt/help.test
    llvm/trunk/test/tools/llvm-mt/simple_merge.test
    llvm/trunk/test/tools/llvm-mt/single_file.test
    llvm/trunk/test/tools/llvm-mt/xml_error.test
    llvm/trunk/tools/llvm-mt/llvm-mt.cpp

Modified: llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h (original)
+++ llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h Fri Aug 18 17:37:41 2017
@@ -29,21 +29,11 @@
 #include "llvm/Config/config.h"
 #include "llvm/Support/Error.h"
 
-#if LLVM_LIBXML2_ENABLED
-#include <libxml/xmlreader.h>
-#endif
-
 namespace llvm {
 
 class MemoryBuffer;
 
-#if LLVM_LIBXML2_ENABLED
-typedef xmlDocPtr XMLDocumentImpl;
-typedef xmlNodePtr XMLNodeImpl;
-#else
-typedef void *XMLDocumentImpl;
-typedef void *XMLNodeImpl;
-#endif
+namespace windows_manifest {
 
 class WindowsManifestError : public ErrorInfo<WindowsManifestError, ECError> {
 public:
@@ -57,8 +47,8 @@ private:
 
 class WindowsManifestMerger {
 public:
+  WindowsManifestMerger();
   ~WindowsManifestMerger();
-
   Error merge(const MemoryBuffer &Manifest);
 
   // Returns vector containing merged xml manifest, or uninitialized vector for
@@ -66,15 +56,10 @@ public:
   std::unique_ptr<MemoryBuffer> getMergedManifest();
 
 private:
-  static void errorCallback(void *Ctx, const char *Format, ...);
-  Error getParseError();
-
-#if LLVM_LIBXML2_ENABLED
-  XMLDocumentImpl CombinedDoc = nullptr;
-  std::vector<XMLDocumentImpl> MergedDocs;
-#endif
-  bool ParseErrorOccurred = false;
+  class WindowsManifestMergerImpl;
+  std::unique_ptr<WindowsManifestMergerImpl> Impl;
 };
 
+} // namespace windows_manifest
 } // namespace llvm
 #endif

Modified: llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp (original)
+++ llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp Fri Aug 18 17:37:41 2017
@@ -14,14 +14,17 @@
 #include "llvm/WindowsManifest/WindowsManifestMerger.h"
 #include "llvm/Support/MemoryBuffer.h"
 
-#include <stdarg.h>
+#include <map>
+
+#if LLVM_LIBXML2_ENABLED
+#include <libxml/xmlreader.h>
+#endif
 
 #define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X)
 #define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X)
 
 using namespace llvm;
-
-namespace llvm {
+using namespace windows_manifest;
 
 char WindowsManifestError::ID = 0;
 
@@ -29,177 +32,676 @@ WindowsManifestError::WindowsManifestErr
 
 void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
 
+class WindowsManifestMerger::WindowsManifestMergerImpl {
+public:
+  ~WindowsManifestMergerImpl();
+  Error merge(const MemoryBuffer &Manifest);
+  std::unique_ptr<MemoryBuffer> getMergedManifest();
+
+private:
+  static void errorCallback(void *Ctx, const char *Format, ...);
+  Error getParseError();
+#if LLVM_LIBXML2_ENABLED
+  xmlDocPtr CombinedDoc = nullptr;
+  std::vector<xmlDocPtr> MergedDocs;
+#endif
+  bool ParseErrorOccurred = false;
+};
+
 #if LLVM_LIBXML2_ENABLED
+
+static const std::pair<StringRef, StringRef> MtNsHrefsPrefixes[] = {
+    {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"},
+    {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"},
+    {"urn:schemas-microsoft-com:asm.v3", "ms_asmv3"},
+    {"http://schemas.microsoft.com/SMI/2005/WindowsSettings",
+     "ms_windowsSettings"},
+    {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}};
+
 static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
+  // Handle null pointers.  Comparison of 2 null pointers returns true because
+  // this indicates the prefix of a default namespace.
+  if (!A || !B)
+    return A == B;
   return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0;
 }
-#endif
 
-bool isMergeableElement(const unsigned char *ElementName) {
+static bool isMergeableElement(const unsigned char *ElementName) {
   for (StringRef S : {"application", "assembly", "assemblyIdentity",
                       "compatibility", "noInherit", "requestedExecutionLevel",
                       "requestedPrivileges", "security", "trustInfo"}) {
-    if (S == FROM_XML_CHAR(ElementName))
+    if (S == FROM_XML_CHAR(ElementName)) {
       return true;
+    }
   }
   return false;
 }
 
-XMLNodeImpl getChildWithName(XMLNodeImpl Parent,
-                             const unsigned char *ElementName) {
-#if LLVM_LIBXML2_ENABLED
-  for (XMLNodeImpl Child = Parent->children; Child; Child = Child->next)
+static xmlNodePtr getChildWithName(xmlNodePtr Parent,
+                                   const unsigned char *ElementName) {
+  for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
     if (xmlStringsEqual(Child->name, ElementName)) {
       return Child;
     }
-#endif
+  }
   return nullptr;
 }
 
-const unsigned char *getAttribute(XMLNodeImpl Node,
-                                  const unsigned char *AttributeName) {
-#if LLVM_LIBXML2_ENABLED
+static xmlAttrPtr getAttribute(xmlNodePtr Node,
+                               const unsigned char *AttributeName) {
   for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
        Attribute = Attribute->next) {
-    if (xmlStringsEqual(Attribute->name, AttributeName))
-      return Attribute->children->content;
+    if (xmlStringsEqual(Attribute->name, AttributeName)) {
+      return Attribute;
+    }
   }
-#endif
   return nullptr;
 }
 
-Error mergeAttributes(XMLNodeImpl OriginalNode, XMLNodeImpl AdditionalNode) {
-#if LLVM_LIBXML2_ENABLED
-  for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute != nullptr;
+// Check if namespace specified by HRef1 overrides that of HRef2.
+static bool namespaceOverrides(const unsigned char *HRef1,
+                               const unsigned char *HRef2) {
+  auto HRef1Position = llvm::find_if(
+      MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
+        return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data()));
+      });
+  auto HRef2Position = llvm::find_if(
+      MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
+        return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data()));
+      });
+  return HRef1Position < HRef2Position;
+}
+
+// Search for prefix-defined namespace specified by HRef, starting on Node and
+// continuing recursively upwards.  Returns the namespace or nullptr if not
+// found.
+static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) {
+  for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
+    if (Def->prefix && xmlStringsEqual(Def->href, HRef)) {
+      return Def;
+    }
+  }
+  if (Node->parent) {
+    return search(HRef, Node->parent);
+  }
+  return nullptr;
+}
+
+// Return the prefix that corresponds to the HRef.  If HRef is not a recognized
+// URI, then just return the HRef itself to use as the prefix.
+static const unsigned char *getPrefixForHref(const unsigned char *HRef) {
+  for (auto &Ns : MtNsHrefsPrefixes) {
+    if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data()))) {
+      return TO_XML_CHAR(Ns.second.data());
+    }
+  }
+  return HRef;
+}
+
+// Search for prefix-defined namespace specified by HRef, starting on Node and
+// continuing recursively upwards.  If it is found, then return it.  If it is
+// not found, then prefix-define that namespace on the node and return a
+// reference to it.
+static Expected<xmlNsPtr> searchOrDefine(const unsigned char *HRef,
+                                         xmlNodePtr Node) {
+  if (xmlNsPtr Def = search(HRef, Node))
+    return Def;
+  if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
+    return Def;
+  return make_error<WindowsManifestError>("failed to create new namespace");
+}
+
+// Set the namespace of OrigionalAttribute on OriginalNode to be that of
+// AdditionalAttribute's.
+static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
+                                    xmlNodePtr OriginalNode,
+                                    xmlAttrPtr AdditionalAttribute) {
+
+  Expected<xmlNsPtr> ExplicitOrError =
+      searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
+  if (!ExplicitOrError)
+    return ExplicitOrError.takeError();
+  OriginalAttribute->ns = std::move(ExplicitOrError.get());
+  return Error::success();
+}
+
+// Return the corresponding namespace definition for the prefix, defined on the
+// given Node.  Returns nullptr if there is no such definition.
+static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix,
+                                       xmlNodePtr Node) {
+  if (Node == nullptr)
+    return nullptr;
+  for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
+    if (xmlStringsEqual(Def->prefix, Prefix)) {
+      return Def;
+    }
+  }
+  return nullptr;
+}
+
+// Search for the closest inheritable default namespace, starting on (and
+// including) the Node and traveling upwards through parent nodes.  Returns
+// nullptr if there are no inheritable default namespaces.
+static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
+  if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node))
+    return Ret;
+  if (Node->parent == nullptr)
+    return nullptr;
+  return getClosestDefault(Node->parent);
+}
+
+// Merge the attributes of AdditionalNode into OriginalNode.  If attributes
+// with identical types are present, they are not duplicated but rather if
+// their values are not consistent and error is thrown.  In addition, the
+// higher priority namespace is used for each attribute, EXCEPT in the case
+// of merging two default namespaces and the lower priority namespace
+// definition occurs closer than the higher priority one.
+static Error mergeAttributes(xmlNodePtr OriginalNode,
+                             xmlNodePtr AdditionalNode) {
+  xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
+  for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute;
        Attribute = Attribute->next) {
-    if (const unsigned char *OriginalValue =
+    if (xmlAttrPtr OriginalAttribute =
             getAttribute(OriginalNode, Attribute->name)) {
-      // Attributes of the same name must also have the same value.  Otherwise
-      // an error is thrown.
-      if (!xmlStringsEqual(OriginalValue, Attribute->children->content))
+      if (!xmlStringsEqual(OriginalAttribute->children->content,
+                           Attribute->children->content)) {
         return make_error<WindowsManifestError>(
             Twine("conflicting attributes for ") +
             FROM_XML_CHAR(OriginalNode->name));
+      }
+      if (!Attribute->ns) {
+        continue;
+      }
+      if (!OriginalAttribute->ns) {
+        if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
+                                            Attribute)) {
+          return E;
+        }
+        continue;
+      }
+      if (namespaceOverrides(OriginalAttribute->ns->href,
+                             Attribute->ns->href)) {
+        // In this case, the original attribute has a higher priority namespace
+        // than the incomiing attribute, however the namespace definition of
+        // the lower priority namespace occurs first traveling upwards in the
+        // tree.  Therefore the lower priority namespace is applied.
+        if (!OriginalAttribute->ns->prefix && !Attribute->ns->prefix &&
+            ClosestDefault &&
+            xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) {
+          if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
+                                              Attribute)) {
+            return E;
+          }
+          continue;
+        }
+        continue;
+        // This covers the case where the incoming attribute has the higher
+        // priority.  The higher priority namespace is applied in all cases
+        // EXCEPT when both of the namespaces are default inherited, and the
+        // closest inherited default is the lower priority one.
+      }
+      if (Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
+          (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
+                                              ClosestDefault->href))) {
+        if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
+                                            Attribute)) {
+          return E;
+        }
+        continue;
+      }
+      continue;
+    }
+    // If the incoming attribute is not already found on the node, append it
+    // to the end of the properties list.  Also explicitly apply its
+    // namespace as a prefix because it might be contained in a separate
+    // namespace that doesn't use the attribute.
+    xmlAttrPtr NewProp =
+        xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content);
+    Expected<xmlNsPtr> ExplicitOrError =
+        searchOrDefine(Attribute->ns->href, OriginalNode);
+    if (!ExplicitOrError)
+      return ExplicitOrError.takeError();
+    NewProp->ns = std::move(ExplicitOrError.get());
+  }
+  return Error::success();
+}
+
+// Given two nodes, return the one with the higher priority namespace.
+static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
+
+  if (!Node1 || !Node1->ns)
+    return Node2;
+  if (!Node2 || !Node2->ns)
+    return Node1;
+  if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
+    return Node1;
+  return Node2;
+}
+
+// Checks if this Node's namespace is inherited or one it defined itself.
+static bool hasInheritedNs(xmlNodePtr Node) {
+  return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node);
+}
+
+// Check if this Node's namespace is a default namespace that it inherited, as
+// opposed to defining itself.
+static bool hasInheritedDefaultNs(xmlNodePtr Node) {
+  return hasInheritedNs(Node) && Node->ns->prefix == nullptr;
+}
+
+// Check if this Node's namespace is a default namespace it defined itself.
+static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
+  return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node));
+}
+
+// For the given explicit prefix-definition of a namespace, travel downwards
+// from a node recursively, and for every implicit, inherited default usage of
+// that namespace replace it with that explicit prefix use.  This is important
+// when namespace overriding occurs when merging, so that elements unique to a
+// namespace will still stay in that namespace.
+static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
+  // If a node as its own default namespace definition it clearly cannot have
+  // inherited the given default namespace, and neither will any of its
+  // children.
+  if (hasDefinedDefaultNamespace(Node))
+    return;
+  if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) &&
+      hasInheritedDefaultNs(Node))
+    Node->ns = PrefixDef;
+  for (xmlAttrPtr Attribute = Node->properties; Attribute;
+       Attribute = Attribute->next) {
+    if (Attribute->ns &&
+        xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) {
+      Attribute->ns = PrefixDef;
+    }
+  }
+  for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
+    explicateNamespace(PrefixDef, Child);
+  }
+}
+
+// Perform the namespace merge between two nodes.
+static Error mergeNamespaces(xmlNodePtr OriginalNode,
+                             xmlNodePtr AdditionalNode) {
+  // Save the original default namespace definition in case the incoming node
+  // overrides it.
+  const unsigned char *OriginalDefinedDefaultHref = nullptr;
+  if (xmlNsPtr OriginalDefinedDefaultNs =
+          getNamespaceWithPrefix(nullptr, OriginalNode)) {
+    OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
+  }
+  const unsigned char *NewDefinedDefaultHref = nullptr;
+  // Copy all namespace definitions.  There can only be one default namespace
+  // definition per node, so the higher priority one takes precedence in the
+  // case of collision.
+  for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) {
+    if (xmlNsPtr OriginalNsDef =
+            getNamespaceWithPrefix(Def->prefix, OriginalNode)) {
+      if (!Def->prefix) {
+        if (namespaceOverrides(Def->href, OriginalNsDef->href)) {
+          NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href)));
+        }
+      } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) {
+        return make_error<WindowsManifestError>(
+            Twine("conflicting namespace definitions for ") +
+            FROM_XML_CHAR(Def->prefix));
+      }
     } else {
-      char *NameCopy = strdup(FROM_XML_CHAR(Attribute->name));
-      char *ContentCopy = strdup(FROM_XML_CHAR(Attribute->children->content));
-      xmlNewProp(OriginalNode, TO_XML_CHAR(NameCopy), TO_XML_CHAR(ContentCopy));
+      xmlNsPtr NewDef = xmlCopyNamespace(Def);
+      NewDef->next = OriginalNode->nsDef;
+      OriginalNode->nsDef = NewDef;
     }
   }
-#endif
+
+  // Check whether the original node or the incoming node has the higher
+  // priority namespace.  Depending on which one is dominant, we will have
+  // to recursively apply namespace changes down to children of the original
+  // node.
+  xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode);
+  xmlNodePtr NonDominantNode =
+      DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
+  if (DominantNode == OriginalNode) {
+    if (OriginalDefinedDefaultHref) {
+      xmlNsPtr NonDominantDefinedDefault =
+          getNamespaceWithPrefix(nullptr, NonDominantNode);
+      // In this case, both the nodes defined a default namespace.  However
+      // the lower priority node ended up having a higher priority default
+      // definition.  This can occur if the higher priority node is prefix
+      // namespace defined.  In this case we have to define an explicit
+      // prefix for the overridden definition and apply it to all children
+      // who relied on that definition.
+      if (NonDominantDefinedDefault &&
+          namespaceOverrides(NonDominantDefinedDefault->href,
+                             OriginalDefinedDefaultHref)) {
+        Expected<xmlNsPtr> EC =
+            searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
+        if (!EC) {
+          return EC.takeError();
+        }
+        xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get());
+        explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
+      }
+      // In this case the node with a higher priority namespace did not have a
+      // default namespace definition, but the lower priority node did.  In this
+      // case the new default namespace definition is copied.  A side effect of
+      // this is that all children will suddenly find themselves in a different
+      // default namespace.  To maintain correctness we need to ensure that all
+      // children now explicitly refer to the namespace that they had previously
+      // implicitly inherited.
+    } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) {
+      if (DominantNode->parent) {
+        xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
+        Expected<xmlNsPtr> EC =
+            searchOrDefine(ClosestDefault->href, DominantNode);
+        if (!EC) {
+          return EC.takeError();
+        }
+        xmlNsPtr ExplicitDefault = std::move(EC.get());
+        explicateNamespace(ExplicitDefault, DominantNode);
+      }
+    }
+  } else {
+    // Covers case where the incoming node has a default namespace definition
+    // that overrides the original node's namespace.  This always leads to
+    // the original node receiving that new default namespace.
+    if (hasDefinedDefaultNamespace(DominantNode)) {
+      NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode);
+    } else {
+      // This covers the case where the incoming node either has a prefix
+      // namespace, or an inherited default namespace.  Since the namespace
+      // may not yet be defined in the original tree we do a searchOrDefine
+      // for it, and then set the namespace equal to it.
+      Expected<xmlNsPtr> EC =
+          searchOrDefine(DominantNode->ns->href, NonDominantNode);
+      if (!EC) {
+        return EC.takeError();
+      }
+      xmlNsPtr Explicit = std::move(EC.get());
+      NonDominantNode->ns = Explicit;
+    }
+    // This covers cases where the incoming dominant node HAS a default
+    // namespace definition, but MIGHT NOT NECESSARILY be in that namespace.
+    if (xmlNsPtr DominantDefaultDefined =
+            getNamespaceWithPrefix(nullptr, DominantNode)) {
+      if (OriginalDefinedDefaultHref) {
+        if (namespaceOverrides(DominantDefaultDefined->href,
+                               OriginalDefinedDefaultHref)) {
+          // In this case, the incoming node's default definition overrides
+          // the original default definition, all children who relied on that
+          // definition must be updated accordingly.
+          Expected<xmlNsPtr> EC =
+              searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
+          if (!EC) {
+            return EC.takeError();
+          }
+          xmlNsPtr ExplicitDefault = std::move(EC.get());
+          explicateNamespace(ExplicitDefault, NonDominantNode);
+        }
+      } else {
+        // The original did not define a default definition, however the new
+        // default definition still applies to all children, so they must be
+        // updated to explicitly refer to the namespace they had previously
+        // been inheriting implicitly.
+        xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
+        Expected<xmlNsPtr> EC =
+            searchOrDefine(ClosestDefault->href, NonDominantNode);
+        if (!EC) {
+          return EC.takeError();
+        }
+        xmlNsPtr ExplicitDefault = std::move(EC.get());
+        explicateNamespace(ExplicitDefault, NonDominantNode);
+      }
+    }
+  }
+  if (NewDefinedDefaultHref) {
+    xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode);
+    xmlFree(const_cast<unsigned char *>(OriginalNsDef->href));
+    OriginalNsDef->href = NewDefinedDefaultHref;
+  }
+  xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref));
   return Error::success();
 }
 
-Error treeMerge(XMLNodeImpl OriginalRoot, XMLNodeImpl AdditionalRoot) {
-#if LLVM_LIBXML2_ENABLED
-  XMLNodeImpl AdditionalFirstChild = AdditionalRoot->children;
+static bool isRecognizedNamespace(const unsigned char *NsHref) {
+  for (auto &Ns : MtNsHrefsPrefixes) {
+    if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data()))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool hasRecognizedNamespace(xmlNodePtr Node) {
+  return isRecognizedNamespace(Node->ns->href);
+}
+
+// Ensure a node's inherited namespace is actually defined in the tree it
+// resides in.
+static Error reconcileNamespaces(xmlNodePtr Node) {
+  if (!Node) {
+    return Error::success();
+  }
+  if (hasInheritedNs(Node)) {
+    Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(Node->ns->href, Node);
+    if (!ExplicitOrError) {
+      return ExplicitOrError.takeError();
+    }
+    xmlNsPtr Explicit = std::move(ExplicitOrError.get());
+    Node->ns = Explicit;
+  }
+  for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
+    if (auto E = reconcileNamespaces(Child)) {
+      return E;
+    }
+  }
+  return Error::success();
+}
+
+// Recursively merge the two given manifest trees, depending on which elements
+// are of a mergeable type, and choose namespaces according to which have
+// higher priority.
+static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
+  if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
+    return E;
+  if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
+    return E;
+  xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
   xmlNode StoreNext;
-  for (XMLNodeImpl Child = AdditionalFirstChild; Child; Child = Child->next) {
-    XMLNodeImpl OriginalChildWithName;
+  for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
+    xmlNodePtr OriginalChildWithName;
     if (!isMergeableElement(Child->name) ||
         !(OriginalChildWithName =
-              getChildWithName(OriginalRoot, Child->name))) {
+              getChildWithName(OriginalRoot, Child->name)) ||
+        !hasRecognizedNamespace(Child)) {
       StoreNext.next = Child->next;
       xmlUnlinkNode(Child);
-      if (!xmlAddChild(OriginalRoot, Child))
+      if (!xmlAddChild(OriginalRoot, Child)) {
         return make_error<WindowsManifestError>(Twine("could not merge ") +
                                                 FROM_XML_CHAR(Child->name));
+      }
+      if (auto E = reconcileNamespaces(Child)) {
+        return E;
+      }
       Child = &StoreNext;
     } else if (auto E = treeMerge(OriginalChildWithName, Child)) {
       return E;
     }
   }
-  if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
-    return E;
-#endif
   return Error::success();
 }
 
-void stripCommentsAndText(XMLNodeImpl Root) {
-#if LLVM_LIBXML2_ENABLED
+static void stripComments(xmlNodePtr Root) {
   xmlNode StoreNext;
-  for (XMLNodeImpl Child = Root->children; Child; Child = Child->next) {
-    if (!xmlStringsEqual(Child->name, TO_XML_CHAR("text")) &&
-        !xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
-      stripCommentsAndText(Child);
+  for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
+    if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
+      stripComments(Child);
+      continue;
+    }
+    StoreNext.next = Child->next;
+    xmlNodePtr Remove = Child;
+    Child = &StoreNext;
+    xmlUnlinkNode(Remove);
+    xmlFreeNode(Remove);
+  }
+}
+
+// libxml2 assumes that attributes do not inherit default namespaces, whereas
+// the original  mt.exe does make this assumption.  This function reconciles
+// this by setting all attributes to have the inherited default namespace.
+static void setAttributeNamespaces(xmlNodePtr Node) {
+  for (xmlAttrPtr Attribute = Node->properties; Attribute;
+       Attribute = Attribute->next) {
+    if (!Attribute->ns) {
+      Attribute->ns = getClosestDefault(Node);
+    }
+  }
+  for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
+    setAttributeNamespaces(Child);
+  }
+}
+
+// The merging process may create too many prefix defined namespaces.  This
+// function removes all unnecessary ones from the tree.
+static void checkAndStripPrefixes(xmlNodePtr Node,
+                                  std::vector<xmlNsPtr> &RequiredPrefixes) {
+  for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
+    checkAndStripPrefixes(Child, RequiredPrefixes);
+  }
+  if (Node->ns && Node->ns->prefix != nullptr) {
+    xmlNsPtr ClosestDefault = getClosestDefault(Node);
+    if (ClosestDefault &&
+        xmlStringsEqual(ClosestDefault->href, Node->ns->href)) {
+      Node->ns = ClosestDefault;
+    } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
+      RequiredPrefixes.push_back(Node->ns);
+    }
+  }
+  for (xmlAttrPtr Attribute = Node->properties; Attribute;
+       Attribute = Attribute->next) {
+    if (Attribute->ns && Attribute->ns->prefix != nullptr) {
+      xmlNsPtr ClosestDefault = getClosestDefault(Node);
+      if (ClosestDefault &&
+          xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) {
+        Attribute->ns = ClosestDefault;
+      } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
+        RequiredPrefixes.push_back(Attribute->ns);
+      }
+    }
+  }
+  xmlNsPtr Prev;
+  xmlNs Temp;
+  for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
+    if (!Def->prefix || llvm::is_contained(RequiredPrefixes, Def)) {
+      Prev = Def;
+      continue;
+    }
+    if (Def == Node->nsDef) {
+      Node->nsDef = Def->next;
     } else {
-      StoreNext.next = Child->next;
-      XMLNodeImpl Remove = Child;
-      Child = &StoreNext;
-      xmlUnlinkNode(Remove);
-      xmlFreeNode(Remove);
+      Prev->next = Def->next;
     }
+    Temp.next = Def->next;
+    xmlFreeNs(Def);
+    Def = &Temp;
   }
-#endif
 }
 
-WindowsManifestMerger::~WindowsManifestMerger() {
-#if LLVM_LIBXML2_ENABLED
+WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
   for (auto &Doc : MergedDocs)
     xmlFreeDoc(Doc);
-#endif
 }
 
-Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
-#if LLVM_LIBXML2_ENABLED
+Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
+    const MemoryBuffer &Manifest) {
   if (Manifest.getBufferSize() == 0)
     return make_error<WindowsManifestError>(
         "attempted to merge empty manifest");
-  xmlSetGenericErrorFunc((void *)this, WindowsManifestMerger::errorCallback);
-  XMLDocumentImpl ManifestXML =
+  xmlSetGenericErrorFunc((void *)this,
+                         WindowsManifestMergerImpl::errorCallback);
+  xmlDocPtr ManifestXML =
       xmlReadMemory(Manifest.getBufferStart(), Manifest.getBufferSize(),
                     "manifest.xml", nullptr, XML_PARSE_NOBLANKS);
   xmlSetGenericErrorFunc(nullptr, nullptr);
   if (auto E = getParseError())
     return E;
-  XMLNodeImpl AdditionalRoot = xmlDocGetRootElement(ManifestXML);
-  stripCommentsAndText(AdditionalRoot);
+  xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML);
+  stripComments(AdditionalRoot);
+  setAttributeNamespaces(AdditionalRoot);
   if (CombinedDoc == nullptr) {
     CombinedDoc = ManifestXML;
   } else {
-    XMLNodeImpl CombinedRoot = xmlDocGetRootElement(CombinedDoc);
-    if (xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) &&
-        isMergeableElement(AdditionalRoot->name)) {
-      if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
-        return E;
-      }
-    } else {
+    xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
+    if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
+        !isMergeableElement(AdditionalRoot->name) ||
+        !hasRecognizedNamespace(AdditionalRoot)) {
       return make_error<WindowsManifestError>("multiple root nodes");
     }
+    if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
+      return E;
+    }
   }
   MergedDocs.push_back(ManifestXML);
-#endif
   return Error::success();
 }
 
-std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
-#if LLVM_LIBXML2_ENABLED
+std::unique_ptr<MemoryBuffer>
+WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
   unsigned char *XmlBuff;
   int BufferSize = 0;
   if (CombinedDoc) {
+    xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
+    std::vector<xmlNsPtr> RequiredPrefixes;
+    checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
     std::unique_ptr<xmlDoc> OutputDoc(xmlNewDoc((const unsigned char *)"1.0"));
-    xmlDocSetRootElement(OutputDoc.get(), xmlDocGetRootElement(CombinedDoc));
+    xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
     xmlKeepBlanksDefault(0);
-    xmlDocDumpFormatMemory(OutputDoc.get(), &XmlBuff, &BufferSize, 1);
+    xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &XmlBuff, &BufferSize, "UTF-8",
+                              1);
   }
   if (BufferSize == 0)
     return nullptr;
   return MemoryBuffer::getMemBuffer(
       StringRef(FROM_XML_CHAR(XmlBuff), (size_t)BufferSize));
+}
+
 #else
+
+WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
+}
+
+Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
+    const MemoryBuffer &Manifest) {
+  return Error::success();
+}
+
+std::unique_ptr<MemoryBuffer>
+WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
   return nullptr;
+}
+
 #endif
+
+WindowsManifestMerger::WindowsManifestMerger()
+    : Impl(make_unique<WindowsManifestMergerImpl>()) {}
+
+WindowsManifestMerger::~WindowsManifestMerger() {}
+
+Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
+  return Impl->merge(Manifest);
 }
 
-void WindowsManifestMerger::errorCallback(void *Ctx, const char *Format, ...) {
-  auto *Merger = (WindowsManifestMerger *)Ctx;
+std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
+  return Impl->getMergedManifest();
+}
+
+void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
+    void *Ctx, const char *Format, ...) {
+  auto *Merger = (WindowsManifestMergerImpl *)Ctx;
   Merger->ParseErrorOccurred = true;
 }
 
-Error WindowsManifestMerger::getParseError() {
+Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
   if (!ParseErrorOccurred)
     return Error::success();
   return make_error<WindowsManifestError>("invalid xml document");
 }
-
-} // namespace llvm

Added: llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v2" manifestVersion="1.0">
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity foo="bar" name="identity1" version="1.2.3.4"></assemblyIdentity>
+    </dependentAssembly>
+  </dependency>
+</assembly>

Added: llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+  <application>
+    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+      <supportedOS Id="FooOS"/>
+      <supportedOS Id="BarOS"/>
+    </compatibility>
+  </application>
+</assembly>

Added: llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<ms_asmv1:trustInfo xmlns="urn:schemas-microsoft-com:asm.v3" xmlns:ms_asmv1="urn:schemas-microsoft-com:asm.v1">
+  <ms_asmv1:security>
+    <ms_asmv1:requestedPrivileges>
+      <ms_asmv1:requestedExecutionLevel level="trust1" ms_asmv1:access="false"></ms_asmv1:requestedExecutionLevel>
+    </ms_asmv1:requestedPrivileges>
+  </ms_asmv1:security>
+</ms_asmv1:trustInfo>
+<ms_asmv2:dependency xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+  <ms_asmv2:dependentAssembly>
+    <ms_asmv2:assemblyIdentity foo="bar" name="identity1" version="1.2.3.4"></assemblyIdentity>
+  </ms_asmv2:dependentAssembly>
+</ms_asmv2:dependency>
+<dependency>
+  <dependentAssembly>
+    <assemblyIdentity bar="foo" name="my assembly" version="5"></assemblyIdentity>
+  </dependentAssembly>
+</dependency>
+<application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <supportedOS Id="FooOS"/>
+    <supportedOS Id="BarOS"/>
+  </compatibility>
+  <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+    <dpiAware>true/pm</dpiAware>
+  </asmv3:windowsSettings>
+</application>
+</assembly>

Added: llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+
+  <!--random comment -->
+
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity bar="foo" name="my assembly" version="5"></assemblyIdentity>
+    </dependentAssembly>
+  </dependency>
+
+  <trustInfo>
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="trust1" access="false"/>
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+
+</assembly>

Added: llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+  <security>
+    <requestedPrivileges>
+      <requestedExecutionLevel level="trust1"></requestedExecutionLevel>
+    </requestedPrivileges>
+  </security>
+</trustInfo></assembly>

Added: llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings" manifestVersion="1.0">
+ <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+      <dpiAware>true/pm</dpiAware>
+    </asmv3:windowsSettings>
+  </asmv3:application>
+</assembly>

Added: llvm/trunk/test/tools/llvm-mt/big_merge.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/big_merge.test?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/big_merge.test (added)
+++ llvm/trunk/test/tools/llvm-mt/big_merge.test Fri Aug 18 17:37:41 2017
@@ -0,0 +1,39 @@
+REQUIRES: libxml2
+UNSUPPORTED: windows
+
+RUN: llvm-mt /manifest %p/Inputs/trust_info.manifest \
+RUN:   /manifest %p/Inputs/assembly_identity.manifest \
+RUN:   /manifest %p/Inputs/trust_and_identity.manifest \
+RUN:   /manifest %p/Inputs/compatibility.manifest \
+RUN:   /manifest  %p/Inputs/windows_settings.manifest /out:%t
+RUN: FileCheck %s -input-file=%t
+
+CHECK:      <?xml version="1.0" encoding="UTF-8"?>
+CHECK-NEXT: <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+CHECK-NEXT: <ms_asmv1:trustInfo xmlns="urn:schemas-microsoft-com:asm.v3" xmlns:ms_asmv1="urn:schemas-microsoft-com:asm.v1">
+CHECK-NEXT:   <ms_asmv1:security>
+CHECK-NEXT:     <ms_asmv1:requestedPrivileges>
+CHECK-NEXT:       <ms_asmv1:requestedExecutionLevel level="trust1" ms_asmv1:access="false"/>
+CHECK-NEXT:     </ms_asmv1:requestedPrivileges>
+CHECK-NEXT:   </ms_asmv1:security>
+CHECK-NEXT: </ms_asmv1:trustInfo>
+CHECK-NEXT: <ms_asmv2:dependency xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+CHECK-NEXT:   <ms_asmv2:dependentAssembly>
+CHECK-NEXT:     <ms_asmv2:assemblyIdentity foo="bar" name="identity1" version="1.2.3.4"/>
+CHECK-NEXT:   </ms_asmv2:dependentAssembly>
+CHECK-NEXT: </ms_asmv2:dependency>
+CHECK-NEXT: <dependency>
+CHECK-NEXT:   <dependentAssembly>
+CHECK-NEXT:     <assemblyIdentity bar="foo" name="my assembly" version="5"/>
+CHECK-NEXT:   </dependentAssembly>
+CHECK-NEXT: </dependency>
+CHECK-NEXT: <application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+CHECK-NEXT:   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+CHECK-NEXT:     <supportedOS Id="FooOS"/>
+CHECK-NEXT:     <supportedOS Id="BarOS"/>
+CHECK-NEXT:   </compatibility>
+CHECK-NEXT:   <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+CHECK-NEXT:     <dpiAware>true/pm</dpiAware>
+CHECK-NEXT:   </asmv3:windowsSettings>
+CHECK-NEXT: </application>
+CHECK-NEXT: </assembly>

Modified: llvm/trunk/test/tools/llvm-mt/help.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/help.test?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/help.test (original)
+++ llvm/trunk/test/tools/llvm-mt/help.test Fri Aug 18 17:37:41 2017
@@ -1,3 +1,7 @@
 RUN: llvm-mt /h | FileCheck %s -check-prefix=HELP
 
 HELP:      OVERVIEW: Manifest Tool
+
+RUN: not llvm-mt /foo 2>&1 >/dev/null | FileCheck %s -check-prefix=INVALID
+
+INVALID: llvm-mt error: invalid option /foo

Modified: llvm/trunk/test/tools/llvm-mt/simple_merge.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/simple_merge.test?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/simple_merge.test (original)
+++ llvm/trunk/test/tools/llvm-mt/simple_merge.test Fri Aug 18 17:37:41 2017
@@ -5,7 +5,7 @@ RUN: llvm-mt /manifest %p/Inputs/test_ma
 RUN:   %p/Inputs/additional.manifest /out:%t
 RUN: FileCheck %s -input-file=%t
 
-CHECK:      <?xml version="1.0"?>
+CHECK:      <?xml version="1.0" encoding="UTF-8"?>
 CHECK-NEXT: <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 CHECK-NEXT:   <trustInfo>
 CHECK-NEXT:     <security>

Modified: llvm/trunk/test/tools/llvm-mt/single_file.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/single_file.test?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/single_file.test (original)
+++ llvm/trunk/test/tools/llvm-mt/single_file.test Fri Aug 18 17:37:41 2017
@@ -4,7 +4,7 @@ UNSUPPORTED: windows
 RUN: llvm-mt /manifest %p/Inputs/test_manifest.manifest /out:%t
 RUN: FileCheck %s --input-file=%t
 
-CHECK:      <?xml version="1.0"?>
+CHECK:      <?xml version="1.0" encoding="UTF-8"?>
 CHECK-NEXT: <assembly xmlns="urn:schemas-microsoft-com:asm.v1">
 CHECK-NEXT:   <trustInfo>
 CHECK-NEXT:     <security>

Modified: llvm/trunk/test/tools/llvm-mt/xml_error.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/xml_error.test?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/xml_error.test (original)
+++ llvm/trunk/test/tools/llvm-mt/xml_error.test Fri Aug 18 17:37:41 2017
@@ -11,8 +11,8 @@ RUN:   FileCheck %s -check-prefix=EMPTY
 
 EMPTY: llvm-mt error: attempted to merge empty manifest
 
-RUN: llvm-mt /inputresource:foo.res /manifest \
-RUN:   %p/Inputs/test_manifest.manifest | FileCheck %s \
-RUN:    -check-prefix=NOT_SUPPORTED
+RUN: llvm-mt /inputresource:foo.res \
+RUN:   /manifest %p/Inputs/test_manifest.manifest \
+RUN:   /out:%t | FileCheck %s -check-prefix=NOT_SUPPORTED
 
 NOT_SUPPORTED: llvm-mt: ignoring unsupported 'inputresource:' option

Modified: llvm/trunk/tools/llvm-mt/llvm-mt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mt/llvm-mt.cpp?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mt/llvm-mt.cpp (original)
+++ llvm/trunk/tools/llvm-mt/llvm-mt.cpp Fri Aug 18 17:37:41 2017
@@ -102,6 +102,9 @@ int main(int argc, const char **argv) {
   ArrayRef<const char *> ArgsArr = makeArrayRef(argv + 1, argc);
   opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
 
+  for (auto *Arg : InputArgs.filtered(OPT_INPUT))
+    reportError(Twine("invalid option ") + Arg->getSpelling());
+
   for (auto &Arg : InputArgs) {
     if (Arg->getOption().matches(OPT_unsupported)) {
       outs() << "llvm-mt: ignoring unsupported '" << Arg->getOption().getName()
@@ -129,7 +132,7 @@ int main(int argc, const char **argv) {
     reportError("no output file specified");
   }
 
-  WindowsManifestMerger Merger;
+  windows_manifest::WindowsManifestMerger Merger;
 
   for (const auto &File : InputFiles) {
     ErrorOr<std::unique_ptr<MemoryBuffer>> ManifestOrErr =




More information about the llvm-commits mailing list