This revision was automatically updated to reflect the committed changes.
Closed by commit rL365413: Let unaliased Args track which Alias they were 
created from, and use that in… (authored by nico, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D64253?vs=208192&id=208553#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64253/new/

https://reviews.llvm.org/D64253

Files:
  cfe/trunk/test/Driver/arm-execute-only.c
  cfe/trunk/test/Driver/cl-options.c
  cfe/trunk/test/Driver/darwin-version.c
  lld/trunk/Common/Reproduce.cpp
  lld/trunk/ELF/Driver.cpp
  lld/trunk/test/ELF/sectionstart.s
  llvm/trunk/include/llvm/Option/Arg.h
  llvm/trunk/include/llvm/Option/Option.h
  llvm/trunk/lib/Option/Arg.cpp
  llvm/trunk/lib/Option/Option.cpp

Index: lld/trunk/test/ELF/sectionstart.s
===================================================================
--- lld/trunk/test/ELF/sectionstart.s
+++ lld/trunk/test/ELF/sectionstart.s
@@ -45,15 +45,15 @@
 
 # RUN: not ld.lld %t.o -Ttext=1w0000 -o %t6 2>&1 \
 # RUN:    | FileCheck -check-prefix=ERR3 %s
-# ERR3: invalid argument: --Ttext 1w0000
+# ERR3: invalid argument: -Ttext=1w0000
 
 # RUN: not ld.lld %t.o -Tbss=1w0000 -o %t6 2>&1 \
 # RUN:    | FileCheck -check-prefix=ERR4 %s
-# ERR4: invalid argument: --Tbss 1w0000
+# ERR4: invalid argument: -Tbss=1w0000
 
 # RUN: not ld.lld %t.o -Tdata=1w0000 -o %t6 2>&1 \
 # RUN:    | FileCheck -check-prefix=ERR5 %s
-# ERR5: invalid argument: --Tdata 1w0000
+# ERR5: invalid argument: -Tdata=1w0000
 
 .text
 .globl _start
Index: lld/trunk/ELF/Driver.cpp
===================================================================
--- lld/trunk/ELF/Driver.cpp
+++ lld/trunk/ELF/Driver.cpp
@@ -588,12 +588,13 @@
   return StripPolicy::Debug;
 }
 
-static uint64_t parseSectionAddress(StringRef S, const opt::Arg &Arg) {
+static uint64_t parseSectionAddress(StringRef S, opt::InputArgList &Args,
+                                    const opt::Arg &Arg) {
   uint64_t VA = 0;
   if (S.startswith("0x"))
     S = S.drop_front(2);
   if (!to_integer(S, VA, 16))
-    error("invalid argument: " + toString(Arg));
+    error("invalid argument: " + Arg.getAsString(Args));
   return VA;
 }
 
@@ -603,15 +604,15 @@
     StringRef Name;
     StringRef Addr;
     std::tie(Name, Addr) = StringRef(Arg->getValue()).split('=');
-    Ret[Name] = parseSectionAddress(Addr, *Arg);
+    Ret[Name] = parseSectionAddress(Addr, Args, *Arg);
   }
 
   if (auto *Arg = Args.getLastArg(OPT_Ttext))
-    Ret[".text"] = parseSectionAddress(Arg->getValue(), *Arg);
+    Ret[".text"] = parseSectionAddress(Arg->getValue(), Args, *Arg);
   if (auto *Arg = Args.getLastArg(OPT_Tdata))
-    Ret[".data"] = parseSectionAddress(Arg->getValue(), *Arg);
+    Ret[".data"] = parseSectionAddress(Arg->getValue(), Args, *Arg);
   if (auto *Arg = Args.getLastArg(OPT_Tbss))
-    Ret[".bss"] = parseSectionAddress(Arg->getValue(), *Arg);
+    Ret[".bss"] = parseSectionAddress(Arg->getValue(), Args, *Arg);
   return Ret;
 }
 
