[lld] 5ce4e92 - [clang] Use a StringRef instead of a raw char pointer to store builtin and call information

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 23 04:02:15 PST 2022


On Fri, Dec 23, 2022 at 12:49 PM via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

>
> Author: serge-sans-paille
> Date: 2022-12-23T12:48:17+01:00
> New Revision: 5ce4e92264102de21760c94db9166afe8f71fcf6
>
> URL:
> https://github.com/llvm/llvm-project/commit/5ce4e92264102de21760c94db9166afe8f71fcf6
> DIFF:
> https://github.com/llvm/llvm-project/commit/5ce4e92264102de21760c94db9166afe8f71fcf6.diff
>
> LOG: [clang] Use a StringRef instead of a raw char pointer to store
> builtin and call information
>
> This avoids recomputing string length that is already known at compile
> time.
>
> It has a slight impact on preprocessing / compile time, see
>
>
> https://llvm-compile-time-tracker.com/compare.php?from=3f36d2d579d8b0e8824d9dd99bfa79f456858f88&to=e49640c507ddc6615b5e503144301c8e41f8f434&stat=instructions:u
>
> This is a recommit of 719d98dfa841c522d8d452f0685e503538415a53 with a
> change to llvm/utils/TableGen/OptParserEmitter.cpp to cope with GCC bug
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108158
>
> Differential Revision: https://reviews.llvm.org/D139881


Unfortunately, I still see a lot of build failures like this with gcc
12.2.1:

llvm-project/llvm/tools/llvm-mt/llvm-mt.cpp:59:1: error: modification of
‘<temporary>’ is not a constant expression

Nikita


