Index: clang/test/Driver/arm-execute-only.c =================================================================== --- clang/test/Driver/arm-execute-only.c +++ clang/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' Index: clang/test/Driver/cl-options.c =================================================================== --- clang/test/Driver/cl-options.c +++ clang/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: clang/test/Driver/darwin-version.c =================================================================== --- clang/test/Driver/darwin-version.c +++ clang/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: lld/Common/Reproduce.cpp =================================================================== --- lld/Common/Reproduce.cpp +++ lld/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: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/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/test/ELF/sectionstart.s =================================================================== --- lld/test/ELF/sectionstart.s +++ lld/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: llvm/include/llvm/Option/Arg.h =================================================================== --- llvm/include/llvm/Option/Arg.h +++ llvm/include/llvm/Option/Arg.h @@ -58,6 +58,11 @@ /// The argument values, as C strings. SmallVector 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 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 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/include/llvm/Option/Option.h =================================================================== --- llvm/include/llvm/Option/Option.h +++ llvm/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/lib/Option/Arg.cpp =================================================================== --- llvm/lib/Option/Arg.cpp +++ llvm/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/lib/Option/Option.cpp =================================================================== --- llvm/lib/Option/Option.cpp +++ llvm/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 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; +}