Index: lld/trunk/Common/Reproduce.cpp
===================================================================
--- lld/trunk/Common/Reproduce.cpp
+++ lld/trunk/Common/Reproduce.cpp
@@ -48,6 +48,8 @@
   return S;
 }
 
+// Converts an Arg to a string representation suitable for a response file.
+// To show an Arg in a diagnostic, use Arg::getAsString() instead.
 std::string lld::toString(const opt::Arg &Arg) {
   std::string K = Arg.getSpelling();
   if (Arg.getNumValues() == 0)
Index: llvm/trunk/include/llvm/Option/Arg.h
===================================================================
--- llvm/trunk/include/llvm/Option/Arg.h
+++ llvm/trunk/include/llvm/Option/Arg.h
@@ -58,6 +58,11 @@
   /// The argument values, as C strings.
   SmallVector<const char *, 2> Values;
 
+  /// If this arg was created through an alias, this is the original alias arg.
+  /// For example, *this might be "-finput-charset=utf-8" and Alias might
+  /// point to an arg representing "/source-charset:utf-8".
+  std::unique_ptr<Arg> Alias;
+
 public:
   Arg(const Option Opt, StringRef Spelling, unsigned Index,
       const Arg *BaseArg = nullptr);
@@ -90,6 +95,11 @@
   }
   void setBaseArg(const Arg *BaseArg) { this->BaseArg = BaseArg; }
 
+  /// Args are converted to their unaliased form.  For args that originally
+  /// came from an alias, this returns the alias the arg was produced from.
+  const Arg* getAlias() const { return Alias.get(); }
+  void setAlias(std::unique_ptr<Arg> Alias) { this->Alias = std::move(Alias); }
+
   bool getOwnsValues() const { return OwnsValues; }
   void setOwnsValues(bool Value) const { OwnsValues = Value; }
 
@@ -127,8 +137,10 @@
   void print(raw_ostream &O) const;
   void dump() const;
 
-  /// Return a formatted version of the argument and
-  /// its values, for debugging and diagnostics.
+  /// Return a formatted version of the argument and its values, for
+  /// diagnostics. Since this is for diagnostics, if this Arg was produced
+  /// through an alias, this returns the string representation of the alias
+  /// that the user wrote.
   std::string getAsString(const ArgList &Args) const;
 };
 
Index: llvm/trunk/include/llvm/Option/Option.h
===================================================================
--- llvm/trunk/include/llvm/Option/Option.h
+++ llvm/trunk/include/llvm/Option/Option.h
@@ -206,6 +206,11 @@
   ///                start.
   Arg *accept(const ArgList &Args, unsigned &Index, unsigned ArgSize) const;
 
+private:
+  Arg *acceptInternal(const ArgList &Args, unsigned &Index,
+                      unsigned ArgSize) const;
+
+public:
   void print(raw_ostream &O) const;
   void dump() const;
 };
Index: llvm/trunk/lib/Option/Arg.cpp
===================================================================
--- llvm/trunk/lib/Option/Arg.cpp
+++ llvm/trunk/lib/Option/Arg.cpp
@@ -66,6 +66,9 @@
 #endif
 
 std::string Arg::getAsString(const ArgList &Args) const {
+  if (Alias)
+    return Alias->getAsString(Args);
+
   SmallString<256> Res;
   raw_svector_ostream OS(Res);
 
Index: llvm/trunk/lib/Option/Option.cpp
===================================================================
--- llvm/trunk/lib/Option/Option.cpp
+++ llvm/trunk/lib/Option/Option.cpp
@@ -106,49 +106,23 @@
   return false;
 }
 