>
>
> Added:
>
>
> Modified:
>     clang-tools-extra/clangd/CompileCommands.cpp
>     clang/include/clang/Basic/Builtins.h
>     clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
>     clang/lib/AST/ExprConstant.cpp
>     clang/lib/Basic/Builtins.cpp
>     clang/lib/CodeGen/CGBuiltin.cpp
>     clang/lib/Driver/DriverOptions.cpp
>     clang/lib/Sema/SemaChecking.cpp
>     clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
>     clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
>     clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
>     clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
>     clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
>     clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
>     clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
>     clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
>     clang/lib/StaticAnalyzer/Core/CallDescription.cpp
>     clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
>     clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp
>     clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
>     clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp
>     clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp
>     clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp
>     lld/COFF/DriverUtils.cpp
>     lld/ELF/DriverUtils.cpp
>     lld/MachO/DriverUtils.cpp
>     lld/MinGW/Driver.cpp
>     lld/wasm/Driver.cpp
>     lldb/tools/driver/Driver.cpp
>     lldb/tools/lldb-server/lldb-gdbserver.cpp
>     lldb/tools/lldb-vscode/lldb-vscode.cpp
>     llvm/include/llvm/ADT/ArrayRef.h
>     llvm/include/llvm/Option/OptTable.h
>     llvm/include/llvm/Option/Option.h
>     llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
>     llvm/lib/Option/OptTable.cpp
>     llvm/lib/Option/Option.cpp
>     llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
>     llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
>     llvm/tools/dsymutil/dsymutil.cpp
>     llvm/tools/llvm-cvtres/llvm-cvtres.cpp
>     llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
>     llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
>     llvm/tools/llvm-ifs/llvm-ifs.cpp
>     llvm/tools/llvm-lipo/llvm-lipo.cpp
>     llvm/tools/llvm-ml/llvm-ml.cpp
>     llvm/tools/llvm-mt/llvm-mt.cpp
>     llvm/tools/llvm-nm/llvm-nm.cpp
>     llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
>     llvm/tools/llvm-objdump/llvm-objdump.cpp
>     llvm/tools/llvm-rc/llvm-rc.cpp
>     llvm/tools/llvm-readobj/llvm-readobj.cpp
>     llvm/tools/llvm-size/llvm-size.cpp
>     llvm/tools/llvm-strings/llvm-strings.cpp
>     llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
>     llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
>     llvm/unittests/Option/OptionParsingTest.cpp
>     llvm/utils/TableGen/OptParserEmitter.cpp
>
> Removed:
>
>
>
>
> ################################################################################
> diff  --git a/clang-tools-extra/clangd/CompileCommands.cpp
> b/clang-tools-extra/clangd/CompileCommands.cpp
> index e88d92189c1fb..dbd2a8ada93f4 100644
> --- a/clang-tools-extra/clangd/CompileCommands.cpp
> +++ b/clang-tools-extra/clangd/CompileCommands.cpp
> @@ -466,8 +466,10 @@ llvm::ArrayRef<ArgStripper::Rule>
> ArgStripper::rulesFor(llvm::StringRef Arg) {
>        NextAlias[T] = Self;
>      };
>      // Also grab prefixes for each option, these are not fully exposed.
> -    const char *const *Prefixes[DriverID::LastOption] = {nullptr};
> -#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
> +    std::initializer_list<llvm::StringLiteral>
> Prefixes[DriverID::LastOption];
> +
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<llvm::StringLiteral> NAME =
> VALUE;
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELP, METAVAR, VALUES)
>       \
>    Prefixes[DriverID::OPT_##ID] = PREFIX;
> @@ -499,7 +501,7 @@ llvm::ArrayRef<ArgStripper::Rule>
> ArgStripper::rulesFor(llvm::StringRef Arg) {
>        llvm::SmallVector<Rule> Rules;
>        // Iterate over each alias, to add rules for parsing it.
>        for (unsigned A = ID; A != DriverID::OPT_INVALID; A = NextAlias[A])
> {
> -        if (Prefixes[A] == nullptr) // option groups.
> +        if (!Prefixes[A].size()) // option groups.
>            continue;
>          auto Opt = DriverTable.getOption(A);
>          // Exclude - and -foo pseudo-options.
> @@ -508,8 +510,8 @@ llvm::ArrayRef<ArgStripper::Rule>
> ArgStripper::rulesFor(llvm::StringRef Arg) {
>          auto Modes = getModes(Opt);
>          std::pair<unsigned, unsigned> ArgCount = getArgCount(Opt);
>          // Iterate over each spelling of the alias, e.g. -foo vs --foo.
> -        for (auto *Prefix = Prefixes[A]; *Prefix != nullptr; ++Prefix) {
> -          llvm::SmallString<64> Buf(*Prefix);
> +        for (StringRef Prefix : Prefixes[A]) {
> +          llvm::SmallString<64> Buf(Prefix);
>            Buf.append(Opt.getName());
>            llvm::StringRef Spelling =
> Result->try_emplace(Buf).first->getKey();
>            Rules.emplace_back();
>
> diff  --git a/clang/include/clang/Basic/Builtins.h
> b/clang/include/clang/Basic/Builtins.h
> index 5396477411106..6050ec47910ed 100644
> --- a/clang/include/clang/Basic/Builtins.h
> +++ b/clang/include/clang/Basic/Builtins.h
> @@ -57,7 +57,8 @@ enum ID {
>  };
>
>  struct Info {
> -  const char *Name, *Type, *Attributes, *HeaderName;
> +  llvm::StringRef Name;
> +  const char *Type, *Attributes, *HeaderName;
>    LanguageID Langs;
>    const char *Features;
>  };
> @@ -86,9 +87,7 @@ class Context {
>
>    /// Return the identifier name for the specified builtin,
>    /// e.g. "__builtin_abs".
> -  const char *getName(unsigned ID) const {
> -    return getRecord(ID).Name;
> -  }
> +  llvm::StringRef getName(unsigned ID) const { return getRecord(ID).Name;
> }
>
>    /// Get the type descriptor string for the specified builtin.
>    const char *getTypeString(unsigned ID) const {
>
> diff  --git
> a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
> b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
> index 368972d0382b5..091c3ce20e717 100644
> ---
> a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
> +++
> b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h
> @@ -63,13 +63,12 @@ class CallDescription {
>    /// @param RequiredArgs The number of arguments that is expected to
> match a
>    /// call. Omit this parameter to match every occurrence of call with a
> given
>    /// name regardless the number of arguments.
> -  CallDescription(CallDescriptionFlags Flags,
> -                  ArrayRef<const char *> QualifiedName,
> +  CallDescription(CallDescriptionFlags Flags, ArrayRef<StringRef>
> QualifiedName,
>                    MaybeCount RequiredArgs = std::nullopt,
>                    MaybeCount RequiredParams = std::nullopt);
>
>    /// Construct a CallDescription with default flags.
> -  CallDescription(ArrayRef<const char *> QualifiedName,
> +  CallDescription(ArrayRef<StringRef> QualifiedName,
>                    MaybeCount RequiredArgs = std::nullopt,
>                    MaybeCount RequiredParams = std::nullopt);
>
>
> diff  --git a/clang/lib/AST/ExprConstant.cpp
> b/clang/lib/AST/ExprConstant.cpp
> index 30a7b5880ec09..120ceb9ad0814 100644
> --- a/clang/lib/AST/ExprConstant.cpp
> +++ b/clang/lib/AST/ExprConstant.cpp
> @@ -9242,8 +9242,8 @@ bool
> PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
>    case Builtin::BIwmemchr:
>      if (Info.getLangOpts().CPlusPlus11)
>        Info.CCEDiag(E, diag::note_constexpr_invalid_function)
> -        << /*isConstexpr*/0 << /*isConstructor*/0
> -        << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) +
> "'");
> +          << /*isConstexpr*/ 0 << /*isConstructor*/ 0
> +          << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
>      else
>        Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
>      [[fallthrough]];
> @@ -9288,7 +9288,7 @@ bool
> PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
>      // FIXME: We can compare the bytes in the correct order.
>      if (IsRawByte && !isOneByteCharacterType(CharTy)) {
>        Info.FFDiag(E, diag::note_constexpr_memchr_unsupported)
> -          << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp)
> + "'")
> +          << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str()
>            << CharTy;
>        return false;
>      }
> @@ -9350,8 +9350,8 @@ bool
> PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
>    case Builtin::BIwmemmove:
>      if (Info.getLangOpts().CPlusPlus11)
>        Info.CCEDiag(E, diag::note_constexpr_invalid_function)
> -        << /*isConstexpr*/0 << /*isConstructor*/0
> -        << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) +
> "'");
> +          << /*isConstexpr*/ 0 << /*isConstructor*/ 0
> +          << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
>      else
>        Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
>      [[fallthrough]];
> @@ -12209,8 +12209,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const
> CallExpr *E,
>      // A call to strlen is not a constant expression.
>      if (Info.getLangOpts().CPlusPlus11)
>        Info.CCEDiag(E, diag::note_constexpr_invalid_function)
> -        << /*isConstexpr*/0 << /*isConstructor*/0
> -        << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) +
> "'");
> +          << /*isConstexpr*/ 0 << /*isConstructor*/ 0
> +          << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
>      else
>        Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
>      [[fallthrough]];
> @@ -12234,8 +12234,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const
> CallExpr *E,
>      // A call to strlen is not a constant expression.
>      if (Info.getLangOpts().CPlusPlus11)
>        Info.CCEDiag(E, diag::note_constexpr_invalid_function)
> -        << /*isConstexpr*/0 << /*isConstructor*/0
> -        << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) +
> "'");
> +          << /*isConstexpr*/ 0 << /*isConstructor*/ 0
> +          << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
>      else
>        Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
>      [[fallthrough]];
> @@ -12290,7 +12290,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const
> CallExpr *E,
>          !(isOneByteCharacterType(CharTy1) &&
> isOneByteCharacterType(CharTy2))) {
>        // FIXME: Consider using our bit_cast implementation to support
> this.
>        Info.FFDiag(E, diag::note_constexpr_memcmp_unsupported)
> -          << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp)
> + "'")
> +          << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str()
>            << CharTy1 << CharTy2;
>        return false;
>      }
>
> diff  --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp
> index 0e0566878c30c..375f474f84ad6 100644
> --- a/clang/lib/Basic/Builtins.cpp
> +++ b/clang/lib/Basic/Builtins.cpp
> @@ -18,8 +18,9 @@
>  #include "llvm/ADT/StringRef.h"
>  using namespace clang;
>
> -static const Builtin::Info BuiltinInfo[] = {
> -  { "not a builtin function", nullptr, nullptr, nullptr,
> ALL_LANGUAGES,nullptr},
> +static constexpr Builtin::Info BuiltinInfo[] = {
> +    {"not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES,
> +     nullptr},
>  #define BUILTIN(ID, TYPE, ATTRS)
>      \
>    { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
>  #define LANGBUILTIN(ID, TYPE, ATTRS, LANGS)
>       \
>
> diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp
> b/clang/lib/CodeGen/CGBuiltin.cpp
> index a194fc7b105cb..4efd4f15cf066 100644
> --- a/clang/lib/CodeGen/CGBuiltin.cpp
> +++ b/clang/lib/CodeGen/CGBuiltin.cpp
> @@ -134,7 +134,7 @@ llvm::Constant
> *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
>                   AIXLongDouble64Builtins.end())
>        Name = AIXLongDouble64Builtins[BuiltinID];
>      else
> -      Name = Context.BuiltinInfo.getName(BuiltinID) + 10;
> +      Name = Context.BuiltinInfo.getName(BuiltinID).substr(10);
>    }
>
>    llvm::FunctionType *Ty =
> @@ -5302,7 +5302,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const
> GlobalDecl GD, unsigned BuiltinID,
>      LargestVectorWidth = std::max(LargestVectorWidth, VectorWidth);
>
>    // See if we have a target specific intrinsic.
> -  const char *Name = getContext().BuiltinInfo.getName(BuiltinID);
> +  StringRef Name = getContext().BuiltinInfo.getName(BuiltinID);
>    Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic;
>    StringRef Prefix =
>        llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch());
>
> diff  --git a/clang/lib/Driver/DriverOptions.cpp
> b/clang/lib/Driver/DriverOptions.cpp
> index 169bb137c2896..a22e9b6f78fd2 100644
> --- a/clang/lib/Driver/DriverOptions.cpp
> +++ b/clang/lib/Driver/DriverOptions.cpp
> @@ -16,11 +16,12 @@ using namespace clang::driver;
>  using namespace clang::driver::options;
>  using namespace llvm::opt;
>
> -#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<llvm::StringLiteral> NAME =
> VALUE;
>  #include "clang/Driver/Options.inc"
>  #undef PREFIX
>
> -static constexpr  OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {PREFIX, NAME,  HELPTEXT,    METAVAR,     OPT_##ID,
> Option::KIND##Class,    \
>
> diff  --git a/clang/lib/Sema/SemaChecking.cpp
> b/clang/lib/Sema/SemaChecking.cpp
> index 67c4ea5812298..75296306c98e9 100644
> --- a/clang/lib/Sema/SemaChecking.cpp
> +++ b/clang/lib/Sema/SemaChecking.cpp
> @@ -6956,7 +6956,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult
> TheCallResult) {
>    // Get the decl for the concrete builtin from this, we can tell what the
>    // concrete integer type we should convert to is.
>    unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
> -  const char *NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID);
> +  StringRef NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID);
>    FunctionDecl *NewBuiltinDecl;
>    if (NewBuiltinID == BuiltinID)
>      NewBuiltinDecl = FDecl;
> @@ -11008,7 +11008,7 @@ static void emitReplacement(Sema &S,
> SourceLocation Loc, SourceRange Range,
>                              unsigned AbsKind, QualType ArgType) {
>    bool EmitHeaderHint = true;
>    const char *HeaderName = nullptr;
> -  const char *FunctionName = nullptr;
> +  StringRef FunctionName;
>    if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) {
>      FunctionName = "std::abs";
>      if (ArgType->isIntegralOrEnumerationType()) {
> @@ -11116,7 +11116,7 @@ void Sema::CheckAbsoluteValueFunction(const
> CallExpr *Call,
>    // Unsigned types cannot be negative.  Suggest removing the absolute
> value
>    // function call.
>    if (ArgType->isUnsignedIntegerType()) {
> -    const char *FunctionName =
> +    StringRef FunctionName =
>          IsStdAbs ? "std::abs" : Context.BuiltinInfo.getName(AbsKind);
>      Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType <<
> ParamType;
>      Diag(Call->getExprLoc(), diag::note_remove_abs)
>
> diff  --git
> a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
> b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
> index 4edf0e7cea7f8..615d994f2b275 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
> @@ -532,10 +532,10 @@ namespace {
>  class CFRetainReleaseChecker : public Checker<check::PreCall> {
>    mutable APIMisuse BT{this, "null passed to CF memory management
> function"};
>    const CallDescriptionSet ModelledCalls = {
> -      {"CFRetain", 1},
> -      {"CFRelease", 1},
> -      {"CFMakeCollectable", 1},
> -      {"CFAutorelease", 1},
> +      {{"CFRetain"}, 1},
> +      {{"CFRelease"}, 1},
> +      {{"CFMakeCollectable"}, 1},
> +      {{"CFAutorelease"}, 1},
>    };
>
>  public:
>
> diff  --git
> a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
> index 8416ab39e1943..76f091562cd57 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
> @@ -64,19 +64,15 @@ class BlockInCriticalSectionChecker : public
> Checker<check::PostCall> {
>  REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
>
>  BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
> -    : IILockGuard(nullptr), IIUniqueLock(nullptr),
> -      LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"),
> GetcFn("getc"),
> -      FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"),
> -      PthreadLockFn("pthread_mutex_lock"),
> -      PthreadTryLockFn("pthread_mutex_trylock"),
> -      PthreadUnlockFn("pthread_mutex_unlock"),
> -      MtxLock("mtx_lock"),
> -      MtxTimedLock("mtx_timedlock"),
> -      MtxTryLock("mtx_trylock"),
> -      MtxUnlock("mtx_unlock"),
> -      ClassLockGuard("lock_guard"),
> -      ClassUniqueLock("unique_lock"),
> -      IdentifierInfoInitialized(false) {
> +    : IILockGuard(nullptr), IIUniqueLock(nullptr), LockFn({"lock"}),
> +      UnlockFn({"unlock"}), SleepFn({"sleep"}), GetcFn({"getc"}),
> +      FgetsFn({"fgets"}), ReadFn({"read"}), RecvFn({"recv"}),
> +      PthreadLockFn({"pthread_mutex_lock"}),
> +      PthreadTryLockFn({"pthread_mutex_trylock"}),
> +      PthreadUnlockFn({"pthread_mutex_unlock"}), MtxLock({"mtx_lock"}),
> +      MtxTimedLock({"mtx_timedlock"}), MtxTryLock({"mtx_trylock"}),
> +      MtxUnlock({"mtx_unlock"}), ClassLockGuard("lock_guard"),
> +      ClassUniqueLock("unique_lock"), IdentifierInfoInitialized(false) {
>    // Initialize the bug type.
>    BlockInCritSectionBugType.reset(
>        new BugType(this, "Call to blocking function in critical section",
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
> index 09549534fcfd2..cd760b1ae62ec 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
> @@ -134,45 +134,46 @@ class CStringChecker : public Checker< eval::Call,
>                                       const CallExpr *)>;
>
>    CallDescriptionMap<FnCheck> Callbacks = {
> -      {{CDF_MaybeBuiltin, "memcpy", 3},
> +      {{CDF_MaybeBuiltin, {"memcpy"}, 3},
>         std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Regular)},
> -      {{CDF_MaybeBuiltin, "wmemcpy", 3},
> +      {{CDF_MaybeBuiltin, {"wmemcpy"}, 3},
>         std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Wide)},
> -      {{CDF_MaybeBuiltin, "mempcpy", 3},
> +      {{CDF_MaybeBuiltin, {"mempcpy"}, 3},
>         std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Regular)},
> -      {{CDF_None, "wmempcpy", 3},
> +      {{CDF_None, {"wmempcpy"}, 3},
>         std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Wide)},
> -      {{CDF_MaybeBuiltin, "memcmp", 3},
> +      {{CDF_MaybeBuiltin, {"memcmp"}, 3},
>         std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
> -      {{CDF_MaybeBuiltin, "wmemcmp", 3},
> +      {{CDF_MaybeBuiltin, {"wmemcmp"}, 3},
>         std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Wide)},
> -      {{CDF_MaybeBuiltin, "memmove", 3},
> +      {{CDF_MaybeBuiltin, {"memmove"}, 3},
>         std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Regular)},
> -      {{CDF_MaybeBuiltin, "wmemmove", 3},
> +      {{CDF_MaybeBuiltin, {"wmemmove"}, 3},
>         std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Wide)},
> -      {{CDF_MaybeBuiltin, "memset", 3}, &CStringChecker::evalMemset},
> -      {{CDF_MaybeBuiltin, "explicit_memset", 3},
> &CStringChecker::evalMemset},
> -      {{CDF_MaybeBuiltin, "strcpy", 2}, &CStringChecker::evalStrcpy},
> -      {{CDF_MaybeBuiltin, "strncpy", 3}, &CStringChecker::evalStrncpy},
> -      {{CDF_MaybeBuiltin, "stpcpy", 2}, &CStringChecker::evalStpcpy},
> -      {{CDF_MaybeBuiltin, "strlcpy", 3}, &CStringChecker::evalStrlcpy},
> -      {{CDF_MaybeBuiltin, "strcat", 2}, &CStringChecker::evalStrcat},
> -      {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat},
> -      {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat},
> -      {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength},
> -      {{CDF_MaybeBuiltin, "wcslen", 1}, &CStringChecker::evalstrLength},
> -      {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength},
> -      {{CDF_MaybeBuiltin, "wcsnlen", 2}, &CStringChecker::evalstrnLength},
> -      {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp},
> -      {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp},
> -      {{CDF_MaybeBuiltin, "strcasecmp", 2},
> &CStringChecker::evalStrcasecmp},
> -      {{CDF_MaybeBuiltin, "strncasecmp", 3},
> &CStringChecker::evalStrncasecmp},
> -      {{CDF_MaybeBuiltin, "strsep", 2}, &CStringChecker::evalStrsep},
> -      {{CDF_MaybeBuiltin, "bcopy", 3}, &CStringChecker::evalBcopy},
> -      {{CDF_MaybeBuiltin, "bcmp", 3},
> +      {{CDF_MaybeBuiltin, {"memset"}, 3}, &CStringChecker::evalMemset},
> +      {{CDF_MaybeBuiltin, {"explicit_memset"}, 3},
> &CStringChecker::evalMemset},
> +      {{CDF_MaybeBuiltin, {"strcpy"}, 2}, &CStringChecker::evalStrcpy},
> +      {{CDF_MaybeBuiltin, {"strncpy"}, 3}, &CStringChecker::evalStrncpy},
> +      {{CDF_MaybeBuiltin, {"stpcpy"}, 2}, &CStringChecker::evalStpcpy},
> +      {{CDF_MaybeBuiltin, {"strlcpy"}, 3}, &CStringChecker::evalStrlcpy},
> +      {{CDF_MaybeBuiltin, {"strcat"}, 2}, &CStringChecker::evalStrcat},
> +      {{CDF_MaybeBuiltin, {"strncat"}, 3}, &CStringChecker::evalStrncat},
> +      {{CDF_MaybeBuiltin, {"strlcat"}, 3}, &CStringChecker::evalStrlcat},
> +      {{CDF_MaybeBuiltin, {"strlen"}, 1}, &CStringChecker::evalstrLength},
> +      {{CDF_MaybeBuiltin, {"wcslen"}, 1}, &CStringChecker::evalstrLength},
> +      {{CDF_MaybeBuiltin, {"strnlen"}, 2},
> &CStringChecker::evalstrnLength},
> +      {{CDF_MaybeBuiltin, {"wcsnlen"}, 2},
> &CStringChecker::evalstrnLength},
> +      {{CDF_MaybeBuiltin, {"strcmp"}, 2}, &CStringChecker::evalStrcmp},
> +      {{CDF_MaybeBuiltin, {"strncmp"}, 3}, &CStringChecker::evalStrncmp},
> +      {{CDF_MaybeBuiltin, {"strcasecmp"}, 2},
> &CStringChecker::evalStrcasecmp},
> +      {{CDF_MaybeBuiltin, {"strncasecmp"}, 3},
> +       &CStringChecker::evalStrncasecmp},
> +      {{CDF_MaybeBuiltin, {"strsep"}, 2}, &CStringChecker::evalStrsep},
> +      {{CDF_MaybeBuiltin, {"bcopy"}, 3}, &CStringChecker::evalBcopy},
> +      {{CDF_MaybeBuiltin, {"bcmp"}, 3},
>         std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
> -      {{CDF_MaybeBuiltin, "bzero", 2}, &CStringChecker::evalBzero},
> -      {{CDF_MaybeBuiltin, "explicit_bzero", 2},
> &CStringChecker::evalBzero},
> +      {{CDF_MaybeBuiltin, {"bzero"}, 2}, &CStringChecker::evalBzero},
> +      {{CDF_MaybeBuiltin, {"explicit_bzero"}, 2},
> &CStringChecker::evalBzero},
>    };
>
>    // These require a bit of special handling.
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
> index ce8d6c8798703..9ace1583eb538 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
> @@ -43,7 +43,7 @@ class ChrootChecker : public Checker<eval::Call,
> check::PreCall> {
>    // This bug refers to possibly break out of a chroot() jail.
>    mutable std::unique_ptr<BuiltinBug> BT_BreakJail;
>
> -  const CallDescription Chroot{"chroot", 1}, Chdir{"chdir", 1};
> +  const CallDescription Chroot{{"chroot"}, 1}, Chdir{{"chdir"}, 1};
>
>  public:
>    ChrootChecker() {}
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
> b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
> index 77a3218f55fbb..67962f75f9bfa 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
> @@ -72,26 +72,26 @@ class ContainerModeling
>                                                     SVal) const;
>
>    CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
> -      {{"clear", 0}, &ContainerModeling::handleClear},
> -      {{"assign", 2}, &ContainerModeling::handleAssign},
> -      {{"push_back", 1}, &ContainerModeling::handlePushBack},
> -      {{"emplace_back", 1}, &ContainerModeling::handlePushBack},
> -      {{"pop_back", 0}, &ContainerModeling::handlePopBack},
> -      {{"push_front", 1}, &ContainerModeling::handlePushFront},
> -      {{"emplace_front", 1}, &ContainerModeling::handlePushFront},
> -      {{"pop_front", 0}, &ContainerModeling::handlePopFront},
> +      {{{"clear"}, 0}, &ContainerModeling::handleClear},
> +      {{{"assign"}, 2}, &ContainerModeling::handleAssign},
> +      {{{"push_back"}, 1}, &ContainerModeling::handlePushBack},
> +      {{{"emplace_back"}, 1}, &ContainerModeling::handlePushBack},
> +      {{{"pop_back"}, 0}, &ContainerModeling::handlePopBack},
> +      {{{"push_front"}, 1}, &ContainerModeling::handlePushFront},
> +      {{{"emplace_front"}, 1}, &ContainerModeling::handlePushFront},
> +      {{{"pop_front"}, 0}, &ContainerModeling::handlePopFront},
>    };
>
>    CallDescriptionMap<OneItParamFn> OneIterParamFunctions = {
> -      {{"insert", 2}, &ContainerModeling::handleInsert},
> -      {{"emplace", 2}, &ContainerModeling::handleInsert},
> -      {{"erase", 1}, &ContainerModeling::handleErase},
> -      {{"erase_after", 1}, &ContainerModeling::handleEraseAfter},
> +      {{{"insert"}, 2}, &ContainerModeling::handleInsert},
> +      {{{"emplace"}, 2}, &ContainerModeling::handleInsert},
> +      {{{"erase"}, 1}, &ContainerModeling::handleErase},
> +      {{{"erase_after"}, 1}, &ContainerModeling::handleEraseAfter},
>    };
>
>    CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = {
> -      {{"erase", 2}, &ContainerModeling::handleErase},
> -      {{"erase_after", 2}, &ContainerModeling::handleEraseAfter},
> +      {{{"erase"}, 2}, &ContainerModeling::handleErase},
> +      {{{"erase_after"}, 2}, &ContainerModeling::handleEraseAfter},
>    };
>  };
>
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
> b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
> index 47fd57c7db9bd..832bb78c48035 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
> @@ -41,9 +41,9 @@ class DebugContainerModeling
>                                                   CheckerContext &) const;
>
>    CallDescriptionMap<FnCheck> Callbacks = {
> -      {{"clang_analyzer_container_begin", 1},
> +      {{{"clang_analyzer_container_begin"}, 1},
>         &DebugContainerModeling::analyzerContainerBegin},
> -      {{"clang_analyzer_container_end", 1},
> +      {{{"clang_analyzer_container_end"}, 1},
>         &DebugContainerModeling::analyzerContainerEnd},
>    };
>
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
> b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
> index 6add9a007a87e..d05298b42c55c 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
> @@ -42,11 +42,11 @@ class DebugIteratorModeling
>                                                   CheckerContext &) const;
>
>    CallDescriptionMap<FnCheck> Callbacks = {
> -      {{"clang_analyzer_iterator_position", 1},
> +      {{{"clang_analyzer_iterator_position"}, 1},
>         &DebugIteratorModeling::analyzerIteratorPosition},
> -      {{"clang_analyzer_iterator_container", 1},
> +      {{{"clang_analyzer_iterator_container"}, 1},
>         &DebugIteratorModeling::analyzerIteratorContainer},
> -      {{"clang_analyzer_iterator_validity", 1},
> +      {{{"clang_analyzer_iterator_validity"}, 1},
>         &DebugIteratorModeling::analyzerIteratorValidity},
>    };
>
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
> b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
> index a9e249de38047..5f79c162f10df 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
> @@ -57,11 +57,11 @@ class ErrnoModeling
>
>  private:
>    // FIXME: Names from `ErrnoLocationFuncNames` are used to build this
> set.
> -  CallDescriptionSet ErrnoLocationCalls{{"__errno_location", 0, 0},
> -                                        {"___errno", 0, 0},
> -                                        {"__errno", 0, 0},
> -                                        {"_errno", 0, 0},
> -                                        {"__error", 0, 0}};
> +  CallDescriptionSet ErrnoLocationCalls{{{"__errno_location"}, 0, 0},
> +                                        {{"___errno"}, 0, 0},
> +                                        {{"__errno"}, 0, 0},
> +                                        {{"_errno"}, 0, 0},
> +                                        {{"__error"}, 0, 0}};
>  };
>
>  } // namespace
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
> index 924407ebe2d18..3b9ff0cca0fa3 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
> @@ -69,13 +69,13 @@ class ErrnoTesterChecker : public Checker<eval::Call> {
>
>    using EvalFn = std::function<void(CheckerContext &, const CallEvent &)>;
>    const CallDescriptionMap<EvalFn> TestCalls{
> -      {{"ErrnoTesterChecker_setErrno", 1},
> &ErrnoTesterChecker::evalSetErrno},
> -      {{"ErrnoTesterChecker_getErrno", 0},
> &ErrnoTesterChecker::evalGetErrno},
> -      {{"ErrnoTesterChecker_setErrnoIfError", 0},
> +      {{{"ErrnoTesterChecker_setErrno"}, 1},
> &ErrnoTesterChecker::evalSetErrno},
> +      {{{"ErrnoTesterChecker_getErrno"}, 0},
> &ErrnoTesterChecker::evalGetErrno},
> +      {{{"ErrnoTesterChecker_setErrnoIfError"}, 0},
>         &ErrnoTesterChecker::evalSetErrnoIfError},
> -      {{"ErrnoTesterChecker_setErrnoIfErrorRange", 0},
> +      {{{"ErrnoTesterChecker_setErrnoIfErrorRange"}, 0},
>         &ErrnoTesterChecker::evalSetErrnoIfErrorRange},
> -      {{"ErrnoTesterChecker_setErrnoCheckState", 0},
> +      {{{"ErrnoTesterChecker_setErrnoCheckState"}, 0},
>         &ErrnoTesterChecker::evalSetErrnoCheckState}};
>  };
>
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
> index 0f7973e740993..80f9f88816129 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
> @@ -304,7 +304,7 @@ struct GenericTaintRuleParser {
>                                   TaintConfiguration &&Config) const;
>
>  private:
> -  using NamePartsTy = llvm::SmallVector<SmallString<32>, 2>;
> +  using NamePartsTy = llvm::SmallVector<StringRef, 2>;
>
>    /// Validate part of the configuration, which contains a list of
> argument
>    /// indexes.
> @@ -444,10 +444,8 @@ GenericTaintRuleParser::parseNameParts(const Config
> &C) {
>    if (!C.Scope.empty()) {
>      // If the Scope argument contains multiple "::" parts, those are
> considered
>      // namespace identifiers.
> -    llvm::SmallVector<StringRef, 2> NSParts;
> -    StringRef{C.Scope}.split(NSParts, "::", /*MaxSplit*/ -1,
> +    StringRef{C.Scope}.split(NameParts, "::", /*MaxSplit*/ -1,
>                               /*KeepEmpty*/ false);
> -    NameParts.append(NSParts.begin(), NSParts.end());
>    }
>    NameParts.emplace_back(C.Name);
>    return NameParts;
> @@ -458,10 +456,7 @@ void
> GenericTaintRuleParser::consumeRulesFromConfig(const Config &C,
>                                                      GenericTaintRule
> &&Rule,
>                                                      RulesContTy &Rules) {
>    NamePartsTy NameParts = parseNameParts(C);
> -  llvm::SmallVector<const char *, 2> CallDescParts{NameParts.size()};
> -  llvm::transform(NameParts, CallDescParts.begin(),
> -                  [](SmallString<32> &S) { return S.c_str(); });
> -  Rules.emplace_back(CallDescription(CallDescParts), std::move(Rule));
> +  Rules.emplace_back(CallDescription(NameParts), std::move(Rule));
>  }
>
>  void GenericTaintRuleParser::parseConfig(const std::string &Option,
> @@ -531,128 +526,128 @@ void
> GenericTaintChecker::initTaintRules(CheckerContext &C) const {
>
>    RulesConstructionTy GlobalCRules{
>        // Sources
> -      {{"fdopen"}, TR::Source({{ReturnValueIndex}})},
> -      {{"fopen"}, TR::Source({{ReturnValueIndex}})},
> -      {{"freopen"}, TR::Source({{ReturnValueIndex}})},
> -      {{"getch"}, TR::Source({{ReturnValueIndex}})},
> -      {{"getchar"}, TR::Source({{ReturnValueIndex}})},
> -      {{"getchar_unlocked"}, TR::Source({{ReturnValueIndex}})},
> -      {{"gets"}, TR::Source({{0}, ReturnValueIndex})},
> -      {{"gets_s"}, TR::Source({{0}, ReturnValueIndex})},
> -      {{"scanf"}, TR::Source({{}, 1})},
> -      {{"scanf_s"}, TR::Source({{}, {1}})},
> -      {{"wgetch"}, TR::Source({{}, ReturnValueIndex})},
> +      {{{"fdopen"}}, TR::Source({{ReturnValueIndex}})},
> +      {{{"fopen"}}, TR::Source({{ReturnValueIndex}})},
> +      {{{"freopen"}}, TR::Source({{ReturnValueIndex}})},
> +      {{{"getch"}}, TR::Source({{ReturnValueIndex}})},
> +      {{{"getchar"}}, TR::Source({{ReturnValueIndex}})},
> +      {{{"getchar_unlocked"}}, TR::Source({{ReturnValueIndex}})},
> +      {{{"gets"}}, TR::Source({{0}, ReturnValueIndex})},
> +      {{{"gets_s"}}, TR::Source({{0}, ReturnValueIndex})},
> +      {{{"scanf"}}, TR::Source({{}, 1})},
> +      {{{"scanf_s"}}, TR::Source({{}, {1}})},
> +      {{{"wgetch"}}, TR::Source({{}, ReturnValueIndex})},
>        // Sometimes the line between taint sources and propagators is
> blurry.
>        // _IO_getc is choosen to be a source, but could also be a
> propagator.
>        // This way it is simpler, as modeling it as a propagator would
> require
>        // to model the possible sources of _IO_FILE * values, which the
> _IO_getc
>        // function takes as parameters.
> -      {{"_IO_getc"}, TR::Source({{ReturnValueIndex}})},
> -      {{"getcwd"}, TR::Source({{0, ReturnValueIndex}})},
> -      {{"getwd"}, TR::Source({{0, ReturnValueIndex}})},
> -      {{"readlink"}, TR::Source({{1, ReturnValueIndex}})},
> -      {{"readlinkat"}, TR::Source({{2, ReturnValueIndex}})},
> -      {{"get_current_dir_name"}, TR::Source({{ReturnValueIndex}})},
> -      {{"gethostname"}, TR::Source({{0}})},
> -      {{"getnameinfo"}, TR::Source({{2, 4}})},
> -      {{"getseuserbyname"}, TR::Source({{1, 2}})},
> -      {{"getgroups"}, TR::Source({{1, ReturnValueIndex}})},
> -      {{"getlogin"}, TR::Source({{ReturnValueIndex}})},
> -      {{"getlogin_r"}, TR::Source({{0}})},
> +      {{{"_IO_getc"}}, TR::Source({{ReturnValueIndex}})},
> +      {{{"getcwd"}}, TR::Source({{0, ReturnValueIndex}})},
> +      {{{"getwd"}}, TR::Source({{0, ReturnValueIndex}})},
> +      {{{"readlink"}}, TR::Source({{1, ReturnValueIndex}})},
> +      {{{"readlinkat"}}, TR::Source({{2, ReturnValueIndex}})},
> +      {{{"get_current_dir_name"}}, TR::Source({{ReturnValueIndex}})},
> +      {{{"gethostname"}}, TR::Source({{0}})},
> +      {{{"getnameinfo"}}, TR::Source({{2, 4}})},
> +      {{{"getseuserbyname"}}, TR::Source({{1, 2}})},
> +      {{{"getgroups"}}, TR::Source({{1, ReturnValueIndex}})},
> +      {{{"getlogin"}}, TR::Source({{ReturnValueIndex}})},
> +      {{{"getlogin_r"}}, TR::Source({{0}})},
>
>        // Props
> -      {{"atoi"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"atol"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"atoll"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"fgetc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"fgetln"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"fgets"}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
> -      {{"fscanf"}, TR::Prop({{0}}, {{}, 2})},
> -      {{"fscanf_s"}, TR::Prop({{0}}, {{}, {2}})},
> -      {{"sscanf"}, TR::Prop({{0}}, {{}, 2})},
> -
> -      {{"getc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"getc_unlocked"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"getdelim"}, TR::Prop({{3}}, {{0}})},
> -      {{"getline"}, TR::Prop({{2}}, {{0}})},
> -      {{"getw"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"pread"}, TR::Prop({{0, 1, 2, 3}}, {{1, ReturnValueIndex}})},
> -      {{"read"}, TR::Prop({{0, 2}}, {{1, ReturnValueIndex}})},
> -      {{"strchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"strrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"tolower"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"toupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"fread"}, TR::Prop({{3}}, {{0, ReturnValueIndex}})},
> -      {{"recv"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> -      {{"recvfrom"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> -
> -      {{"ttyname"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"ttyname_r"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> -
> -      {{"basename"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"dirname"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"fnmatch"}, TR::Prop({{1}}, {{ReturnValueIndex}})},
> -      {{"memchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"memrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"rawmemchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -
> -      {{"mbtowc"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> -      {{"wctomb"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> -      {{"wcwidth"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -
> -      {{"memcmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> -      {{"memcpy"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> -      {{"memmove"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> +      {{{"atoi"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"atol"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"atoll"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"fgetc"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"fgetln"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"fgets"}}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
> +      {{{"fscanf"}}, TR::Prop({{0}}, {{}, 2})},
> +      {{{"fscanf_s"}}, TR::Prop({{0}}, {{}, {2}})},
> +      {{{"sscanf"}}, TR::Prop({{0}}, {{}, 2})},
> +
> +      {{{"getc"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"getc_unlocked"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"getdelim"}}, TR::Prop({{3}}, {{0}})},
> +      {{{"getline"}}, TR::Prop({{2}}, {{0}})},
> +      {{{"getw"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"pread"}}, TR::Prop({{0, 1, 2, 3}}, {{1, ReturnValueIndex}})},
> +      {{{"read"}}, TR::Prop({{0, 2}}, {{1, ReturnValueIndex}})},
> +      {{{"strchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"strrchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"tolower"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"toupper"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"fread"}}, TR::Prop({{3}}, {{0, ReturnValueIndex}})},
> +      {{{"recv"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> +      {{{"recvfrom"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> +
> +      {{{"ttyname"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"ttyname_r"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> +
> +      {{{"basename"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"dirname"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"fnmatch"}}, TR::Prop({{1}}, {{ReturnValueIndex}})},
> +      {{{"memchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"memrchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"rawmemchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +
> +      {{{"mbtowc"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> +      {{{"wctomb"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> +      {{{"wcwidth"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +
> +      {{{"memcmp"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> +      {{{"memcpy"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> +      {{{"memmove"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
>        // If memmem was called with a tainted needle and the search was
>        // successful, that would mean that the value pointed by the return
> value
>        // has the same content as the needle. If we choose to go by the
> policy of
>        // content equivalence implies taintedness equivalence, that would
> mean
>        // haystack should be considered a propagation source argument.
> -      {{"memmem"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"memmem"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
>
>        // The comment for memmem above also applies to strstr.
> -      {{"strstr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"strcasestr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"strstr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"strcasestr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
>
> -      {{"strchrnul"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"strchrnul"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
>
> -      {{"index"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"rindex"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"index"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"rindex"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
>
>        // FIXME: In case of arrays, only the first element of the array
> gets
>        // tainted.
> -      {{"qsort"}, TR::Prop({{0}}, {{0}})},
> -      {{"qsort_r"}, TR::Prop({{0}}, {{0}})},
> -
> -      {{"strcmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> -      {{"strcasecmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> -      {{"strncmp"}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
> -      {{"strncasecmp"}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
> -      {{"strspn"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> -      {{"strcspn"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> -      {{"strpbrk"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"strndup"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"strndupa"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"strlen"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"strnlen"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"strtol"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> -      {{"strtoll"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> -      {{"strtoul"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> -      {{"strtoull"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> -
> -      {{"isalnum"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"isalpha"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"isascii"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"isblank"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"iscntrl"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"isdigit"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"isgraph"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"islower"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"isprint"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"ispunct"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"isspace"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"isupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> -      {{"isxdigit"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"qsort"}}, TR::Prop({{0}}, {{0}})},
> +      {{{"qsort_r"}}, TR::Prop({{0}}, {{0}})},
> +
> +      {{{"strcmp"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> +      {{{"strcasecmp"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> +      {{{"strncmp"}}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
> +      {{{"strncasecmp"}}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
> +      {{{"strspn"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> +      {{{"strcspn"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
> +      {{{"strpbrk"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"strndup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"strndupa"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"strlen"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"strnlen"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"strtol"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> +      {{{"strtoll"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> +      {{{"strtoul"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> +      {{{"strtoull"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
> +
> +      {{{"isalnum"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"isalpha"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"isascii"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"isblank"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"iscntrl"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"isdigit"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"isgraph"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"islower"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"isprint"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"ispunct"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"isspace"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"isupper"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{{"isxdigit"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
>
>        {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncat)}},
>         TR::Prop({{1, 2}}, {{0, ReturnValueIndex}})},
> @@ -660,37 +655,40 @@ void
> GenericTaintChecker::initTaintRules(CheckerContext &C) const {
>         TR::Prop({{1, 2}}, {{0}})},
>        {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcat)}},
>         TR::Prop({{1, 2}}, {{0}})},
> -      {{CDF_MaybeBuiltin, {"snprintf"}},
> +      {{CDF_MaybeBuiltin, {{"snprintf"}}},
>         TR::Prop({{1}, 3}, {{0, ReturnValueIndex}})},
> -      {{CDF_MaybeBuiltin, {"sprintf"}},
> +      {{CDF_MaybeBuiltin, {{"sprintf"}}},
>         TR::Prop({{1}, 2}, {{0, ReturnValueIndex}})},
> -      {{CDF_MaybeBuiltin, {"strcpy"}},
> +      {{CDF_MaybeBuiltin, {{"strcpy"}}},
>         TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> -      {{CDF_MaybeBuiltin, {"stpcpy"}},
> +      {{CDF_MaybeBuiltin, {{"stpcpy"}}},
>         TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> -      {{CDF_MaybeBuiltin, {"strcat"}},
> +      {{CDF_MaybeBuiltin, {{"strcat"}}},
>         TR::Prop({{1}}, {{0, ReturnValueIndex}})},
> -      {{CDF_MaybeBuiltin, {"strdup"}}, TR::Prop({{0}},
> {{ReturnValueIndex}})},
> -      {{CDF_MaybeBuiltin, {"strdupa"}}, TR::Prop({{0}},
> {{ReturnValueIndex}})},
> -      {{CDF_MaybeBuiltin, {"wcsdup"}}, TR::Prop({{0}},
> {{ReturnValueIndex}})},
> +      {{CDF_MaybeBuiltin, {{"strdup"}}}, TR::Prop({{0}},
> {{ReturnValueIndex}})},
> +      {{CDF_MaybeBuiltin, {{"strdupa"}}},
> +       TR::Prop({{0}}, {{ReturnValueIndex}})},
> +      {{CDF_MaybeBuiltin, {{"wcsdup"}}}, TR::Prop({{0}},
> {{ReturnValueIndex}})},
>
>        // Sinks
> -      {{"system"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> -      {{"popen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> -      {{"execl"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> -      {{"execle"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> -      {{"execlp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> -      {{"execvp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> -      {{"execvP"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> -      {{"execve"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> -      {{"dlopen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> -      {{CDF_MaybeBuiltin, {"malloc"}}, TR::Sink({{0}},
> MsgTaintedBufferSize)},
> -      {{CDF_MaybeBuiltin, {"calloc"}}, TR::Sink({{0}},
> MsgTaintedBufferSize)},
> -      {{CDF_MaybeBuiltin, {"alloca"}}, TR::Sink({{0}},
> MsgTaintedBufferSize)},
> -      {{CDF_MaybeBuiltin, {"memccpy"}}, TR::Sink({{3}},
> MsgTaintedBufferSize)},
> -      {{CDF_MaybeBuiltin, {"realloc"}}, TR::Sink({{1}},
> MsgTaintedBufferSize)},
> -      {{{"setproctitle"}}, TR::Sink({{0}, 1},
> MsgUncontrolledFormatString)},
> -      {{{"setproctitle_fast"}},
> +      {{{"system"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> +      {{{"popen"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> +      {{{"execl"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> +      {{{"execle"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> +      {{{"execlp"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> +      {{{"execvp"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> +      {{{"execvP"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> +      {{{"execve"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> +      {{{"dlopen"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
> +      {{CDF_MaybeBuiltin, {{"malloc"}}}, TR::Sink({{0}},
> MsgTaintedBufferSize)},
> +      {{CDF_MaybeBuiltin, {{"calloc"}}}, TR::Sink({{0}},
> MsgTaintedBufferSize)},
> +      {{CDF_MaybeBuiltin, {{"alloca"}}}, TR::Sink({{0}},
> MsgTaintedBufferSize)},
> +      {{CDF_MaybeBuiltin, {{"memccpy"}}},
> +       TR::Sink({{3}}, MsgTaintedBufferSize)},
> +      {{CDF_MaybeBuiltin, {{"realloc"}}},
> +       TR::Sink({{1}}, MsgTaintedBufferSize)},
> +      {{{{"setproctitle"}}}, TR::Sink({{0}, 1},
> MsgUncontrolledFormatString)},
> +      {{{{"setproctitle_fast"}}},
>         TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
>
>        // SinkProps
> @@ -706,7 +704,7 @@ void
> GenericTaintChecker::initTaintRules(CheckerContext &C) const {
>        {{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrndup)}},
>         TR::SinkProp({{1}}, {{0, 1}}, {{ReturnValueIndex}},
>                      MsgTaintedBufferSize)},
> -      {{CDF_MaybeBuiltin, {"bcopy"}},
> +      {{CDF_MaybeBuiltin, {{"bcopy"}}},
>         TR::SinkProp({{2}}, {{0, 2}}, {{1}}, MsgTaintedBufferSize)}};
>
>    // `getenv` returns taint only in untrusted environments.
> @@ -714,7 +712,7 @@ void
> GenericTaintChecker::initTaintRules(CheckerContext &C) const {
>      // void setproctitle_init(int argc, char *argv[], char *envp[])
>      GlobalCRules.push_back(
>          {{{"setproctitle_init"}}, TR::Sink({{1, 2}}, MsgCustomSink)});
> -    GlobalCRules.push_back({{"getenv"},
> TR::Source({{ReturnValueIndex}})});
> +    GlobalCRules.push_back({{{"getenv"}},
> TR::Source({{ReturnValueIndex}})});
>    }
>
>    StaticTaintRules.emplace(std::make_move_iterator(GlobalCRules.begin()),
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
> index 139bc0e99d78a..6952953627e30 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
> @@ -86,7 +86,7 @@ class MIGChecker : public Checker<check::PostCall,
> check::PreStmt<ReturnStmt>,
>  #undef CALL
>    };
>
> -  CallDescription OsRefRetain{"os_ref_retain", 1};
> +  CallDescription OsRefRetain{{"os_ref_retain"}, 1};
>
>    void checkReturnAux(const ReturnStmt *RS, CheckerContext &C) const;
>
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
> index 9f8017266bb93..aa24f1a03d145 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
> @@ -392,10 +392,10 @@ class MallocChecker
>                                       const CallEvent &Call,
> CheckerContext &C)>;
>
>    const CallDescriptionMap<CheckFn> FreeingMemFnMap{
> -      {{"free", 1}, &MallocChecker::checkFree},
> -      {{"if_freenameindex", 1}, &MallocChecker::checkIfFreeNameIndex},
> -      {{"kfree", 1}, &MallocChecker::checkFree},
> -      {{"g_free", 1}, &MallocChecker::checkFree},
> +      {{{"free"}, 1}, &MallocChecker::checkFree},
> +      {{{"if_freenameindex"}, 1}, &MallocChecker::checkIfFreeNameIndex},
> +      {{{"kfree"}, 1}, &MallocChecker::checkFree},
> +      {{{"g_free"}, 1}, &MallocChecker::checkFree},
>    };
>
>    bool isFreeingCall(const CallEvent &Call) const;
> @@ -404,41 +404,41 @@ class MallocChecker
>    friend class NoOwnershipChangeVisitor;
>
>    CallDescriptionMap<CheckFn> AllocatingMemFnMap{
> -      {{"alloca", 1}, &MallocChecker::checkAlloca},
> -      {{"_alloca", 1}, &MallocChecker::checkAlloca},
> -      {{"malloc", 1}, &MallocChecker::checkBasicAlloc},
> -      {{"malloc", 3}, &MallocChecker::checkKernelMalloc},
> -      {{"calloc", 2}, &MallocChecker::checkCalloc},
> -      {{"valloc", 1}, &MallocChecker::checkBasicAlloc},
> -      {{CDF_MaybeBuiltin, "strndup", 2}, &MallocChecker::checkStrdup},
> -      {{CDF_MaybeBuiltin, "strdup", 1}, &MallocChecker::checkStrdup},
> -      {{"_strdup", 1}, &MallocChecker::checkStrdup},
> -      {{"kmalloc", 2}, &MallocChecker::checkKernelMalloc},
> -      {{"if_nameindex", 1}, &MallocChecker::checkIfNameIndex},
> -      {{CDF_MaybeBuiltin, "wcsdup", 1}, &MallocChecker::checkStrdup},
> -      {{CDF_MaybeBuiltin, "_wcsdup", 1}, &MallocChecker::checkStrdup},
> -      {{"g_malloc", 1}, &MallocChecker::checkBasicAlloc},
> -      {{"g_malloc0", 1}, &MallocChecker::checkGMalloc0},
> -      {{"g_try_malloc", 1}, &MallocChecker::checkBasicAlloc},
> -      {{"g_try_malloc0", 1}, &MallocChecker::checkGMalloc0},
> -      {{"g_memdup", 2}, &MallocChecker::checkGMemdup},
> -      {{"g_malloc_n", 2}, &MallocChecker::checkGMallocN},
> -      {{"g_malloc0_n", 2}, &MallocChecker::checkGMallocN0},
> -      {{"g_try_malloc_n", 2}, &MallocChecker::checkGMallocN},
> -      {{"g_try_malloc0_n", 2}, &MallocChecker::checkGMallocN0},
> +      {{{"alloca"}, 1}, &MallocChecker::checkAlloca},
> +      {{{"_alloca"}, 1}, &MallocChecker::checkAlloca},
> +      {{{"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
> +      {{{"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
> +      {{{"calloc"}, 2}, &MallocChecker::checkCalloc},
> +      {{{"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
> +      {{CDF_MaybeBuiltin, {"strndup"}, 2}, &MallocChecker::checkStrdup},
> +      {{CDF_MaybeBuiltin, {"strdup"}, 1}, &MallocChecker::checkStrdup},
> +      {{{"_strdup"}, 1}, &MallocChecker::checkStrdup},
> +      {{{"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
> +      {{{"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
> +      {{CDF_MaybeBuiltin, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
> +      {{CDF_MaybeBuiltin, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
> +      {{{"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
> +      {{{"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
> +      {{{"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
> +      {{{"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
> +      {{{"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
> +      {{{"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
> +      {{{"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
> +      {{{"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
> +      {{{"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
>    };
>
>    CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
> -      {{"realloc", 2},
> +      {{{"realloc"}, 2},
>         std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
> -      {{"reallocf", 2},
> +      {{{"reallocf"}, 2},
>         std::bind(&MallocChecker::checkRealloc, _1, _2, _3, true)},
> -      {{"g_realloc", 2},
> +      {{{"g_realloc"}, 2},
>         std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
> -      {{"g_try_realloc", 2},
> +      {{{"g_try_realloc"}, 2},
>         std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
> -      {{"g_realloc_n", 3}, &MallocChecker::checkReallocN},
> -      {{"g_try_realloc_n", 3}, &MallocChecker::checkReallocN},
> +      {{{"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
> +      {{{"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
>    };
>
>    bool isMemCall(const CallEvent &Call) const;
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
> index 1906ca5c8f554..0b3d635a50a3f 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
> @@ -33,7 +33,7 @@ class MmapWriteExecChecker : public
> Checker<check::PreCall> {
>    static int ProtRead;
>    mutable std::unique_ptr<BugType> BT;
>  public:
> -  MmapWriteExecChecker() : MmapFn("mmap", 6), MprotectFn("mprotect", 3) {}
> +  MmapWriteExecChecker() : MmapFn({"mmap"}, 6), MprotectFn({"mprotect"},
> 3) {}
>    void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
>    int ProtExecOv;
>    int ProtReadOv;
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
> index e877dd119ff61..929bd6bc3eb39 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
> @@ -87,7 +87,7 @@ class PthreadLockChecker : public
> Checker<check::PostCall, check::DeadSymbols,
>                                                CheckerKind CheckKind)
> const;
>    CallDescriptionMap<FnCheck> PThreadCallbacks = {
>        // Init.
> -      {{"pthread_mutex_init", 2}, &PthreadLockChecker::InitAnyLock},
> +      {{{"pthread_mutex_init"}, 2}, &PthreadLockChecker::InitAnyLock},
>        // TODO: pthread_rwlock_init(2 arguments).
>        // TODO: lck_mtx_init(3 arguments).
>        // TODO: lck_mtx_alloc_init(2 arguments) => returns the mutex.
> @@ -95,74 +95,74 @@ class PthreadLockChecker : public
> Checker<check::PostCall, check::DeadSymbols,
>        // TODO: lck_rw_alloc_init(2 arguments) => returns the mutex.
>
>        // Acquire.
> -      {{"pthread_mutex_lock", 1},
> &PthreadLockChecker::AcquirePthreadLock},
> -      {{"pthread_rwlock_rdlock", 1},
> &PthreadLockChecker::AcquirePthreadLock},
> -      {{"pthread_rwlock_wrlock", 1},
> &PthreadLockChecker::AcquirePthreadLock},
> -      {{"lck_mtx_lock", 1}, &PthreadLockChecker::AcquireXNULock},
> -      {{"lck_rw_lock_exclusive", 1}, &PthreadLockChecker::AcquireXNULock},
> -      {{"lck_rw_lock_shared", 1}, &PthreadLockChecker::AcquireXNULock},
> +      {{{"pthread_mutex_lock"}, 1},
> &PthreadLockChecker::AcquirePthreadLock},
> +      {{{"pthread_rwlock_rdlock"}, 1},
> &PthreadLockChecker::AcquirePthreadLock},
> +      {{{"pthread_rwlock_wrlock"}, 1},
> &PthreadLockChecker::AcquirePthreadLock},
> +      {{{"lck_mtx_lock"}, 1}, &PthreadLockChecker::AcquireXNULock},
> +      {{{"lck_rw_lock_exclusive"}, 1},
> &PthreadLockChecker::AcquireXNULock},
> +      {{{"lck_rw_lock_shared"}, 1}, &PthreadLockChecker::AcquireXNULock},
>
>        // Try.
> -      {{"pthread_mutex_trylock", 1}, &PthreadLockChecker::TryPthreadLock},
> -      {{"pthread_rwlock_tryrdlock", 1},
> &PthreadLockChecker::TryPthreadLock},
> -      {{"pthread_rwlock_trywrlock", 1},
> &PthreadLockChecker::TryPthreadLock},
> -      {{"lck_mtx_try_lock", 1}, &PthreadLockChecker::TryXNULock},
> -      {{"lck_rw_try_lock_exclusive", 1}, &PthreadLockChecker::TryXNULock},
> -      {{"lck_rw_try_lock_shared", 1}, &PthreadLockChecker::TryXNULock},
> +      {{{"pthread_mutex_trylock"}, 1},
> &PthreadLockChecker::TryPthreadLock},
> +      {{{"pthread_rwlock_tryrdlock"}, 1},
> &PthreadLockChecker::TryPthreadLock},
> +      {{{"pthread_rwlock_trywrlock"}, 1},
> &PthreadLockChecker::TryPthreadLock},
> +      {{{"lck_mtx_try_lock"}, 1}, &PthreadLockChecker::TryXNULock},
> +      {{{"lck_rw_try_lock_exclusive"}, 1},
> &PthreadLockChecker::TryXNULock},
> +      {{{"lck_rw_try_lock_shared"}, 1}, &PthreadLockChecker::TryXNULock},
>
>        // Release.
> -      {{"pthread_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
> -      {{"pthread_rwlock_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
> -      {{"lck_mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
> -      {{"lck_rw_unlock_exclusive", 1},
> &PthreadLockChecker::ReleaseAnyLock},
> -      {{"lck_rw_unlock_shared", 1}, &PthreadLockChecker::ReleaseAnyLock},
> -      {{"lck_rw_done", 1}, &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"pthread_mutex_unlock"}, 1},
> &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"pthread_rwlock_unlock"}, 1},
> &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"lck_mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"lck_rw_unlock_exclusive"}, 1},
> &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"lck_rw_unlock_shared"}, 1},
> &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"lck_rw_done"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
>
>        // Destroy.
> -      {{"pthread_mutex_destroy", 1},
> &PthreadLockChecker::DestroyPthreadLock},
> -      {{"lck_mtx_destroy", 2}, &PthreadLockChecker::DestroyXNULock},
> +      {{{"pthread_mutex_destroy"}, 1},
> &PthreadLockChecker::DestroyPthreadLock},
> +      {{{"lck_mtx_destroy"}, 2}, &PthreadLockChecker::DestroyXNULock},
>        // TODO: pthread_rwlock_destroy(1 argument).
>        // TODO: lck_rw_destroy(2 arguments).
>    };
>
>    CallDescriptionMap<FnCheck> FuchsiaCallbacks = {
>        // Init.
> -      {{"spin_lock_init", 1}, &PthreadLockChecker::InitAnyLock},
> +      {{{"spin_lock_init"}, 1}, &PthreadLockChecker::InitAnyLock},
>
>        // Acquire.
> -      {{"spin_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
> -      {{"spin_lock_save", 3}, &PthreadLockChecker::AcquirePthreadLock},
> -      {{"sync_mutex_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
> -      {{"sync_mutex_lock_with_waiter", 1},
> +      {{{"spin_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
> +      {{{"spin_lock_save"}, 3}, &PthreadLockChecker::AcquirePthreadLock},
> +      {{{"sync_mutex_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
> +      {{{"sync_mutex_lock_with_waiter"}, 1},
>         &PthreadLockChecker::AcquirePthreadLock},
>
>        // Try.
> -      {{"spin_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock},
> -      {{"sync_mutex_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock},
> -      {{"sync_mutex_timedlock", 2}, &PthreadLockChecker::TryFuchsiaLock},
> +      {{{"spin_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
> +      {{{"sync_mutex_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
> +      {{{"sync_mutex_timedlock"}, 2},
> &PthreadLockChecker::TryFuchsiaLock},
>
>        // Release.
> -      {{"spin_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
> -      {{"spin_unlock_restore", 3}, &PthreadLockChecker::ReleaseAnyLock},
> -      {{"sync_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"spin_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"spin_unlock_restore"}, 3}, &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"sync_mutex_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
>    };
>
>    CallDescriptionMap<FnCheck> C11Callbacks = {
>        // Init.
> -      {{"mtx_init", 2}, &PthreadLockChecker::InitAnyLock},
> +      {{{"mtx_init"}, 2}, &PthreadLockChecker::InitAnyLock},
>
>        // Acquire.
> -      {{"mtx_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
> +      {{{"mtx_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
>
>        // Try.
> -      {{"mtx_trylock", 1}, &PthreadLockChecker::TryC11Lock},
> -      {{"mtx_timedlock", 2}, &PthreadLockChecker::TryC11Lock},
> +      {{{"mtx_trylock"}, 1}, &PthreadLockChecker::TryC11Lock},
> +      {{{"mtx_timedlock"}, 2}, &PthreadLockChecker::TryC11Lock},
>
>        // Release.
> -      {{"mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
> +      {{{"mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
>
>        // Destroy
> -      {{"mtx_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock},
> +      {{{"mtx_destroy"}, 1}, &PthreadLockChecker::DestroyPthreadLock},
>    };
>
>    ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state,
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
> index 8c87a548fd91e..9251c895614ca 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
> @@ -90,7 +90,7 @@ class SimpleStreamChecker : public
> Checker<check::PostCall,
>  REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
>
>  SimpleStreamChecker::SimpleStreamChecker()
> -    : OpenFn("fopen"), CloseFn("fclose", 1) {
> +    : OpenFn({"fopen"}), CloseFn({"fclose"}, 1) {
>    // Initialize the bug types.
>    DoubleCloseBugType.reset(
>        new BugType(this, "Double fclose", "Unix Stream API Error"));
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
> b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
> index 92eef20d2daaf..107ff5aa0d9d0 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
> @@ -85,10 +85,10 @@ class SmartPtrModeling
>    using SmartPtrMethodHandlerFn =
>        void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &)
> const;
>    CallDescriptionMap<SmartPtrMethodHandlerFn> SmartPtrMethodHandlers{
> -      {{"reset"}, &SmartPtrModeling::handleReset},
> -      {{"release"}, &SmartPtrModeling::handleRelease},
> -      {{"swap", 1}, &SmartPtrModeling::handleSwapMethod},
> -      {{"get"}, &SmartPtrModeling::handleGet}};
> +      {{{"reset"}}, &SmartPtrModeling::handleReset},
> +      {{{"release"}}, &SmartPtrModeling::handleRelease},
> +      {{{"swap"}, 1}, &SmartPtrModeling::handleSwapMethod},
> +      {{{"get"}}, &SmartPtrModeling::handleGet}};
>    const CallDescription StdSwapCall{{"std", "swap"}, 2};
>    const CallDescription StdMakeUniqueCall{{"std", "make_unique"}};
>    const CallDescription StdMakeUniqueForOverwriteCall{
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
> index fb90fc9c91ea3..b6516988c0876 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
> @@ -236,42 +236,43 @@ class StreamChecker : public Checker<check::PreCall,
> eval::Call,
>
>  private:
>    CallDescriptionMap<FnDescription> FnDescriptions = {
> -      {{"fopen"}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
> -      {{"freopen", 3},
> +      {{{"fopen"}}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
> +      {{{"freopen"}, 3},
>         {&StreamChecker::preFreopen, &StreamChecker::evalFreopen, 2}},
> -      {{"tmpfile"}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
> -      {{"fclose", 1},
> +      {{{"tmpfile"}}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
> +      {{{"fclose"}, 1},
>         {&StreamChecker::preDefault, &StreamChecker::evalFclose, 0}},
> -      {{"fread", 4},
> +      {{{"fread"}, 4},
>         {&StreamChecker::preFread,
>          std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, true),
> 3}},
> -      {{"fwrite", 4},
> +      {{{"fwrite"}, 4},
>         {&StreamChecker::preFwrite,
>          std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4,
> false), 3}},
> -      {{"fseek", 3}, {&StreamChecker::preFseek,
> &StreamChecker::evalFseek, 0}},
> -      {{"ftell", 1}, {&StreamChecker::preDefault, nullptr, 0}},
> -      {{"rewind", 1}, {&StreamChecker::preDefault, nullptr, 0}},
> -      {{"fgetpos", 2}, {&StreamChecker::preDefault, nullptr, 0}},
> -      {{"fsetpos", 2}, {&StreamChecker::preDefault, nullptr, 0}},
> -      {{"clearerr", 1},
> +      {{{"fseek"}, 3},
> +       {&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
> +      {{{"ftell"}, 1}, {&StreamChecker::preDefault, nullptr, 0}},
> +      {{{"rewind"}, 1}, {&StreamChecker::preDefault, nullptr, 0}},
> +      {{{"fgetpos"}, 2}, {&StreamChecker::preDefault, nullptr, 0}},
> +      {{{"fsetpos"}, 2}, {&StreamChecker::preDefault, nullptr, 0}},
> +      {{{"clearerr"}, 1},
>         {&StreamChecker::preDefault, &StreamChecker::evalClearerr, 0}},
> -      {{"feof", 1},
> +      {{{"feof"}, 1},
>         {&StreamChecker::preDefault,
>          std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4,
> ErrorFEof),
>          0}},
> -      {{"ferror", 1},
> +      {{{"ferror"}, 1},
>         {&StreamChecker::preDefault,
>          std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4,
> ErrorFError),
>          0}},
> -      {{"fileno", 1}, {&StreamChecker::preDefault, nullptr, 0}},
> +      {{{"fileno"}, 1}, {&StreamChecker::preDefault, nullptr, 0}},
>    };
>
>    CallDescriptionMap<FnDescription> FnTestDescriptions = {
> -      {{"StreamTesterChecker_make_feof_stream", 1},
> +      {{{"StreamTesterChecker_make_feof_stream"}, 1},
>         {nullptr,
>          std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4,
> ErrorFEof),
>          0}},
> -      {{"StreamTesterChecker_make_ferror_stream", 1},
> +      {{{"StreamTesterChecker_make_ferror_stream"}, 1},
>         {nullptr,
>          std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4,
>                    ErrorFError),
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
> index fbefd5f9ffdc9..2d1b873abf73f 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
> @@ -100,27 +100,26 @@ class ValistChecker : public Checker<check::PreCall,
> check::PreStmt<VAArgExpr>,
>  };
>
>  const SmallVector<ValistChecker::VAListAccepter, 15>
> -    ValistChecker::VAListAccepters = {
> -        {{"vfprintf", 3}, 2},
> -        {{"vfscanf", 3}, 2},
> -        {{"vprintf", 2}, 1},
> -        {{"vscanf", 2}, 1},
> -        {{"vsnprintf", 4}, 3},
> -        {{"vsprintf", 3}, 2},
> -        {{"vsscanf", 3}, 2},
> -        {{"vfwprintf", 3}, 2},
> -        {{"vfwscanf", 3}, 2},
> -        {{"vwprintf", 2}, 1},
> -        {{"vwscanf", 2}, 1},
> -        {{"vswprintf", 4}, 3},
> -        // vswprintf is the wide version of vsnprintf,
> -        // vsprintf has no wide version
> -        {{"vswscanf", 3}, 2}};
> -
> -const CallDescription
> -    ValistChecker::VaStart("__builtin_va_start", /*Args=*/2,
> /*Params=*/1),
> -    ValistChecker::VaCopy("__builtin_va_copy", 2),
> -    ValistChecker::VaEnd("__builtin_va_end", 1);
> +    ValistChecker::VAListAccepters = {{{{"vfprintf"}, 3}, 2},
> +                                      {{{"vfscanf"}, 3}, 2},
> +                                      {{{"vprintf"}, 2}, 1},
> +                                      {{{"vscanf"}, 2}, 1},
> +                                      {{{"vsnprintf"}, 4}, 3},
> +                                      {{{"vsprintf"}, 3}, 2},
> +                                      {{{"vsscanf"}, 3}, 2},
> +                                      {{{"vfwprintf"}, 3}, 2},
> +                                      {{{"vfwscanf"}, 3}, 2},
> +                                      {{{"vwprintf"}, 2}, 1},
> +                                      {{{"vwscanf"}, 2}, 1},
> +                                      {{{"vswprintf"}, 4}, 3},
> +                                      // vswprintf is the wide version of
> +                                      // vsnprintf, vsprintf has no wide
> version
> +                                      {{{"vswscanf"}, 3}, 2}};
> +
> +const CallDescription ValistChecker::VaStart({"__builtin_va_start"},
> /*Args=*/2,
> +                                             /*Params=*/1),
> +    ValistChecker::VaCopy({"__builtin_va_copy"}, 2),
> +    ValistChecker::VaEnd({"__builtin_va_end"}, 1);
>  } // end anonymous namespace
>
>  void ValistChecker::checkPreCall(const CallEvent &Call,
>
> diff  --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
> index 084789509533e..aae1a17bc0ae5 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
> @@ -39,11 +39,11 @@ class InvalidPtrChecker
>
>    // SEI CERT ENV31-C
>    const CallDescriptionMap<HandlerFn> EnvpInvalidatingFunctions = {
> -      {{"setenv", 3}, &InvalidPtrChecker::EnvpInvalidatingCall},
> -      {{"unsetenv", 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
> -      {{"putenv", 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
> -      {{"_putenv_s", 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
> -      {{"_wputenv_s", 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
> +      {{{"setenv"}, 3}, &InvalidPtrChecker::EnvpInvalidatingCall},
> +      {{{"unsetenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
> +      {{{"putenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
> +      {{{"_putenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
> +      {{{"_wputenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
>    };
>
>    void postPreviousReturnInvalidatingCall(const CallEvent &Call,
> @@ -51,13 +51,15 @@ class InvalidPtrChecker
>
>    // SEI CERT ENV34-C
>    const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions =
> {
> -      {{"getenv", 1},
> &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
> -      {{"setlocale", 2},
> +      {{{"getenv"}, 1},
> &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
> +      {{{"setlocale"}, 2},
>         &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
> -      {{"strerror", 1},
> &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
> -      {{"localeconv", 0},
> +      {{{"strerror"}, 1},
> +       &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
> +      {{{"localeconv"}, 0},
> +       &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
> +      {{{"asctime"}, 1},
>         &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
> -      {{"asctime", 1},
> &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
>    };
>
>  public:
>
> diff  --git
> a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
> b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
> index ed3bdafad084d..eae162cda6931 100644
> --- a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
> +++ b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
> @@ -30,7 +30,7 @@ class PutenvWithAutoChecker : public
> Checker<check::PostCall> {
>  private:
>    BugType BT{this, "'putenv' function should not be called with auto
> variables",
>               categories::SecurityError};
> -  const CallDescription Putenv{"putenv", 1};
> +  const CallDescription Putenv{{"putenv"}, 1};
>
>  public:
>    void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
>
> diff  --git a/clang/lib/StaticAnalyzer/Core/CallDescription.cpp
> b/clang/lib/StaticAnalyzer/Core/CallDescription.cpp
> index 44b61d0750af0..229fb4883ed29 100644
> --- a/clang/lib/StaticAnalyzer/Core/CallDescription.cpp
> +++ b/clang/lib/StaticAnalyzer/Core/CallDescription.cpp
> @@ -36,7 +36,7 @@ static MaybeCount readRequiredParams(MaybeCount
> RequiredArgs,
>  }
>
>  ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
> -                                       ArrayRef<const char *>
> QualifiedName,
> +                                       ArrayRef<StringRef> QualifiedName,
>                                         MaybeCount RequiredArgs /*= None*/,
>                                         MaybeCount RequiredParams /*=
> None*/)
>      : RequiredArgs(RequiredArgs),
> @@ -44,11 +44,12 @@
> ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
>        Flags(Flags) {
>    assert(!QualifiedName.empty());
>    this->QualifiedName.reserve(QualifiedName.size());
> -  llvm::copy(QualifiedName, std::back_inserter(this->QualifiedName));
> +  llvm::transform(QualifiedName, std::back_inserter(this->QualifiedName),
> +                  [](StringRef From) { return From.str(); });
>  }
>
>  /// Construct a CallDescription with default flags.
> -ento::CallDescription::CallDescription(ArrayRef<const char *>
> QualifiedName,
> +ento::CallDescription::CallDescription(ArrayRef<StringRef> QualifiedName,
>                                         MaybeCount RequiredArgs /*= None*/,
>                                         MaybeCount RequiredParams /*=
> None*/)
>      : CallDescription(CDF_None, QualifiedName, RequiredArgs,
> RequiredParams) {}
>
> diff  --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
> b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
> index 0d75ba02a280e..33711886766b1 100644
> --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
> +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
> @@ -121,11 +121,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "LinkerWrapperOpts.inc"
>  #undef PREFIX
>
> -static constexpr OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {PREFIX, NAME,  HELPTEXT,    METAVAR,     OPT_##ID,
> Option::KIND##Class,    \
>
> diff  --git
> a/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp
> b/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp
> index 832281766e437..26f69df5dddc1 100644
> --- a/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp
> +++ b/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp
> @@ -33,11 +33,11 @@ class InterestingnessTestChecker : public
> Checker<check::PreCall> {
>                                         const CallEvent &, CheckerContext
> &)>;
>
>    CallDescriptionMap<HandlerFn> Handlers = {
> -      {{"setInteresting", 1},
> &InterestingnessTestChecker::handleInteresting},
> -      {{"setNotInteresting", 1},
> +      {{{"setInteresting"}, 1},
> &InterestingnessTestChecker::handleInteresting},
> +      {{{"setNotInteresting"}, 1},
>         &InterestingnessTestChecker::handleNotInteresting},
> -      {{"check", 1}, &InterestingnessTestChecker::handleCheck},
> -      {{"bug", 1}, &InterestingnessTestChecker::handleBug},
> +      {{{"check"}, 1}, &InterestingnessTestChecker::handleCheck},
> +      {{{"bug"}, 1}, &InterestingnessTestChecker::handleBug},
>    };
>
>    void handleInteresting(const CallEvent &Call, CheckerContext &C) const;
>
> diff  --git a/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
> b/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
> index 991a45d30103b..14fb03545265b 100644
> --- a/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
> +++ b/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
> @@ -135,8 +135,8 @@ class CallDescriptionAction : public ASTFrontendAction
> {
>  TEST(CallDescription, SimpleNameMatching) {
>    EXPECT_TRUE(tooling::runToolOnCode(
>        std::unique_ptr<FrontendAction>(new CallDescriptionAction<>({
> -          {{"bar"}, false}, // false: there's no call to 'bar' in this
> code.
> -          {{"foo"}, true},  // true: there's a call to 'foo' in this code.
> +          {{{"bar"}}, false}, // false: there's no call to 'bar' in this
> code.
> +          {{{"foo"}}, true},  // true: there's a call to 'foo' in this
> code.
>        })),
>        "void foo(); void bar() { foo(); }"));
>  }
> @@ -144,8 +144,8 @@ TEST(CallDescription, SimpleNameMatching) {
>  TEST(CallDescription, RequiredArguments) {
>    EXPECT_TRUE(tooling::runToolOnCode(
>        std::unique_ptr<FrontendAction>(new CallDescriptionAction<>({
> -          {{"foo", 1}, true},
> -          {{"foo", 2}, false},
> +          {{{"foo"}, 1}, true},
> +          {{{"foo"}, 2}, false},
>        })),
>        "void foo(int); void foo(int, int); void bar() { foo(1); }"));
>  }
> @@ -153,8 +153,8 @@ TEST(CallDescription, RequiredArguments) {
>  TEST(CallDescription, LackOfRequiredArguments) {
>    EXPECT_TRUE(tooling::runToolOnCode(
>        std::unique_ptr<FrontendAction>(new CallDescriptionAction<>({
> -          {{"foo", std::nullopt}, true},
> -          {{"foo", 2}, false},
> +          {{{"foo"}, std::nullopt}, true},
> +          {{{"foo"}, 2}, false},
>        })),
>        "void foo(int); void foo(int, int); void bar() { foo(1); }"));
>  }
> @@ -479,7 +479,7 @@ TEST(CallDescription, NegativeMatchQualifiedNames) {
>        std::unique_ptr<FrontendAction>(new CallDescriptionAction<>({
>            {{{"foo", "bar"}}, false},
>            {{{"bar", "foo"}}, false},
> -          {{"foo"}, true},
> +          {{{"foo"}}, true},
>        })),
>        "void foo(); struct bar { void foo(); }; void test() { foo(); }"));
>  }
> @@ -488,7 +488,8 @@ TEST(CallDescription, MatchBuiltins) {
>    // Test CDF_MaybeBuiltin - a flag that allows matching weird builtins.
>    EXPECT_TRUE(tooling::runToolOnCode(
>        std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
> -          {{{"memset", 3}, false}, {{CDF_MaybeBuiltin, "memset", 3},
> true}})),
> +          {{{{"memset"}, 3}, false},
> +           {{CDF_MaybeBuiltin, {"memset"}, 3}, true}})),
>        "void foo() {"
>        "  int x;"
>        "  __builtin___memset_chk(&x, 0, sizeof(x),"
> @@ -499,8 +500,8 @@ TEST(CallDescription, MatchBuiltins) {
>      SCOPED_TRACE("multiple similar builtins");
>      EXPECT_TRUE(tooling::runToolOnCode(
>          std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
> -            {{{CDF_MaybeBuiltin, "memcpy", 3}, false},
> -             {{CDF_MaybeBuiltin, "wmemcpy", 3}, true}})),
> +            {{{CDF_MaybeBuiltin, {"memcpy"}, 3}, false},
> +             {{CDF_MaybeBuiltin, {"wmemcpy"}, 3}, true}})),
>          R"(void foo(wchar_t *x, wchar_t *y) {
>              __builtin_wmemcpy(x, y, sizeof(wchar_t));
>            })"));
> @@ -509,8 +510,8 @@ TEST(CallDescription, MatchBuiltins) {
>      SCOPED_TRACE("multiple similar builtins reversed order");
>      EXPECT_TRUE(tooling::runToolOnCode(
>          std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
> -            {{{CDF_MaybeBuiltin, "wmemcpy", 3}, true},
> -             {{CDF_MaybeBuiltin, "memcpy", 3}, false}})),
> +            {{{CDF_MaybeBuiltin, {"wmemcpy"}, 3}, true},
> +             {{CDF_MaybeBuiltin, {"memcpy"}, 3}, false}})),
>          R"(void foo(wchar_t *x, wchar_t *y) {
>              __builtin_wmemcpy(x, y, sizeof(wchar_t));
>            })"));
> @@ -518,8 +519,8 @@ TEST(CallDescription, MatchBuiltins) {
>    {
>      SCOPED_TRACE("lookbehind and lookahead mismatches");
>      EXPECT_TRUE(tooling::runToolOnCode(
> -        std::unique_ptr<FrontendAction>(
> -            new CallDescriptionAction<>({{{CDF_MaybeBuiltin, "func"},
> false}})),
> +        std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
> +            {{{CDF_MaybeBuiltin, {"func"}}, false}})),
>          R"(
>            void funcXXX();
>            void XXXfunc();
> @@ -533,8 +534,8 @@ TEST(CallDescription, MatchBuiltins) {
>    {
>      SCOPED_TRACE("lookbehind and lookahead matches");
>      EXPECT_TRUE(tooling::runToolOnCode(
> -        std::unique_ptr<FrontendAction>(
> -            new CallDescriptionAction<>({{{CDF_MaybeBuiltin, "func"},
> true}})),
> +        std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
> +            {{{CDF_MaybeBuiltin, {"func"}}, true}})),
>          R"(
>            void func();
>            void func_XXX();
> @@ -561,7 +562,7 @@ TEST(CallDescription, MatchBuiltins) {
>
>  class CallDescChecker
>      : public Checker<check::PreCall, check::PreStmt<CallExpr>> {
> -  CallDescriptionSet Set = {{"bar", 0}};
> +  CallDescriptionSet Set = {{{"bar"}, 0}};
>
>  public:
>    void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
>
> diff  --git a/clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp
> b/clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp
> index e6c07d6292338..d3eb4b7a94d32 100644
> --- a/clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp
> +++ b/clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp
> @@ -18,7 +18,7 @@ using namespace ento;
>
>  namespace {
>  class EvalCallBase : public Checker<eval::Call> {
> -  const CallDescription Foo = {"foo", 0};
> +  const CallDescription Foo = {{"foo"}, 0};
>
>  public:
>    bool evalCall(const CallEvent &Call, CheckerContext &C) const {
>
> diff  --git
> a/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp
> b/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp
> index c778b189aca78..3f36a6494bd4a 100644
> ---
> a/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp
> +++
> b/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp
> @@ -30,9 +30,9 @@ class FalsePositiveGenerator : public
> Checker<eval::Call> {
>    using HandlerFn = bool (Self::*)(const CallEvent &Call,
>                                     CheckerContext &) const;
>    CallDescriptionMap<HandlerFn> Callbacks = {
> -      {{"reachedWithContradiction", 0}, &Self::reachedWithContradiction},
> -      {{"reachedWithNoContradiction", 0},
> &Self::reachedWithNoContradiction},
> -      {{"reportIfCanBeTrue", 1}, &Self::reportIfCanBeTrue},
> +      {{{"reachedWithContradiction"}, 0},
> &Self::reachedWithContradiction},
> +      {{{"reachedWithNoContradiction"}, 0},
> &Self::reachedWithNoContradiction},
> +      {{{"reportIfCanBeTrue"}, 1}, &Self::reportIfCanBeTrue},
>    };
>
>    bool report(CheckerContext &C, ProgramStateRef State,
>
> diff  --git
> a/clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp
> b/clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp
> index a9700e6e7766d..69e29b47f9257 100644
> --- a/clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp
> +++ b/clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp
> @@ -86,17 +86,17 @@ class StatefulChecker : public Checker<check::PreCall>
> {
>
>  public:
>    void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
> -    if (CallDescription{"preventError", 0}.matches(Call)) {
> +    if (CallDescription{{"preventError"}, 0}.matches(Call)) {
>        C.addTransition(C.getState()->set<ErrorPrevented>(true));
>        return;
>      }
>
> -    if (CallDescription{"allowError", 0}.matches(Call)) {
> +    if (CallDescription{{"allowError"}, 0}.matches(Call)) {
>        C.addTransition(C.getState()->set<ErrorPrevented>(false));
>        return;
>      }
>
> -    if (CallDescription{"error", 0}.matches(Call)) {
> +    if (CallDescription{{"error"}, 0}.matches(Call)) {
>        if (C.getState()->get<ErrorPrevented>())
>          return;
>        const ExplodedNode *N = C.generateErrorNode();
>
> diff  --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
> index 26802f8beeb0b..9a8d88c38c376 100644
> --- a/lld/COFF/DriverUtils.cpp
> +++ b/lld/COFF/DriverUtils.cpp
> @@ -772,12 +772,13 @@ MemoryBufferRef
> convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
>  // Create OptTable
>
>  // Create prefix string literals used in Options.td
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<llvm::StringLiteral> NAME =
> VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
>  // Create table mapping all options defined in Options.td
> -static constexpr llvm::opt::OptTable::Info infoTable[] = {
> +static constexpr std::initializer_list<llvm::opt::OptTable::Info>
> infoTable = {
>  #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11,
> X12)      \
>    {X1, X2, X10,         X11,         OPT_##ID,
> llvm::opt::Option::KIND##Class, \
>     X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
>
> diff  --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp
> index 4915069bee3c6..9c31d13cc913f 100644
> --- a/lld/ELF/DriverUtils.cpp
> +++ b/lld/ELF/DriverUtils.cpp
> @@ -34,12 +34,13 @@ using namespace lld::elf;
>  // Create OptTable
>
>  // Create prefix string literals used in Options.td
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
>  // Create table mapping all options defined in Options.td
> -static constexpr opt::OptTable::Info optInfo[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> optInfo = {
>  #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11,
> X12)      \
>    {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,
>      \
>     X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
>
> diff  --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp
> index be03d88f5a720..efc8e32322954 100644
> --- a/lld/MachO/DriverUtils.cpp
> +++ b/lld/MachO/DriverUtils.cpp
> @@ -35,12 +35,13 @@ using namespace lld;
>  using namespace lld::macho;
>
>  // Create prefix string literals used in Options.td
> -#define PREFIX(NAME, VALUE) const char *NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
>  // Create table mapping all options defined in Options.td
> -static constexpr OptTable::Info optInfo[] = {
> +static constexpr std::initializer_list<OptTable::Info> optInfo = {
>  #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11,
> X12)      \
>    {X1, X2, X10,         X11,         OPT_##ID, Option::KIND##Class,
>       \
>     X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
>
> diff  --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp
> index cab2d0c97532b..b35fbd6b5c3fb 100644
> --- a/lld/MinGW/Driver.cpp
> +++ b/lld/MinGW/Driver.cpp
> @@ -61,12 +61,13 @@ enum {
>  };
>
>  // Create prefix string literals used in Options.td
> -#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<llvm::StringLiteral> NAME =
> VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
>  // Create table mapping all options defined in Options.td
> -static constexpr opt::OptTable::Info infoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> infoTable = {
>  #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11,
> X12)      \
>    {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,
>      \
>     X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
>
> diff  --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
> index 657156bde83c7..a3925a2519eb4 100644
> --- a/lld/wasm/Driver.cpp
> +++ b/lld/wasm/Driver.cpp
> @@ -101,12 +101,13 @@ bool link(ArrayRef<const char *> args,
> llvm::raw_ostream &stdoutOS,
>  }
>
>  // Create prefix string literals used in Options.td
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
>  // Create table mapping all options defined in Options.td
> -static constexpr opt::OptTable::Info optInfo[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> optInfo = {
>  #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11,
> X12)      \
>    {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,
>      \
>     X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
>
> diff  --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
> index 73152f350395f..76b0d7bf60a56 100644
> --- a/lldb/tools/driver/Driver.cpp
> +++ b/lldb/tools/driver/Driver.cpp
> @@ -59,7 +59,7 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE) constexpr llvm::StringLiteral NAME[] = VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
>
> diff  --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp
> b/lldb/tools/lldb-server/lldb-gdbserver.cpp
> index 4dd8a37ef3dad..8565c39efe9b6 100644
> --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp
> +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp
> @@ -278,7 +278,7 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE) constexpr llvm::StringLiteral NAME[] = VALUE;
>  #include "LLGSOptions.inc"
>  #undef PREFIX
>
>
> diff  --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp
> b/lldb/tools/lldb-vscode/lldb-vscode.cpp
> index a80d4a90e39b0..b2b7ea4e1d825 100644
> --- a/lldb/tools/lldb-vscode/lldb-vscode.cpp
> +++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp
> @@ -79,7 +79,7 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE) constexpr llvm::StringLiteral NAME[] = VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
>
> diff  --git a/llvm/include/llvm/ADT/ArrayRef.h
> b/llvm/include/llvm/ADT/ArrayRef.h
> index 09c6188469ea5..6f23de9a7136f 100644
> --- a/llvm/include/llvm/ADT/ArrayRef.h
> +++ b/llvm/include/llvm/ADT/ArrayRef.h
> @@ -74,12 +74,12 @@ namespace llvm {
>        : Data(&OneElt), Length(1) {}
>
>      /// Construct an ArrayRef from a pointer and length.
> -    /*implicit*/ ArrayRef(const T *data, size_t length)
> -      : Data(data), Length(length) {}
> +    constexpr /*implicit*/ ArrayRef(const T *data, size_t length)
> +        : Data(data), Length(length) {}
>
>      /// Construct an ArrayRef from a range.
> -    ArrayRef(const T *begin, const T *end)
> -      : Data(begin), Length(end - begin) {}
> +    constexpr ArrayRef(const T *begin, const T *end)
> +        : Data(begin), Length(end - begin) {}
>
>      /// Construct an ArrayRef from a SmallVector. This is templated in
> order to
>      /// avoid instantiating SmallVectorTemplateCommon<T> whenever we
> @@ -111,9 +111,9 @@ namespace llvm {
>  #pragma GCC diagnostic push
>  #pragma GCC diagnostic ignored "-Winit-list-lifetime"
>  #endif
> -    /*implicit*/ ArrayRef(const std::initializer_list<T> &Vec)
> -    : Data(Vec.begin() == Vec.end() ? (T*)nullptr : Vec.begin()),
> -      Length(Vec.size()) {}
> +    constexpr /*implicit*/ ArrayRef(const std::initializer_list<T> &Vec)
> +        : Data(Vec.begin() == Vec.end() ? (T *)nullptr : Vec.begin()),
> +          Length(Vec.size()) {}
>  #if LLVM_GNUC_PREREQ(9, 0, 0)
>  #pragma GCC diagnostic pop
>  #endif
>
> diff  --git a/llvm/include/llvm/Option/OptTable.h
> b/llvm/include/llvm/Option/OptTable.h
> index 10d67b1b34915..52354eb954559 100644
> --- a/llvm/include/llvm/Option/OptTable.h
> +++ b/llvm/include/llvm/Option/OptTable.h
> @@ -44,7 +44,7 @@ class OptTable {
>    struct Info {
>      /// A null terminated array of prefix strings to apply to name while
>      /// matching.
> -    const char *const *Prefixes;
> +    ArrayRef<StringLiteral> Prefixes;
>      StringRef Name;
>      const char *HelpText;
>      const char *MetaVar;
>
> diff  --git a/llvm/include/llvm/Option/Option.h
> b/llvm/include/llvm/Option/Option.h
> index 106f6863fca1c..9b35e81cd9914 100644
> --- a/llvm/include/llvm/Option/Option.h
> +++ b/llvm/include/llvm/Option/Option.h
> @@ -124,8 +124,9 @@ class Option {
>
>    /// Get the default prefix for this option.
>    StringRef getPrefix() const {
> -    const char *Prefix = *Info->Prefixes;
> -    return Prefix ? Prefix : StringRef();
> +    return Info->Prefixes.empty()
> +               ? StringRef()
> +               : static_cast<const StringRef &>(Info->Prefixes[0]);
>    }
>
>    /// Get the name of this option with the default prefix.
>
> diff  --git a/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
> b/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
> index 8c1c7e26c0833..10ed8a7ec61cd 100644
> --- a/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
> +++ b/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
> @@ -12,18 +12,21 @@
>
>  #include "COFFDirectiveParser.h"
>
> +#include <array>
> +
>  using namespace llvm;
>  using namespace jitlink;
>
>  #define DEBUG_TYPE "jitlink"
>
>  // Create prefix string literals used in Options.td
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "COFFOptions.inc"
>  #undef PREFIX
>
>  // Create table mapping all options defined in COFFOptions.td
> -static constexpr opt::OptTable::Info infoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> infoTable = {
>  #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11,
> X12)      \
>    {X1,
>      \
>     X2,
>      \
>
> diff  --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp
> index 786760f2c64ac..c21072bda4026 100644
> --- a/llvm/lib/Option/OptTable.cpp
> +++ b/llvm/lib/Option/OptTable.cpp
> @@ -62,12 +62,10 @@ static inline bool operator<(const OptTable::Info &A,
> const OptTable::Info &B) {
>    if (int N = StrCmpOptionName(A.Name, B.Name))
>      return N < 0;
>
> -  for (const char * const *APre = A.Prefixes,
> -                  * const *BPre = B.Prefixes;
> -                          *APre != nullptr && *BPre != nullptr; ++APre,
> ++BPre){
> -    if (int N = StrCmpOptionName(*APre, *BPre))
> +  for (size_t I = 0, K = std::min(A.Prefixes.size(), B.Prefixes.size());
> I != K;
> +       ++I)
> +    if (int N = StrCmpOptionName(A.Prefixes[I], B.Prefixes[I]))
>        return N < 0;
> -  }
>
>    // Names are the same, check that classes are in order; exactly one
>    // should be joined, and it should succeed the other.
> @@ -131,11 +129,8 @@ OptTable::OptTable(ArrayRef<Info> OptionInfos, bool
> IgnoreCase)
>    // Build prefixes.
>    for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions() + 1;
>                  i != e; ++i) {
> -    if (const char *const *P = getInfo(i).Prefixes) {
> -      for (; *P != nullptr; ++P) {
> -        PrefixesUnion.insert(*P);
> -      }
> -    }
> +    const auto &P = getInfo(i).Prefixes;
> +    PrefixesUnion.insert(P.begin(), P.end());
>    }
>
>    // Build prefix chars.
> @@ -168,8 +163,7 @@ static bool isInput(const StringSet<> &Prefixes,
> StringRef Arg) {
>  /// \returns Matched size. 0 means no match.
>  static unsigned matchOption(const OptTable::Info *I, StringRef Str,
>                              bool IgnoreCase) {
> -  for (const char * const *Pre = I->Prefixes; *Pre != nullptr; ++Pre) {
> -    StringRef Prefix(*Pre);
> +  for (auto Prefix : I->Prefixes) {
>      if (Str.startswith(Prefix)) {
>        StringRef Rest = Str.substr(Prefix.size());
>        bool Matched = IgnoreCase ? Rest.startswith_insensitive(I->Name)
> @@ -183,13 +177,10 @@ static unsigned matchOption(const OptTable::Info *I,
> StringRef Str,
>
>  // Returns true if one of the Prefixes + In.Names matches Option
>  static bool optionMatches(const OptTable::Info &In, StringRef Option) {
> -  if (In.Prefixes) {
> -    StringRef InName(In.Name);
> -    for (size_t I = 0; In.Prefixes[I]; I++)
> -      if (Option.endswith(InName))
> -        if (Option.slice(0, Option.size() - InName.size()) ==
> In.Prefixes[I])
> -          return true;
> -  }
> +  for (auto Prefix : In.Prefixes)
> +    if (Option.endswith(In.Name))
> +      if (Option.slice(0, Option.size() - In.Name.size()) == Prefix)
> +        return true;
>    return false;
>  }
>
> @@ -221,13 +212,13 @@ OptTable::findByPrefix(StringRef Cur, unsigned int
> DisableFlags) const {
>    std::vector<std::string> Ret;
>    for (size_t I = FirstSearchableIndex, E = OptionInfos.size(); I < E;
> I++) {
>      const Info &In = OptionInfos[I];
> -    if (!In.Prefixes || (!In.HelpText && !In.GroupID))
> +    if (In.Prefixes.empty() || (!In.HelpText && !In.GroupID))
>        continue;
>      if (In.Flags & DisableFlags)
>        continue;
>
> -    for (int I = 0; In.Prefixes[I]; I++) {
> -      std::string S = std::string(In.Prefixes[I]) + std::string(In.Name)
> + "\t";
> +    for (auto Prefix : In.Prefixes) {
> +      std::string S = (Prefix + In.Name + "\t").str();
>        if (In.HelpText)
>          S += In.HelpText;
>        if (StringRef(S).startswith(Cur) && S != std::string(Cur) + "\t")
> @@ -265,7 +256,7 @@ unsigned OptTable::findNearest(StringRef Option,
> std::string &NearestString,
>
>      // * Ignore positional argument option candidates (which do not
>      //   have prefixes).
> -    if (!CandidateInfo.Prefixes)
> +    if (CandidateInfo.Prefixes.empty())
>        continue;
>
>      // Now check if the candidate ends with a character commonly used when
> @@ -285,8 +276,7 @@ unsigned OptTable::findNearest(StringRef Option,
> std::string &NearestString,
>      // Consider each possible prefix for each candidate to find the most
>      // appropriate one. For example, if a user asks for "--helm", suggest
>      // "--help" over "-help".
> -    for (int P = 0;
> -         const char *const CandidatePrefix = CandidateInfo.Prefixes[P];
> P++) {
> +    for (auto CandidatePrefix : CandidateInfo.Prefixes) {
>        std::string Candidate = (CandidatePrefix + CandidateName).str();
>        StringRef CandidateRef = Candidate;
>        unsigned Distance =
>
> diff  --git a/llvm/lib/Option/Option.cpp b/llvm/lib/Option/Option.cpp
> index ebdba8949223b..1f1eb93bcca05 100644
> --- a/llvm/lib/Option/Option.cpp
> +++ b/llvm/lib/Option/Option.cpp
> @@ -58,11 +58,10 @@ void Option::print(raw_ostream &O) const {
>  #undef P
>    }
>
> -  if (Info->Prefixes) {
> +  if (!Info->Prefixes.empty()) {
>      O << " Prefixes:[";
> -    for (const char *const *Pre = Info->Prefixes; *Pre != nullptr; ++Pre)
> {
> -      O << '"' << *Pre << (*(Pre + 1) == nullptr ? "\"" : "\", ");
> -    }
> +    for (size_t I = 0, N = Info->Prefixes.size(); I != N; ++I)
> +      O << '"' << Info->Prefixes[I] << (I == N - 1 ? "\"" : "\", ");
>      O << ']';
>    }
>
>
> diff  --git a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
> b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
> index c8ef0d16983bd..9bdff119a3f4b 100644
> --- a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
> +++ b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
> @@ -37,11 +37,12 @@ enum {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
> -static constexpr llvm::opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11,
> X12)      \
>    {X1, X2, X10,         X11,         OPT_##ID,
> llvm::opt::Option::KIND##Class, \
>     X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
>
> diff  --git a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
> b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
> index 7f06ed097c031..74a20a4ab7421 100644
> --- a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
> +++ b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
> @@ -41,11 +41,12 @@ enum {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11,
> X12)      \
>    {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,
>      \
>     X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
>
> diff  --git a/llvm/tools/dsymutil/dsymutil.cpp
> b/llvm/tools/dsymutil/dsymutil.cpp
> index 5ed3b2bf609fa..7c4e3d99ffa5e 100644
> --- a/llvm/tools/dsymutil/dsymutil.cpp
> +++ b/llvm/tools/dsymutil/dsymutil.cpp
> @@ -63,11 +63,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
> b/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
> index b2be58b72d62a..6dbf0a7a91e54 100644
> --- a/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
> +++ b/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
> @@ -44,11 +44,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
> b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
> index 52a75eee64b54..bbf4b63081997 100644
> --- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
> +++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
> @@ -32,11 +32,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<llvm::StringLiteral> NAME =
> VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
> b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
> index eeb92a750e4ad..1c1ebdc6f790a 100644
> --- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
> +++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
> @@ -40,11 +40,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Options.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-ifs/llvm-ifs.cpp
> b/llvm/tools/llvm-ifs/llvm-ifs.cpp
> index bef280075b8bd..f64acf96826ea 100644
> --- a/llvm/tools/llvm-ifs/llvm-ifs.cpp
> +++ b/llvm/tools/llvm-ifs/llvm-ifs.cpp
> @@ -60,11 +60,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-lipo/llvm-lipo.cpp
> b/llvm/tools/llvm-lipo/llvm-lipo.cpp
> index b4a76e18d389d..78cda7566bc4e 100644
> --- a/llvm/tools/llvm-lipo/llvm-lipo.cpp
> +++ b/llvm/tools/llvm-lipo/llvm-lipo.cpp
> @@ -73,26 +73,27 @@ enum LipoID {
>  #undef OPTION
>  };
>
> -// LipoInfoTable below references LIPO_##PREFIX. OptionGroup has prefix
> nullptr.
> -constexpr const char *const *LIPO_nullptr = nullptr;
> -#define PREFIX(NAME, VALUE) const char *const LIPO_##NAME[] = VALUE;
> +namespace lipo {
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<llvm::StringLiteral> NAME =
> VALUE;
>  #include "LipoOpts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info LipoInfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> LipoInfoTable
> = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
> -  {LIPO_##PREFIX, NAME,      HELPTEXT,
>      \
> -   METAVAR,       LIPO_##ID, opt::Option::KIND##Class,
>      \
> -   PARAM,         FLAGS,     LIPO_##GROUP,
>      \
> -   LIPO_##ALIAS,  ALIASARGS, VALUES},
> +  {PREFIX,       NAME,      HELPTEXT,
>       \
> +   METAVAR,      LIPO_##ID, opt::Option::KIND##Class,
>       \
> +   PARAM,        FLAGS,     LIPO_##GROUP,
>       \
> +   LIPO_##ALIAS, ALIASARGS, VALUES},
>  #include "LipoOpts.inc"
>  #undef OPTION
>  };
> +} // namespace lipo
>
>  class LipoOptTable : public opt::OptTable {
>  public:
> -  LipoOptTable() : OptTable(LipoInfoTable) {}
> +  LipoOptTable() : OptTable(lipo::LipoInfoTable) {}
>  };
>
>  enum class LipoAction {
>
> diff  --git a/llvm/tools/llvm-ml/llvm-ml.cpp
> b/llvm/tools/llvm-ml/llvm-ml.cpp
> index 762658045f5b5..5c773bdae9502 100644
> --- a/llvm/tools/llvm-ml/llvm-ml.cpp
> +++ b/llvm/tools/llvm-ml/llvm-ml.cpp
> @@ -60,11 +60,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-mt/llvm-mt.cpp
> b/llvm/tools/llvm-mt/llvm-mt.cpp
> index 3f70c892ac68a..b6d57faed3369 100644
> --- a/llvm/tools/llvm-mt/llvm-mt.cpp
> +++ b/llvm/tools/llvm-mt/llvm-mt.cpp
> @@ -41,11 +41,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>  {
>       \
>
> diff  --git a/llvm/tools/llvm-nm/llvm-nm.cpp
> b/llvm/tools/llvm-nm/llvm-nm.cpp
> index 47644f07fd82d..953637ca678ed 100644
> --- a/llvm/tools/llvm-nm/llvm-nm.cpp
> +++ b/llvm/tools/llvm-nm/llvm-nm.cpp
> @@ -64,11 +64,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
> b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
> index bf39f8ce39051..287744be100c5 100644
> --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
> +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
> @@ -36,32 +36,27 @@ enum ObjcopyID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
> +namespace objcopy_opt {
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "ObjcopyOpts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info ObjcopyInfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info>
> ObjcopyInfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
> -  {OBJCOPY_##PREFIX,
>      \
> -   NAME,
>      \
> -   HELPTEXT,
>      \
> -   METAVAR,
>       \
> -   OBJCOPY_##ID,
>      \
> -   opt::Option::KIND##Class,
>      \
> -   PARAM,
>       \
> -   FLAGS,
>       \
> -   OBJCOPY_##GROUP,
>       \
> -   OBJCOPY_##ALIAS,
>       \
> -   ALIASARGS,
>       \
> -   VALUES},
> +  {PREFIX,          NAME,         HELPTEXT,
>       \
> +   METAVAR,         OBJCOPY_##ID, opt::Option::KIND##Class,
>       \
> +   PARAM,           FLAGS,        OBJCOPY_##GROUP,
>      \
> +   OBJCOPY_##ALIAS, ALIASARGS,    VALUES},
>  #include "ObjcopyOpts.inc"
>  #undef OPTION
>  };
> +} // namespace objcopy_opt
>
>  class ObjcopyOptTable : public opt::OptTable {
>  public:
> -  ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {
> +  ObjcopyOptTable() : OptTable(objcopy_opt::ObjcopyInfoTable) {
>      setGroupedShortOptions(true);
>    }
>  };
> @@ -75,15 +70,18 @@ enum InstallNameToolID {
>  #undef OPTION
>  };
>
> +namespace install_name_tool {
> +
>  #define PREFIX(NAME, VALUE)
>       \
> -  const char *const INSTALL_NAME_TOOL_##NAME[] = VALUE;
> +  constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "InstallNameToolOpts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InstallNameToolInfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info>
> +    InstallNameToolInfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
> -  {INSTALL_NAME_TOOL_##PREFIX,
>      \
> +  {PREFIX,
>      \
>     NAME,
>      \
>     HELPTEXT,
>      \
>     METAVAR,
>       \
> @@ -98,10 +96,12 @@ static constexpr opt::OptTable::Info
> InstallNameToolInfoTable[] = {
>  #include "InstallNameToolOpts.inc"
>  #undef OPTION
>  };
> +} // namespace install_name_tool
>
>  class InstallNameToolOptTable : public opt::OptTable {
>  public:
> -  InstallNameToolOptTable() : OptTable(InstallNameToolInfoTable) {}
> +  InstallNameToolOptTable()
> +      : OptTable(install_name_tool::InstallNameToolInfoTable) {}
>  };
>
>  enum BitcodeStripID {
> @@ -113,14 +113,18 @@ enum BitcodeStripID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const BITCODE_STRIP_##NAME[] =
> VALUE;
> +namespace bitcode_strip {
> +
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "BitcodeStripOpts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info BitcodeStripInfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info>
> +    BitcodeStripInfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
> -  {BITCODE_STRIP_##PREFIX,
>      \
> +  {PREFIX,
>      \
>     NAME,
>      \
>     HELPTEXT,
>      \
>     METAVAR,
>       \
> @@ -135,10 +139,11 @@ static constexpr opt::OptTable::Info
> BitcodeStripInfoTable[] = {
>  #include "BitcodeStripOpts.inc"
>  #undef OPTION
>  };
> +} // namespace bitcode_strip
>
>  class BitcodeStripOptTable : public opt::OptTable {
>  public:
> -  BitcodeStripOptTable() : OptTable(BitcodeStripInfoTable) {}
> +  BitcodeStripOptTable() : OptTable(bitcode_strip::BitcodeStripInfoTable)
> {}
>  };
>
>  enum StripID {
> @@ -150,24 +155,29 @@ enum StripID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
> +namespace strip {
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "StripOpts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info StripInfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info>
> StripInfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
> -  {STRIP_##PREFIX, NAME,       HELPTEXT,
>      \
> -   METAVAR,        STRIP_##ID, opt::Option::KIND##Class,
>      \
> -   PARAM,          FLAGS,      STRIP_##GROUP,
>       \
> -   STRIP_##ALIAS,  ALIASARGS,  VALUES},
> +  {PREFIX,        NAME,       HELPTEXT,
>       \
> +   METAVAR,       STRIP_##ID, opt::Option::KIND##Class,
>       \
> +   PARAM,         FLAGS,      STRIP_##GROUP,
>      \
> +   STRIP_##ALIAS, ALIASARGS,  VALUES},
>  #include "StripOpts.inc"
>  #undef OPTION
>  };
> +} // namespace strip
>
>  class StripOptTable : public opt::OptTable {
>  public:
> -  StripOptTable() : OptTable(StripInfoTable) {
> setGroupedShortOptions(true); }
> +  StripOptTable() : OptTable(strip::StripInfoTable) {
> +    setGroupedShortOptions(true);
> +  }
>  };
>
>  } // namespace
>
> diff  --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp
> b/llvm/tools/llvm-objdump/llvm-objdump.cpp
> index bb02cd016938c..5cd6acbc63f87 100644
> --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
> +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
> @@ -119,28 +119,29 @@ class CommonOptTable : public opt::OptTable {
>  };
>
>  // ObjdumpOptID is in ObjdumpOptID.h
> -
> -#define PREFIX(NAME, VALUE) const char *const OBJDUMP_##NAME[] = VALUE;
> +namespace objdump_opt {
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "ObjdumpOpts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info ObjdumpInfoTable[] = {
> -#define OBJDUMP_nullptr nullptr
> +static constexpr std::initializer_list<opt::OptTable::Info>
> ObjdumpInfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
> -  {OBJDUMP_##PREFIX, NAME,         HELPTEXT,
>      \
> -   METAVAR,          OBJDUMP_##ID, opt::Option::KIND##Class,
>      \
> -   PARAM,            FLAGS,        OBJDUMP_##GROUP,
>       \
> -   OBJDUMP_##ALIAS,  ALIASARGS,    VALUES},
> +  {PREFIX,          NAME,         HELPTEXT,
>       \
> +   METAVAR,         OBJDUMP_##ID, opt::Option::KIND##Class,
>       \
> +   PARAM,           FLAGS,        OBJDUMP_##GROUP,
>      \
> +   OBJDUMP_##ALIAS, ALIASARGS,    VALUES},
>  #include "ObjdumpOpts.inc"
>  #undef OPTION
> -#undef OBJDUMP_nullptr
>  };
> +} // namespace objdump_opt
>
>  class ObjdumpOptTable : public CommonOptTable {
>  public:
>    ObjdumpOptTable()
> -      : CommonOptTable(ObjdumpInfoTable, " [options] <input object
> files>",
> +      : CommonOptTable(objdump_opt::ObjdumpInfoTable,
> +                       " [options] <input object files>",
>                         "llvm object file dumper") {}
>  };
>
> @@ -153,27 +154,28 @@ enum OtoolOptID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const OTOOL_##NAME[] = VALUE;
> +namespace otool {
> +#define PREFIX(NAME, VALUE)
>       \
> +  constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "OtoolOpts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info OtoolInfoTable[] = {
> -#define OTOOL_nullptr nullptr
> +static constexpr std::initializer_list<opt::OptTable::Info>
> OtoolInfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
> -  {OTOOL_##PREFIX, NAME,       HELPTEXT,
>      \
> -   METAVAR,        OTOOL_##ID, opt::Option::KIND##Class,
>      \
> -   PARAM,          FLAGS,      OTOOL_##GROUP,
>       \
> -   OTOOL_##ALIAS,  ALIASARGS,  VALUES},
> +  {PREFIX,        NAME,       HELPTEXT,
>       \
> +   METAVAR,       OTOOL_##ID, opt::Option::KIND##Class,
>       \
> +   PARAM,         FLAGS,      OTOOL_##GROUP,
>      \
> +   OTOOL_##ALIAS, ALIASARGS,  VALUES},
>  #include "OtoolOpts.inc"
>  #undef OPTION
> -#undef OTOOL_nullptr
>  };
> +} // namespace otool
>
>  class OtoolOptTable : public CommonOptTable {
>  public:
>    OtoolOptTable()
> -      : CommonOptTable(OtoolInfoTable, " [option...] [file...]",
> +      : CommonOptTable(otool::OtoolInfoTable, " [option...] [file...]",
>                         "Mach-O object file displaying tool") {}
>  };
>
>
> diff  --git a/llvm/tools/llvm-rc/llvm-rc.cpp
> b/llvm/tools/llvm-rc/llvm-rc.cpp
> index 00fb9c1f74809..ff21213fc300e 100644
> --- a/llvm/tools/llvm-rc/llvm-rc.cpp
> +++ b/llvm/tools/llvm-rc/llvm-rc.cpp
> @@ -55,11 +55,13 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +namespace rc_opt {
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
> @@ -70,10 +72,11 @@ static constexpr opt::OptTable::Info InfoTable[] = {
>  #include "Opts.inc"
>  #undef OPTION
>  };
> +} // namespace rc_opt
>
>  class RcOptTable : public opt::OptTable {
>  public:
> -  RcOptTable() : OptTable(InfoTable, /* IgnoreCase = */ true) {}
> +  RcOptTable() : OptTable(rc_opt::InfoTable, /* IgnoreCase = */ true) {}
>  };
>
>  enum Windres_ID {
> @@ -85,25 +88,28 @@ enum Windres_ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const WINDRES_##NAME[] = VALUE;
> +namespace windres_opt {
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "WindresOpts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info WindresInfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
> -  {
>       \
> -      WINDRES_##PREFIX, NAME,         HELPTEXT,
>       \
> -      METAVAR,          WINDRES_##ID, opt::Option::KIND##Class,
>       \
> -      PARAM,            FLAGS,        WINDRES_##GROUP,
>      \
> -      WINDRES_##ALIAS,  ALIASARGS,    VALUES},
> +  {PREFIX,          NAME,         HELPTEXT,
>       \
> +   METAVAR,         WINDRES_##ID, opt::Option::KIND##Class,
>       \
> +   PARAM,           FLAGS,        WINDRES_##GROUP,
>      \
> +   WINDRES_##ALIAS, ALIASARGS,    VALUES},
>  #include "WindresOpts.inc"
>  #undef OPTION
>  };
> +} // namespace windres_opt
>
>  class WindresOptTable : public opt::OptTable {
>  public:
> -  WindresOptTable() : OptTable(WindresInfoTable, /* IgnoreCase = */
> false) {}
> +  WindresOptTable()
> +      : OptTable(windres_opt::InfoTable, /* IgnoreCase = */ false) {}
>  };
>
>  static ExitOnError ExitOnErr;
>
> diff  --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp
> b/llvm/tools/llvm-readobj/llvm-readobj.cpp
> index 7cb20360308d9..57598b084e84b 100644
> --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
> +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
> @@ -61,11 +61,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-size/llvm-size.cpp
> b/llvm/tools/llvm-size/llvm-size.cpp
> index de2e285fb5cdd..884f6f029e5c0 100644
> --- a/llvm/tools/llvm-size/llvm-size.cpp
> +++ b/llvm/tools/llvm-size/llvm-size.cpp
> @@ -47,11 +47,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-strings/llvm-strings.cpp
> b/llvm/tools/llvm-strings/llvm-strings.cpp
> index 918ca5f9ff1a3..afaa00ba5040a 100644
> --- a/llvm/tools/llvm-strings/llvm-strings.cpp
> +++ b/llvm/tools/llvm-strings/llvm-strings.cpp
> @@ -39,11 +39,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
> b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
> index 833506aa7ee9e..b7e7fd2abb806 100644
> --- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
> +++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
> @@ -56,11 +56,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
> b/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
> index 05fb5ffb7392a..fa5ef6df948f9 100644
> --- a/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
> +++ b/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
> @@ -35,11 +35,12 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> -static constexpr opt::OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<opt::OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {
>       \
>
> diff  --git a/llvm/unittests/Option/OptionParsingTest.cpp
> b/llvm/unittests/Option/OptionParsingTest.cpp
> index 1857345309b71..2f10e2622e424 100644
> --- a/llvm/unittests/Option/OptionParsingTest.cpp
> +++ b/llvm/unittests/Option/OptionParsingTest.cpp
> @@ -25,7 +25,8 @@ enum ID {
>  #undef OPTION
>  };
>
> -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#define PREFIX(NAME, VALUE)
>       \
> +  static constexpr std::initializer_list<StringLiteral> NAME = VALUE;
>  #include "Opts.inc"
>  #undef PREFIX
>
> @@ -35,7 +36,7 @@ enum OptionFlags {
>    OptFlag3 = (1 << 6)
>  };
>
> -static constexpr OptTable::Info InfoTable[] = {
> +static constexpr std::initializer_list<OptTable::Info> InfoTable = {
>  #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS,
> PARAM,  \
>                 HELPTEXT, METAVAR, VALUES)
>       \
>    {PREFIX, NAME,  HELPTEXT,    METAVAR,     OPT_##ID,
> Option::KIND##Class,    \
>
> diff  --git a/llvm/utils/TableGen/OptParserEmitter.cpp
> b/llvm/utils/TableGen/OptParserEmitter.cpp
> index e8bc9daaea49d..e734b8f48b455 100644
> --- a/llvm/utils/TableGen/OptParserEmitter.cpp
> +++ b/llvm/utils/TableGen/OptParserEmitter.cpp
> @@ -54,9 +54,10 @@ static std::string getOptionSpelling(const Record &R) {
>
>  static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) {
>    size_t PrefixLength;
> -  OS << "llvm::StringRef(&";
> -  write_cstring(OS, StringRef(getOptionSpelling(R, PrefixLength)));
> -  OS << "[" << PrefixLength << "], " << R.getValueAsString("Name").size()
> << ")";
> +  OS << "llvm::StringLiteral(";
> +  write_cstring(
> +      OS, StringRef(getOptionSpelling(R,
> PrefixLength)).substr(PrefixLength));
> +  OS << ")";
>  }
>
>  class MarshallingInfo {
> @@ -251,8 +252,8 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream
> &OS) {
>      // Prefix values.
>      OS << ", {";
>      for (const auto &PrefixKey : Prefix.first)
> -      OS << "\"" << PrefixKey << "\" COMMA ";
> -    OS << "nullptr})\n";
> +      OS << "llvm::StringLiteral(\"" << PrefixKey << "\") COMMA ";
> +    OS << "})\n";
>    }
>    OS << "#undef COMMA\n";
>    OS << "#endif // PREFIX\n\n";
> @@ -265,7 +266,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream
> &OS) {
>      OS << "OPTION(";
>
>      // The option prefix;
> -    OS << "nullptr";
> +    OS << "{}";
>
>      // The option string.
>      OS << ", \"" << R.getValueAsString("Name") << '"';
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20221223/cde7c380/attachment-0001.html>


More information about the llvm-commits mailing list