-Arg *Option::accept(const ArgList &Args,
-                    unsigned &Index,
-                    unsigned ArgSize) const {
-  const Option &UnaliasedOption = getUnaliasedOption();
-  StringRef Spelling;
-  // If the option was an alias, get the spelling from the unaliased one.
-  if (getID() == UnaliasedOption.getID()) {
-    Spelling = StringRef(Args.getArgString(Index), ArgSize);
-  } else {
-    Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
-                                  Twine(UnaliasedOption.getName()));
-  }
-
+Arg *Option::acceptInternal(const ArgList &Args, unsigned &Index,
+                            unsigned ArgSize) const {
+  StringRef Spelling = StringRef(Args.getArgString(Index), ArgSize);
   switch (getKind()) {
   case FlagClass: {
     if (ArgSize != strlen(Args.getArgString(Index)))
       return nullptr;
-
-    Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
-    if (getAliasArgs()) {
-      const char *Val = getAliasArgs();
-      while (*Val != '\0') {
-        A->getValues().push_back(Val);
-
-        // Move past the '\0' to the next argument.
-        Val += strlen(Val) + 1;
-      }
-    }
-
-    if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs())
-      // A Flag alias for a Joined option must provide an argument.
-      A->getValues().push_back("");
-
-    return A;
+    return new Arg(*this, Spelling, Index++);
   }
   case JoinedClass: {
     const char *Value = Args.getArgString(Index) + ArgSize;
-    return new Arg(UnaliasedOption, Spelling, Index++, Value);
+    return new Arg(*this, Spelling, Index++, Value);
   }
   case CommaJoinedClass: {
     // Always matches.
     const char *Str = Args.getArgString(Index) + ArgSize;
-    Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
+    Arg *A = new Arg(*this, Spelling, Index++);
 
     // Parse out the comma separated values.
     const char *Prev = Str;
@@ -184,8 +158,7 @@
         Args.getArgString(Index - 1) == nullptr)
       return nullptr;
 
-    return new Arg(UnaliasedOption, Spelling,
-                   Index - 2, Args.getArgString(Index - 1));
+    return new Arg(*this, Spelling, Index - 2, Args.getArgString(Index - 1));
   case MultiArgClass: {
     // Matches iff this is an exact match.
     // FIXME: Avoid strlen.
@@ -196,8 +169,8 @@
     if (Index > Args.getNumInputArgStrings())
       return nullptr;
 
-    Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
-                      Args.getArgString(Index - getNumArgs()));
+    Arg *A = new Arg(*this, Spelling, Index - 1 - getNumArgs(),
+                     Args.getArgString(Index - getNumArgs()));
     for (unsigned i = 1; i != getNumArgs(); ++i)
       A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
     return A;
@@ -207,7 +180,7 @@
     // FIXME: Avoid strlen.
     if (ArgSize != strlen(Args.getArgString(Index))) {
       const char *Value = Args.getArgString(Index) + ArgSize;
-      return new Arg(UnaliasedOption, Spelling, Index++, Value);
+      return new Arg(*this, Spelling, Index++, Value);
     }
 
     // Otherwise it must be separate.
@@ -216,8 +189,7 @@
         Args.getArgString(Index - 1) == nullptr)
       return nullptr;
 
-    return new Arg(UnaliasedOption, Spelling,
-                   Index - 2, Args.getArgString(Index - 1));
+    return new Arg(*this, Spelling, Index - 2, Args.getArgString(Index - 1));
   }
   case JoinedAndSeparateClass:
     // Always matches.
@@ -226,7 +198,7 @@
         Args.getArgString(Index - 1) == nullptr)
       return nullptr;
 
-    return new Arg(UnaliasedOption, Spelling, Index - 2,
+    return new Arg(*this, Spelling, Index - 2,
                    Args.getArgString(Index - 2) + ArgSize,
                    Args.getArgString(Index - 1));
   case RemainingArgsClass: {
@@ -234,14 +206,14 @@
     // FIXME: Avoid strlen.
     if (ArgSize != strlen(Args.getArgString(Index)))
       return nullptr;
-    Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
+    Arg *A = new Arg(*this, Spelling, Index++);
     while (Index < Args.getNumInputArgStrings() &&
            Args.getArgString(Index) != nullptr)
       A->getValues().push_back(Args.getArgString(Index++));
     return A;
   }
   case RemainingArgsJoinedClass: {
-    Arg *A = new Arg(UnaliasedOption, Spelling, Index);
+    Arg *A = new Arg(*this, Spelling, Index);
     if (ArgSize != strlen(Args.getArgString(Index))) {
       // An inexact match means there is a joined arg.
       A->getValues().push_back(Args.getArgString(Index) + ArgSize);
@@ -257,3 +229,62 @@
     llvm_unreachable("Invalid option kind!");
   }
 }
+
+Arg *Option::accept(const ArgList &Args,
+                    unsigned &Index,
+                    unsigned ArgSize) const {
+  std::unique_ptr<Arg> A(acceptInternal(Args, Index, ArgSize));
+  if (!A)
+    return nullptr;
+
+  const Option &UnaliasedOption = getUnaliasedOption();
+  if (getID() == UnaliasedOption.getID())
+    return A.release();
+
+  // "A" is an alias for a different flag. For most clients it's more convenient
+  // if this function returns unaliased Args, so create an unaliased arg for
+  // returning.
+
+  // This creates a completely new Arg object for the unaliased Arg because
+  // the alias and the unaliased arg can have different Kinds and different
+  // Values (due to AliasArgs<>).
+
+  // Get the spelling from the unaliased option.
+  StringRef UnaliasedSpelling = Args.MakeArgString(
+      Twine(UnaliasedOption.getPrefix()) + Twine(UnaliasedOption.getName()));
+
+  // It's a bit weird that aliased and unaliased arg share one index, but
+  // the index is mostly use as a memory optimization in render().
+  // Due to this, ArgList::getArgString(A->getIndex()) will return the spelling
+  // of the aliased arg always, while A->getSpelling() returns either the
+  // unaliased or the aliased arg, depending on which Arg object it's called on.
+  Arg *UnaliasedA = new Arg(UnaliasedOption, UnaliasedSpelling, A->getIndex());
+  Arg *RawA = A.get();
+  UnaliasedA->setAlias(std::move(A));
+
+  if (getKind() != FlagClass) {
+    // Values are usually owned by the ArgList. The exception are
+    // CommaJoined flags, where the Arg owns the values. For aliased flags,
+    // make the unaliased Arg the owner of the values.
+    // FIXME: There aren't many uses of CommaJoined -- try removing
+    // CommaJoined in favor of just calling StringRef::split(',') instead.
+    UnaliasedA->getValues() = RawA->getValues();
+    UnaliasedA->setOwnsValues(RawA->getOwnsValues());
+    RawA->setOwnsValues(false);
+    return UnaliasedA;
+  }
+
+  // FlagClass aliases can have AliasArgs<>; add those to the unaliased arg.
+  if (const char *Val = getAliasArgs()) {
+    while (*Val != '\0') {
+      UnaliasedA->getValues().push_back(Val);
+
+      // Move past the '\0' to the next argument.
+      Val += strlen(Val) + 1;
+    }
+  }
+  if (UnaliasedOption.getKind() == JoinedClass && !getAliasArgs())
+    // A Flag alias for a Joined option must provide an argument.
+    UnaliasedA->getValues().push_back("");
+  return UnaliasedA;
+}
Index: cfe/trunk/test/Driver/cl-options.c
===================================================================
--- cfe/trunk/test/Driver/cl-options.c
+++ cfe/trunk/test/Driver/cl-options.c
@@ -8,7 +8,7 @@
 // c: -c
 
 // RUN: %clang_cl /C -### -- %s 2>&1 | FileCheck -check-prefix=C %s
-// C: error: invalid argument '-C' only allowed with '/E, /P or /EP'
+// C: error: invalid argument '/C' only allowed with '/E, /P or /EP'
 
 // RUN: %clang_cl /C /P -### -- %s 2>&1 | FileCheck -check-prefix=C_P %s
 // C_P: "-E"
@@ -214,11 +214,11 @@
 
 // /source-charset: should warn on everything except UTF-8.
 // RUN: %clang_cl /source-charset:utf-16 -### -- %s 2>&1 | FileCheck -check-prefix=source-charset-utf-16 %s
-// source-charset-utf-16: invalid value 'utf-16'
+// source-charset-utf-16: invalid value 'utf-16' in '/source-charset:utf-16'
 
 // /execution-charset: should warn on everything except UTF-8.
 // RUN: %clang_cl /execution-charset:utf-16 -### -- %s 2>&1 | FileCheck -check-prefix=execution-charset-utf-16 %s
-// execution-charset-utf-16: invalid value 'utf-16'
+// execution-charset-utf-16: invalid value 'utf-16' in '/execution-charset:utf-16'
 //
 // RUN: %clang_cl /Umymacro -### -- %s 2>&1 | FileCheck -check-prefix=U %s
 // RUN: %clang_cl /U mymacro -### -- %s 2>&1 | FileCheck -check-prefix=U %s
Index: cfe/trunk/test/Driver/darwin-version.c
===================================================================
--- cfe/trunk/test/Driver/darwin-version.c
+++ cfe/trunk/test/Driver/darwin-version.c
@@ -18,7 +18,7 @@
 
 // RUN: %clang -target armv7-apple-ios11.0 -c -### %s 2> %t.err
 // RUN: FileCheck --input-file=%t.err --check-prefix=CHECK-VERSION-IOS41 %s
-// CHECK-VERSION-IOS41: invalid iOS deployment version '--target=armv7-apple-ios11.0'
+// CHECK-VERSION-IOS41: invalid iOS deployment version '-target armv7-apple-ios11.0'
 
 // RUN: %clang -target armv7-apple-darwin -miphoneos-version-min=11.0 -c -### %s 2> %t.err
 // RUN: FileCheck --input-file=%t.err --check-prefix=CHECK-VERSION-IOS5 %s
@@ -197,11 +197,11 @@
 
 // RUN: %clang -target x86_64-apple-macos10.11.2 -mmacos-version-min=10.6 -c %s -### 2>&1 | \
 // RUN:   FileCheck --check-prefix=CHECK-VERSION-TNO-OSV1 %s
-// CHECK-VERSION-TNO-OSV1: overriding '-mmacosx-version-min=10.6' option with '--target=x86_64-apple-macos10.11.2'
+// CHECK-VERSION-TNO-OSV1: overriding '-mmacos-version-min=10.6' option with '-target x86_64-apple-macos10.11.2'
 
 // RUN: %clang -target x86_64-apple-macos -miphoneos-version-min=9.1 -c %s -### 2>&1 | \
 // RUN:   FileCheck --check-prefix=CHECK-VERSION-TNO-OSV2 %s
-// CHECK-VERSION-TNO-OSV2: overriding '-miphoneos-version-min=9.1' option with '--target=x86_64-apple-macos'
+// CHECK-VERSION-TNO-OSV2: overriding '-miphoneos-version-min=9.1' option with '-target x86_64-apple-macos'
 
 // RUN: %clang -target x86_64-apple-ios -miphonesimulator-version-min=10.0 -c %s -### 2>&1 | \
 // RUN:   FileCheck --check-prefix=CHECK-VERSION-TNO-OSV3 %s
@@ -211,7 +211,7 @@
 
 // RUN: %clang -target arm64-apple-ios10.1.0 -miphoneos-version-min=10.1.0.1 -c %s -### 2>&1 | \
 // RUN:   FileCheck --check-prefix=CHECK-VERSION-TNO-OSV4 %s
-// CHECK-VERSION-TNO-OSV4: overriding '-miphoneos-version-min=10.1.0.1' option with '--target=arm64-apple-ios10.1.0'
+// CHECK-VERSION-TNO-OSV4: overriding '-miphoneos-version-min=10.1.0.1' option with '-target arm64-apple-ios10.1.0'
 
 // RUN: %clang -target x86_64-apple-macos10.6 -mmacos-version-min=10.6 -c %s -### 2>&1 | \
 // RUN:   FileCheck --check-prefix=CHECK-VERSION-TNO-SAME %s
Index: cfe/trunk/test/Driver/arm-execute-only.c
===================================================================
--- cfe/trunk/test/Driver/arm-execute-only.c
+++ cfe/trunk/test/Driver/arm-execute-only.c
@@ -1,27 +1,27 @@
 // RUN: not %clang -c -target thumbv6m-eabi -mexecute-only %s 2>&1 | \
 // RUN:   FileCheck --check-prefix CHECK-EXECUTE-ONLY-NOT-SUPPORTED %s
+// CHECK-EXECUTE-ONLY-NOT-SUPPORTED: error: execute only is not supported for the thumbv6m sub-architecture
 
 // RUN: not %clang -target armv8m.main-eabi -mexecute-only -mno-movt %s 2>&1 \
 // RUN:    | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY-NO-MOVT
+// CHECK-EXECUTE-ONLY-NO-MOVT: error: option '-mexecute-only' cannot be specified with '-mno-movt'
 
 // RUN: not %clang -target armv8m.main-eabi -mexecute-only -mlong-calls %s 2>&1 \
 // RUN:    | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY-LONG-CALLS
+// CHECK-EXECUTE-ONLY-LONG-CALLS: error: option '-mexecute-only' cannot be specified with '-mlong-calls'
 
+// RUN: %clang -target armv7m-eabi -x assembler -mexecute-only %s -c -### 2>&1 \
+// RUN:    | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY -check-prefix CHECK-NO-EXECUTE-ONLY-ASM
+// CHECK-NO-EXECUTE-ONLY-ASM: warning: argument unused during compilation: '-mexecute-only'
 
 // -mpure-code flag for GCC compatibility
 // RUN: not %clang -c -target thumbv6m-eabi -mpure-code %s 2>&1 | \
 // RUN:   FileCheck --check-prefix CHECK-EXECUTE-ONLY-NOT-SUPPORTED %s
 
 // RUN: not %clang -target armv8m.main-eabi -mpure-code -mno-movt %s 2>&1 \
-// RUN:    | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY-NO-MOVT
+// RUN:    | FileCheck %s -check-prefix CHECK-PURE-CODE-NO-MOVT
+// CHECK-PURE-CODE-NO-MOVT: error: option '-mpure-code' cannot be specified with '-mno-movt'
 
 // RUN: not %clang -target armv8m.main-eabi -mpure-code -mlong-calls %s 2>&1 \
-// RUN:    | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY-LONG-CALLS
-
-// RUN: %clang -target armv7m-eabi -x assembler -mexecute-only %s -c -### 2>&1 \
-// RUN:    | FileCheck %s -check-prefix CHECK-NO-EXECUTE-ONLY -check-prefix CHECK-NO-EXECUTE-ONLY-ASM
-
-// CHECK-EXECUTE-ONLY-NOT-SUPPORTED: error: execute only is not supported for the thumbv6m sub-architecture
-// CHECK-EXECUTE-ONLY-NO-MOVT: error: option '-mexecute-only' cannot be specified with '-mno-movt'
-// CHECK-EXECUTE-ONLY-LONG-CALLS: error: option '-mexecute-only' cannot be specified with '-mlong-calls'
-// CHECK-NO-EXECUTE-ONLY-ASM: warning: argument unused during compilation: '-mexecute-only'
+// RUN:    | FileCheck %s -check-prefix CHECK-PURE-CODE-LONG-CALLS
+// CHECK-PURE-CODE-LONG-CALLS: error: option '-mpure-code' cannot be specified with '-mlong-calls'
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to