2018-03-26 21:45:04 +00:00
|
|
|
//===- CompilerInvocation.cpp ---------------------------------------------===//
|
2009-11-17 06:02:29 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2009-11-17 06:02:29 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2016-07-18 19:02:11 +00:00
|
|
|
#include "clang/Frontend/CompilerInvocation.h"
|
2015-11-03 18:33:07 +00:00
|
|
|
#include "TestModuleFileExtension.h"
|
2016-01-06 14:35:46 +00:00
|
|
|
#include "clang/Basic/Builtins.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/Basic/CharInfo.h"
|
2018-12-11 03:18:39 +00:00
|
|
|
#include "clang/Basic/CodeGenOptions.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/Basic/CommentOptions.h"
|
|
|
|
#include "clang/Basic/DebugInfoOptions.h"
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2020-11-17 10:43:02 -08:00
|
|
|
#include "clang/Basic/DiagnosticDriver.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/Basic/DiagnosticOptions.h"
|
|
|
|
#include "clang/Basic/FileSystemOptions.h"
|
|
|
|
#include "clang/Basic/LLVM.h"
|
|
|
|
#include "clang/Basic/LangOptions.h"
|
2019-08-05 13:59:26 +00:00
|
|
|
#include "clang/Basic/LangStandard.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/Basic/ObjCRuntime.h"
|
|
|
|
#include "clang/Basic/Sanitizers.h"
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
|
|
|
#include "clang/Basic/TargetOptions.h"
|
2012-12-04 09:13:33 +00:00
|
|
|
#include "clang/Basic/Version.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/Basic/Visibility.h"
|
2018-04-13 02:31:58 +00:00
|
|
|
#include "clang/Basic/XRayInstr.h"
|
2014-12-29 12:09:08 +00:00
|
|
|
#include "clang/Config/config.h"
|
2019-01-31 22:15:32 +00:00
|
|
|
#include "clang/Driver/Driver.h"
|
2009-12-01 03:16:53 +00:00
|
|
|
#include "clang/Driver/DriverDiagnostic.h"
|
2012-12-04 09:13:33 +00:00
|
|
|
#include "clang/Driver/Options.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/Frontend/CommandLineSourceLoc.h"
|
|
|
|
#include "clang/Frontend/DependencyOutputOptions.h"
|
2014-04-15 18:16:25 +00:00
|
|
|
#include "clang/Frontend/FrontendDiagnostic.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/Frontend/FrontendOptions.h"
|
2019-01-03 18:26:06 +00:00
|
|
|
#include "clang/Frontend/FrontendPluginRegistry.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/Frontend/MigratorOptions.h"
|
|
|
|
#include "clang/Frontend/PreprocessorOutputOptions.h"
|
2021-02-04 09:49:59 +01:00
|
|
|
#include "clang/Frontend/TextDiagnosticBuffer.h"
|
2013-06-14 17:17:23 +00:00
|
|
|
#include "clang/Frontend/Utils.h"
|
2012-12-04 09:13:33 +00:00
|
|
|
#include "clang/Lex/HeaderSearchOptions.h"
|
2016-07-18 19:02:11 +00:00
|
|
|
#include "clang/Lex/PreprocessorOptions.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/Sema/CodeCompleteOptions.h"
|
Make AST reading work better with LLVM_APPEND_VC_REV=NO
With LLVM_APPEND_VC_REV=NO, Modules/merge-lifetime-extended-temporary.cpp
would fail if it ran before a0f50d731639350c7a7 (which changed
the serialization format) and then after, for these reasons:
1. With LLVM_APPEND_VC_REV=NO, the module hash before and after the
change was the same.
2. Modules/merge-lifetime-extended-temporary.cpp is the only test
we have that uses -fmodule-cache-path=%t that
a) actually writes to the cache path
b) doesn't do `rm -rf %t` at the top of the test
So the old run would write a module file, and then the new run would
try to load it, but the serialized format changed.
Do several things to fix this:
1. Include clang::serialization::VERSION_MAJOR/VERSION_MINOR in
the module hash, so that when the AST format changes (...and
we remember to bump these), we use a different module cache dir.
2. Bump VERSION_MAJOR, since a0f50d731639350c7a7 changed the
on-disk format in a way that a gch file written before that change
can't be read after that change.
3. Add `rm -rf %t` to all tests that pass -fmodule-cache-path=%t.
This is unnecessary from a correctness PoV after 1 and 2,
but makes it so that we don't amass many cache dirs over time.
(Arguably, it also makes it so that the test suite doesn't catch
when we change the serialization format but don't bump
clang::serialization::VERSION_MAJOR/VERSION_MINOR; oh well.)
Differential Revision: https://reviews.llvm.org/D73202
2020-01-22 10:34:34 -05:00
|
|
|
#include "clang/Serialization/ASTBitCodes.h"
|
2015-11-03 18:33:07 +00:00
|
|
|
#include "clang/Serialization/ModuleFileExtension.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
|
|
|
|
#include "llvm/ADT/APInt.h"
|
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "llvm/ADT/CachedHashString.h"
|
2021-02-04 09:49:59 +01:00
|
|
|
#include "llvm/ADT/DenseSet.h"
|
2020-03-26 14:51:09 +07:00
|
|
|
#include "llvm/ADT/FloatingPointMode.h"
|
2012-11-05 19:45:09 +00:00
|
|
|
#include "llvm/ADT/Hashing.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/ADT/None.h"
|
|
|
|
#include "llvm/ADT/Optional.h"
|
2021-02-09 11:42:01 +01:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2015-01-14 11:29:14 +00:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2009-12-01 03:16:53 +00:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2010-08-30 09:42:39 +00:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2020-11-24 20:40:47 -08:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
2018-08-20 20:14:08 +00:00
|
|
|
#include "llvm/IR/DebugInfoMetadata.h"
|
2015-10-27 17:56:59 +00:00
|
|
|
#include "llvm/Linker/Linker.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/MC/MCTargetOptions.h"
|
2013-06-14 17:17:23 +00:00
|
|
|
#include "llvm/Option/Arg.h"
|
|
|
|
#include "llvm/Option/ArgList.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/Option/OptSpecifier.h"
|
2013-06-14 17:17:23 +00:00
|
|
|
#include "llvm/Option/OptTable.h"
|
|
|
|
#include "llvm/Option/Option.h"
|
2016-03-02 20:59:36 +00:00
|
|
|
#include "llvm/ProfileData/InstrProfReader.h"
|
2020-11-17 10:43:02 -08:00
|
|
|
#include "llvm/Remarks/HotnessThresholdParser.h"
|
2014-05-08 02:28:32 +00:00
|
|
|
#include "llvm/Support/CodeGen.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
#include "llvm/Support/Error.h"
|
2009-11-17 06:02:29 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/Support/ErrorOr.h"
|
2013-06-26 05:03:40 +00:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2021-09-03 11:12:27 -07:00
|
|
|
#include "llvm/Support/HashBuilder.h"
|
2010-11-29 18:12:39 +00:00
|
|
|
#include "llvm/Support/Host.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2010-11-29 18:12:39 +00:00
|
|
|
#include "llvm/Support/Path.h"
|
2013-09-11 00:38:02 +00:00
|
|
|
#include "llvm/Support/Process.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/Support/Regex.h"
|
2018-06-11 10:28:04 +00:00
|
|
|
#include "llvm/Support/VersionTuple.h"
|
2018-10-10 13:27:25 +00:00
|
|
|
#include "llvm/Support/VirtualFileSystem.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2015-11-09 12:40:41 +00:00
|
|
|
#include "llvm/Target/TargetOptions.h"
|
2018-03-26 21:45:04 +00:00
|
|
|
#include <algorithm>
|
2014-03-02 17:08:31 +00:00
|
|
|
#include <atomic>
|
2018-03-26 21:45:04 +00:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstring>
|
2022-04-08 23:36:51 -07:00
|
|
|
#include <fstream>
|
2014-03-09 11:36:40 +00:00
|
|
|
#include <memory>
|
2018-03-26 21:45:04 +00:00
|
|
|
#include <string>
|
|
|
|
#include <tuple>
|
2020-12-16 13:14:50 +01:00
|
|
|
#include <type_traits>
|
2018-03-26 21:45:04 +00:00
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
2009-11-17 06:02:29 +00:00
|
|
|
using namespace clang;
|
2018-03-26 21:45:04 +00:00
|
|
|
using namespace driver;
|
|
|
|
using namespace options;
|
|
|
|
using namespace llvm::opt;
|
2009-11-17 06:02:29 +00:00
|
|
|
|
2022-04-01 22:03:48 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Helpers.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
// Parse misexpect tolerance argument value.
|
|
|
|
// Valid option values are integers in the range [0, 100)
|
|
|
|
inline Expected<Optional<uint64_t>> parseToleranceOption(StringRef Arg) {
|
|
|
|
int64_t Val;
|
|
|
|
if (Arg.getAsInteger(10, Val))
|
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
"Not an integer: %s", Arg.data());
|
|
|
|
return Val;
|
|
|
|
}
|
|
|
|
|
2011-11-17 23:01:24 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Initialization.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2021-04-14 14:27:08 +02:00
|
|
|
CompilerInvocationRefBase::CompilerInvocationRefBase()
|
2018-03-26 21:45:04 +00:00
|
|
|
: LangOpts(new LangOptions()), TargetOpts(new TargetOptions()),
|
|
|
|
DiagnosticOpts(new DiagnosticOptions()),
|
|
|
|
HeaderSearchOpts(new HeaderSearchOptions()),
|
2021-03-30 10:45:04 +02:00
|
|
|
PreprocessorOpts(new PreprocessorOptions()),
|
|
|
|
AnalyzerOpts(new AnalyzerOptions()) {}
|
2011-11-17 23:01:24 +00:00
|
|
|
|
2021-04-14 14:27:08 +02:00
|
|
|
CompilerInvocationRefBase::CompilerInvocationRefBase(
|
|
|
|
const CompilerInvocationRefBase &X)
|
2017-01-06 19:49:01 +00:00
|
|
|
: LangOpts(new LangOptions(*X.getLangOpts())),
|
|
|
|
TargetOpts(new TargetOptions(X.getTargetOpts())),
|
|
|
|
DiagnosticOpts(new DiagnosticOptions(X.getDiagnosticOpts())),
|
|
|
|
HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())),
|
2021-03-30 10:45:04 +02:00
|
|
|
PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())),
|
|
|
|
AnalyzerOpts(new AnalyzerOptions(*X.getAnalyzerOpts())) {}
|
2011-11-17 23:01:24 +00:00
|
|
|
|
2021-04-14 14:35:03 +02:00
|
|
|
CompilerInvocationRefBase::CompilerInvocationRefBase(
|
|
|
|
CompilerInvocationRefBase &&X) = default;
|
|
|
|
|
|
|
|
CompilerInvocationRefBase &
|
|
|
|
CompilerInvocationRefBase::operator=(CompilerInvocationRefBase X) {
|
|
|
|
LangOpts.swap(X.LangOpts);
|
|
|
|
TargetOpts.swap(X.TargetOpts);
|
|
|
|
DiagnosticOpts.swap(X.DiagnosticOpts);
|
|
|
|
HeaderSearchOpts.swap(X.HeaderSearchOpts);
|
|
|
|
PreprocessorOpts.swap(X.PreprocessorOpts);
|
|
|
|
AnalyzerOpts.swap(X.AnalyzerOpts);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
CompilerInvocationRefBase &
|
|
|
|
CompilerInvocationRefBase::operator=(CompilerInvocationRefBase &&X) = default;
|
|
|
|
|
2021-04-14 14:27:08 +02:00
|
|
|
CompilerInvocationRefBase::~CompilerInvocationRefBase() = default;
|
2014-05-11 22:10:52 +00:00
|
|
|
|
2020-05-11 11:42:38 +01:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Normalizers
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#define SIMPLE_ENUM_VALUE_TABLE
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef SIMPLE_ENUM_VALUE_TABLE
|
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
static llvm::Optional<bool> normalizeSimpleFlag(OptSpecifier Opt,
|
|
|
|
unsigned TableIndex,
|
|
|
|
const ArgList &Args,
|
|
|
|
DiagnosticsEngine &Diags) {
|
2020-11-11 11:05:24 +01:00
|
|
|
if (Args.hasArg(Opt))
|
|
|
|
return true;
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2020-11-20 12:49:51 +01:00
|
|
|
static Optional<bool> normalizeSimpleNegativeFlag(OptSpecifier Opt, unsigned,
|
|
|
|
const ArgList &Args,
|
2021-04-16 15:30:28 +02:00
|
|
|
DiagnosticsEngine &) {
|
2020-11-20 12:49:51 +01:00
|
|
|
if (Args.hasArg(Opt))
|
|
|
|
return false;
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2020-11-20 12:49:51 +01:00
|
|
|
/// The tblgen-erated code passes in a fifth parameter of an arbitrary type, but
|
|
|
|
/// denormalizeSimpleFlags never looks at it. Avoid bloating compile-time with
|
|
|
|
/// unnecessary template instantiations and just ignore it with a variadic
|
|
|
|
/// argument.
|
|
|
|
static void denormalizeSimpleFlag(SmallVectorImpl<const char *> &Args,
|
|
|
|
const char *Spelling,
|
2021-01-05 17:00:46 +01:00
|
|
|
CompilerInvocation::StringAllocator,
|
|
|
|
Option::OptionClass, unsigned, /*T*/...) {
|
2020-11-13 14:17:54 +01:00
|
|
|
Args.push_back(Spelling);
|
|
|
|
}
|
|
|
|
|
2020-12-21 13:50:09 +01:00
|
|
|
template <typename T> static constexpr bool is_uint64_t_convertible() {
|
|
|
|
return !std::is_same<T, uint64_t>::value &&
|
|
|
|
llvm::is_integral_or_enum<T>::value;
|
|
|
|
}
|
2020-11-20 12:49:51 +01:00
|
|
|
|
2020-12-21 13:50:09 +01:00
|
|
|
template <typename T,
|
|
|
|
std::enable_if_t<!is_uint64_t_convertible<T>(), bool> = false>
|
|
|
|
static auto makeFlagToValueNormalizer(T Value) {
|
|
|
|
return [Value](OptSpecifier Opt, unsigned, const ArgList &Args,
|
2021-04-16 15:30:28 +02:00
|
|
|
DiagnosticsEngine &) -> Optional<T> {
|
2020-11-20 12:49:51 +01:00
|
|
|
if (Args.hasArg(Opt))
|
|
|
|
return Value;
|
|
|
|
return None;
|
2020-12-21 13:50:09 +01:00
|
|
|
};
|
2020-11-20 12:49:51 +01:00
|
|
|
}
|
|
|
|
|
2020-12-21 13:50:09 +01:00
|
|
|
template <typename T,
|
|
|
|
std::enable_if_t<is_uint64_t_convertible<T>(), bool> = false>
|
|
|
|
static auto makeFlagToValueNormalizer(T Value) {
|
|
|
|
return makeFlagToValueNormalizer(uint64_t(Value));
|
2020-11-11 11:05:24 +01:00
|
|
|
}
|
|
|
|
|
2020-12-08 18:15:21 +01:00
|
|
|
static auto makeBooleanOptionNormalizer(bool Value, bool OtherValue,
|
|
|
|
OptSpecifier OtherOpt) {
|
|
|
|
return [Value, OtherValue, OtherOpt](OptSpecifier Opt, unsigned,
|
2021-04-16 15:30:28 +02:00
|
|
|
const ArgList &Args,
|
|
|
|
DiagnosticsEngine &) -> Optional<bool> {
|
2020-12-08 18:15:21 +01:00
|
|
|
if (const Arg *A = Args.getLastArg(Opt, OtherOpt)) {
|
|
|
|
return A->getOption().matches(Opt) ? Value : OtherValue;
|
|
|
|
}
|
2020-12-07 14:22:23 +01:00
|
|
|
return None;
|
|
|
|
};
|
2020-11-13 14:17:54 +01:00
|
|
|
}
|
|
|
|
|
2020-12-09 13:26:39 +01:00
|
|
|
static auto makeBooleanOptionDenormalizer(bool Value) {
|
|
|
|
return [Value](SmallVectorImpl<const char *> &Args, const char *Spelling,
|
2021-01-05 17:00:46 +01:00
|
|
|
CompilerInvocation::StringAllocator, Option::OptionClass,
|
|
|
|
unsigned, bool KeyPath) {
|
2020-12-09 13:26:39 +01:00
|
|
|
if (KeyPath == Value)
|
|
|
|
Args.push_back(Spelling);
|
2020-12-07 14:22:23 +01:00
|
|
|
};
|
2020-11-13 14:17:54 +01:00
|
|
|
}
|
|
|
|
|
2021-01-05 17:00:46 +01:00
|
|
|
static void denormalizeStringImpl(SmallVectorImpl<const char *> &Args,
|
|
|
|
const char *Spelling,
|
|
|
|
CompilerInvocation::StringAllocator SA,
|
|
|
|
Option::OptionClass OptClass, unsigned,
|
2021-02-04 09:49:59 +01:00
|
|
|
const Twine &Value) {
|
2021-01-05 17:00:46 +01:00
|
|
|
switch (OptClass) {
|
|
|
|
case Option::SeparateClass:
|
|
|
|
case Option::JoinedOrSeparateClass:
|
2021-03-30 18:33:10 +01:00
|
|
|
case Option::JoinedAndSeparateClass:
|
2021-01-05 17:00:46 +01:00
|
|
|
Args.push_back(Spelling);
|
|
|
|
Args.push_back(SA(Value));
|
|
|
|
break;
|
|
|
|
case Option::JoinedClass:
|
2021-02-09 10:17:04 +01:00
|
|
|
case Option::CommaJoinedClass:
|
2021-01-05 17:00:46 +01:00
|
|
|
Args.push_back(SA(Twine(Spelling) + Value));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Cannot denormalize an option with option class "
|
|
|
|
"incompatible with string denormalization.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
static void
|
|
|
|
denormalizeString(SmallVectorImpl<const char *> &Args, const char *Spelling,
|
|
|
|
CompilerInvocation::StringAllocator SA,
|
|
|
|
Option::OptionClass OptClass, unsigned TableIndex, T Value) {
|
|
|
|
denormalizeStringImpl(Args, Spelling, SA, OptClass, TableIndex, Twine(Value));
|
|
|
|
}
|
|
|
|
|
2020-11-16 14:30:54 +01:00
|
|
|
static Optional<SimpleEnumValue>
|
|
|
|
findValueTableByName(const SimpleEnumValueTable &Table, StringRef Name) {
|
|
|
|
for (int I = 0, E = Table.Size; I != E; ++I)
|
|
|
|
if (Name == Table.Table[I].Name)
|
|
|
|
return Table.Table[I];
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Optional<SimpleEnumValue>
|
|
|
|
findValueTableByValue(const SimpleEnumValueTable &Table, unsigned Value) {
|
|
|
|
for (int I = 0, E = Table.Size; I != E; ++I)
|
|
|
|
if (Value == Table.Table[I].Value)
|
|
|
|
return Table.Table[I];
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
static llvm::Optional<unsigned> normalizeSimpleEnum(OptSpecifier Opt,
|
|
|
|
unsigned TableIndex,
|
|
|
|
const ArgList &Args,
|
|
|
|
DiagnosticsEngine &Diags) {
|
2020-05-11 11:42:38 +01:00
|
|
|
assert(TableIndex < SimpleEnumValueTablesSize);
|
|
|
|
const SimpleEnumValueTable &Table = SimpleEnumValueTables[TableIndex];
|
|
|
|
|
|
|
|
auto *Arg = Args.getLastArg(Opt);
|
|
|
|
if (!Arg)
|
|
|
|
return None;
|
|
|
|
|
|
|
|
StringRef ArgValue = Arg->getValue();
|
2020-11-16 14:30:54 +01:00
|
|
|
if (auto MaybeEnumVal = findValueTableByName(Table, ArgValue))
|
|
|
|
return MaybeEnumVal->Value;
|
2020-05-11 11:42:38 +01:00
|
|
|
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< Arg->getAsString(Args) << ArgValue;
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2020-12-16 13:17:24 +01:00
|
|
|
static void denormalizeSimpleEnumImpl(SmallVectorImpl<const char *> &Args,
|
|
|
|
const char *Spelling,
|
|
|
|
CompilerInvocation::StringAllocator SA,
|
2021-01-05 17:00:46 +01:00
|
|
|
Option::OptionClass OptClass,
|
2020-12-16 13:17:24 +01:00
|
|
|
unsigned TableIndex, unsigned Value) {
|
2020-05-11 11:42:38 +01:00
|
|
|
assert(TableIndex < SimpleEnumValueTablesSize);
|
|
|
|
const SimpleEnumValueTable &Table = SimpleEnumValueTables[TableIndex];
|
2020-11-16 14:30:54 +01:00
|
|
|
if (auto MaybeEnumVal = findValueTableByValue(Table, Value)) {
|
2021-01-05 17:00:46 +01:00
|
|
|
denormalizeString(Args, Spelling, SA, OptClass, TableIndex,
|
|
|
|
MaybeEnumVal->Name);
|
2020-11-16 14:30:54 +01:00
|
|
|
} else {
|
|
|
|
llvm_unreachable("The simple enum value was not correctly defined in "
|
|
|
|
"the tablegen option description");
|
2020-11-11 11:05:24 +01:00
|
|
|
}
|
2020-11-16 14:30:54 +01:00
|
|
|
}
|
2020-05-11 11:42:38 +01:00
|
|
|
|
2020-12-16 13:17:24 +01:00
|
|
|
template <typename T>
|
|
|
|
static void denormalizeSimpleEnum(SmallVectorImpl<const char *> &Args,
|
|
|
|
const char *Spelling,
|
|
|
|
CompilerInvocation::StringAllocator SA,
|
2021-01-05 17:00:46 +01:00
|
|
|
Option::OptionClass OptClass,
|
2020-12-16 13:17:24 +01:00
|
|
|
unsigned TableIndex, T Value) {
|
2021-01-05 17:00:46 +01:00
|
|
|
return denormalizeSimpleEnumImpl(Args, Spelling, SA, OptClass, TableIndex,
|
2020-12-16 13:17:24 +01:00
|
|
|
static_cast<unsigned>(Value));
|
|
|
|
}
|
|
|
|
|
2020-12-14 09:49:55 +01:00
|
|
|
static Optional<std::string> normalizeString(OptSpecifier Opt, int TableIndex,
|
|
|
|
const ArgList &Args,
|
2021-04-16 15:30:28 +02:00
|
|
|
DiagnosticsEngine &Diags) {
|
2020-12-14 09:49:55 +01:00
|
|
|
auto *Arg = Args.getLastArg(Opt);
|
|
|
|
if (!Arg)
|
|
|
|
return None;
|
|
|
|
return std::string(Arg->getValue());
|
|
|
|
}
|
|
|
|
|
2020-12-16 13:14:50 +01:00
|
|
|
template <typename IntTy>
|
2021-04-16 15:30:28 +02:00
|
|
|
static Optional<IntTy> normalizeStringIntegral(OptSpecifier Opt, int,
|
|
|
|
const ArgList &Args,
|
|
|
|
DiagnosticsEngine &Diags) {
|
2020-12-16 13:14:50 +01:00
|
|
|
auto *Arg = Args.getLastArg(Opt);
|
|
|
|
if (!Arg)
|
|
|
|
return None;
|
|
|
|
IntTy Res;
|
|
|
|
if (StringRef(Arg->getValue()).getAsInteger(0, Res)) {
|
|
|
|
Diags.Report(diag::err_drv_invalid_int_value)
|
|
|
|
<< Arg->getAsString(Args) << Arg->getValue();
|
2021-01-08 11:05:16 +01:00
|
|
|
return None;
|
2020-12-16 13:14:50 +01:00
|
|
|
}
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2021-01-05 17:00:46 +01:00
|
|
|
static Optional<std::vector<std::string>>
|
|
|
|
normalizeStringVector(OptSpecifier Opt, int, const ArgList &Args,
|
2021-04-16 15:30:28 +02:00
|
|
|
DiagnosticsEngine &) {
|
2021-01-05 17:00:46 +01:00
|
|
|
return Args.getAllArgValues(Opt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void denormalizeStringVector(SmallVectorImpl<const char *> &Args,
|
|
|
|
const char *Spelling,
|
|
|
|
CompilerInvocation::StringAllocator SA,
|
|
|
|
Option::OptionClass OptClass,
|
|
|
|
unsigned TableIndex,
|
|
|
|
const std::vector<std::string> &Values) {
|
2020-12-22 10:01:51 +01:00
|
|
|
switch (OptClass) {
|
|
|
|
case Option::CommaJoinedClass: {
|
2020-12-21 16:35:32 +01:00
|
|
|
std::string CommaJoinedValue;
|
|
|
|
if (!Values.empty()) {
|
|
|
|
CommaJoinedValue.append(Values.front());
|
|
|
|
for (const std::string &Value : llvm::drop_begin(Values, 1)) {
|
|
|
|
CommaJoinedValue.append(",");
|
|
|
|
CommaJoinedValue.append(Value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
denormalizeString(Args, Spelling, SA, Option::OptionClass::JoinedClass,
|
|
|
|
TableIndex, CommaJoinedValue);
|
2020-12-22 10:01:51 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Option::JoinedClass:
|
|
|
|
case Option::SeparateClass:
|
|
|
|
case Option::JoinedOrSeparateClass:
|
2020-12-21 16:35:32 +01:00
|
|
|
for (const std::string &Value : Values)
|
|
|
|
denormalizeString(Args, Spelling, SA, OptClass, TableIndex, Value);
|
2020-12-22 10:01:51 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Cannot denormalize an option with option class "
|
|
|
|
"incompatible with string vector denormalization.");
|
2021-01-05 17:00:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-11 11:42:38 +01:00
|
|
|
static Optional<std::string> normalizeTriple(OptSpecifier Opt, int TableIndex,
|
|
|
|
const ArgList &Args,
|
2021-04-16 15:30:28 +02:00
|
|
|
DiagnosticsEngine &Diags) {
|
2020-05-11 11:42:38 +01:00
|
|
|
auto *Arg = Args.getLastArg(Opt);
|
|
|
|
if (!Arg)
|
|
|
|
return None;
|
|
|
|
return llvm::Triple::normalize(Arg->getValue());
|
|
|
|
}
|
|
|
|
|
2020-11-11 11:05:24 +01:00
|
|
|
template <typename T, typename U>
|
|
|
|
static T mergeForwardValue(T KeyPath, U Value) {
|
2020-12-15 09:59:19 +01:00
|
|
|
return static_cast<T>(Value);
|
2020-11-11 11:05:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename U> static T mergeMaskValue(T KeyPath, U Value) {
|
|
|
|
return KeyPath | Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T> static T extractForwardValue(T KeyPath) {
|
|
|
|
return KeyPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename U, U Value>
|
|
|
|
static T extractMaskValue(T KeyPath) {
|
2021-02-10 11:15:39 +08:00
|
|
|
return ((KeyPath & Value) == Value) ? static_cast<T>(Value) : T();
|
2020-11-11 11:05:24 +01:00
|
|
|
}
|
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
#define PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
ARGS, DIAGS, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX) \
|
2021-01-15 17:55:03 +01:00
|
|
|
if ((FLAGS)&options::CC1Option) { \
|
2021-01-28 10:48:26 +01:00
|
|
|
KEYPATH = MERGER(KEYPATH, DEFAULT_VALUE); \
|
2021-01-15 17:55:03 +01:00
|
|
|
if (IMPLIED_CHECK) \
|
2021-01-28 10:48:26 +01:00
|
|
|
KEYPATH = MERGER(KEYPATH, IMPLIED_VALUE); \
|
2021-01-15 17:55:03 +01:00
|
|
|
if (SHOULD_PARSE) \
|
2021-04-16 15:30:28 +02:00
|
|
|
if (auto MaybeValue = NORMALIZER(OPT_##ID, TABLE_INDEX, ARGS, DIAGS)) \
|
2021-01-28 10:48:26 +01:00
|
|
|
KEYPATH = \
|
|
|
|
MERGER(KEYPATH, static_cast<decltype(KEYPATH)>(*MaybeValue)); \
|
2021-01-15 17:55:03 +01:00
|
|
|
}
|
|
|
|
|
2021-01-27 14:50:09 +01:00
|
|
|
// Capture the extracted value as a lambda argument to avoid potential issues
|
|
|
|
// with lifetime extension of the reference.
|
|
|
|
#define GENERATE_OPTION_WITH_MARSHALLING( \
|
2021-01-28 10:48:26 +01:00
|
|
|
ARGS, STRING_ALLOCATOR, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, \
|
2021-01-27 14:50:09 +01:00
|
|
|
TABLE_INDEX) \
|
|
|
|
if ((FLAGS)&options::CC1Option) { \
|
|
|
|
[&](const auto &Extracted) { \
|
|
|
|
if (ALWAYS_EMIT || \
|
|
|
|
(Extracted != \
|
2021-01-28 10:48:26 +01:00
|
|
|
static_cast<decltype(KEYPATH)>((IMPLIED_CHECK) ? (IMPLIED_VALUE) \
|
|
|
|
: (DEFAULT_VALUE)))) \
|
2021-01-27 14:50:09 +01:00
|
|
|
DENORMALIZER(ARGS, SPELLING, STRING_ALLOCATOR, Option::KIND##Class, \
|
|
|
|
TABLE_INDEX, Extracted); \
|
2021-01-28 10:48:26 +01:00
|
|
|
}(EXTRACTOR(KEYPATH)); \
|
2021-01-27 14:50:09 +01:00
|
|
|
}
|
|
|
|
|
2021-12-28 10:01:39 -08:00
|
|
|
static StringRef GetInputKindName(InputKind IK);
|
2021-01-26 09:08:08 +01:00
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
static bool FixupInvocation(CompilerInvocation &Invocation,
|
|
|
|
DiagnosticsEngine &Diags, const ArgList &Args,
|
2021-01-26 09:08:08 +01:00
|
|
|
InputKind IK) {
|
2021-02-25 10:10:40 +01:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
|
|
|
|
2020-11-16 12:17:29 +01:00
|
|
|
LangOptions &LangOpts = *Invocation.getLangOpts();
|
|
|
|
CodeGenOptions &CodeGenOpts = Invocation.getCodeGenOpts();
|
2020-12-15 09:59:19 +01:00
|
|
|
TargetOptions &TargetOpts = Invocation.getTargetOpts();
|
2020-11-20 12:49:51 +01:00
|
|
|
FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
|
2020-11-16 12:17:29 +01:00
|
|
|
CodeGenOpts.XRayInstrumentFunctions = LangOpts.XRayInstrument;
|
|
|
|
CodeGenOpts.XRayAlwaysEmitCustomEvents = LangOpts.XRayAlwaysEmitCustomEvents;
|
|
|
|
CodeGenOpts.XRayAlwaysEmitTypedEvents = LangOpts.XRayAlwaysEmitTypedEvents;
|
2021-01-05 17:00:46 +01:00
|
|
|
CodeGenOpts.DisableFree = FrontendOpts.DisableFree;
|
2020-11-20 12:49:51 +01:00
|
|
|
FrontendOpts.GenerateGlobalModuleIndex = FrontendOpts.UseGlobalModuleIndex;
|
2021-10-17 22:48:35 -07:00
|
|
|
if (FrontendOpts.ShowStats)
|
|
|
|
CodeGenOpts.ClearASTBeforeBackend = false;
|
2021-05-27 18:24:21 +02:00
|
|
|
LangOpts.SanitizeCoverage = CodeGenOpts.hasSanitizeCoverage();
|
2021-01-05 17:00:46 +01:00
|
|
|
LangOpts.ForceEmitVTables = CodeGenOpts.ForceEmitVTables;
|
|
|
|
LangOpts.SpeculativeLoadHardening = CodeGenOpts.SpeculativeLoadHardening;
|
|
|
|
LangOpts.CurrentModule = LangOpts.ModuleName;
|
|
|
|
|
2020-12-15 09:59:19 +01:00
|
|
|
llvm::Triple T(TargetOpts.Triple);
|
2021-01-05 17:00:46 +01:00
|
|
|
llvm::Triple::ArchType Arch = T.getArch();
|
2020-12-15 09:59:19 +01:00
|
|
|
|
2021-01-14 08:34:17 +01:00
|
|
|
CodeGenOpts.CodeModel = TargetOpts.CodeModel;
|
|
|
|
|
2021-04-20 10:58:19 -04:00
|
|
|
if (LangOpts.getExceptionHandling() !=
|
|
|
|
LangOptions::ExceptionHandlingKind::None &&
|
2020-12-15 09:59:19 +01:00
|
|
|
T.isWindowsMSVCEnvironment())
|
|
|
|
Diags.Report(diag::err_fe_invalid_exception_model)
|
|
|
|
<< static_cast<unsigned>(LangOpts.getExceptionHandling()) << T.str();
|
2021-01-05 17:00:46 +01:00
|
|
|
|
|
|
|
if (LangOpts.AppleKext && !LangOpts.CPlusPlus)
|
|
|
|
Diags.Report(diag::warn_c_kext);
|
|
|
|
|
2021-01-27 09:00:16 +01:00
|
|
|
if (Args.hasArg(OPT_fconcepts_ts))
|
|
|
|
Diags.Report(diag::warn_fe_concepts_ts_flag);
|
|
|
|
|
2021-01-05 17:00:46 +01:00
|
|
|
if (LangOpts.NewAlignOverride &&
|
|
|
|
!llvm::isPowerOf2_32(LangOpts.NewAlignOverride)) {
|
|
|
|
Arg *A = Args.getLastArg(OPT_fnew_alignment_EQ);
|
|
|
|
Diags.Report(diag::err_fe_invalid_alignment)
|
|
|
|
<< A->getAsString(Args) << A->getValue();
|
|
|
|
LangOpts.NewAlignOverride = 0;
|
|
|
|
}
|
|
|
|
|
2021-03-17 08:26:07 -04:00
|
|
|
// Prevent the user from specifying both -fsycl-is-device and -fsycl-is-host.
|
|
|
|
if (LangOpts.SYCLIsDevice && LangOpts.SYCLIsHost)
|
|
|
|
Diags.Report(diag::err_drv_argument_not_allowed_with) << "-fsycl-is-device"
|
|
|
|
<< "-fsycl-is-host";
|
|
|
|
|
2021-01-26 09:08:08 +01:00
|
|
|
if (Args.hasArg(OPT_fgnu89_inline) && LangOpts.CPlusPlus)
|
|
|
|
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "-fgnu89-inline" << GetInputKindName(IK);
|
|
|
|
|
2021-01-26 09:35:32 +01:00
|
|
|
if (Args.hasArg(OPT_fgpu_allow_device_init) && !LangOpts.HIP)
|
|
|
|
Diags.Report(diag::warn_ignored_hip_only_option)
|
|
|
|
<< Args.getLastArg(OPT_fgpu_allow_device_init)->getAsString(Args);
|
|
|
|
|
|
|
|
if (Args.hasArg(OPT_gpu_max_threads_per_block_EQ) && !LangOpts.HIP)
|
|
|
|
Diags.Report(diag::warn_ignored_hip_only_option)
|
|
|
|
<< Args.getLastArg(OPT_gpu_max_threads_per_block_EQ)->getAsString(Args);
|
|
|
|
|
2022-04-03 04:28:15 -07:00
|
|
|
// When these options are used, the compiler is allowed to apply
|
|
|
|
// optimizations that may affect the final result. For example
|
|
|
|
// (x+y)+z is transformed to x+(y+z) but may not give the same
|
|
|
|
// final result; it's not value safe.
|
|
|
|
// Another example can be to simplify x/x to 1.0 but x could be 0.0, INF
|
|
|
|
// or NaN. Final result may then differ. An error is issued when the eval
|
|
|
|
// method is set with one of these options.
|
|
|
|
if (Args.hasArg(OPT_ffp_eval_method_EQ)) {
|
|
|
|
if (LangOpts.ApproxFunc)
|
|
|
|
Diags.Report(diag::err_incompatible_fp_eval_method_options) << 0;
|
|
|
|
if (LangOpts.AllowFPReassoc)
|
|
|
|
Diags.Report(diag::err_incompatible_fp_eval_method_options) << 1;
|
|
|
|
if (LangOpts.AllowRecip)
|
|
|
|
Diags.Report(diag::err_incompatible_fp_eval_method_options) << 2;
|
|
|
|
}
|
|
|
|
|
2021-01-26 09:35:32 +01:00
|
|
|
// -cl-strict-aliasing needs to emit diagnostic in the case where CL > 1.0.
|
|
|
|
// This option should be deprecated for CL > 1.0 because
|
|
|
|
// this option was added for compatibility with OpenCL 1.0.
|
2021-08-06 13:50:13 +01:00
|
|
|
if (Args.getLastArg(OPT_cl_strict_aliasing) &&
|
2021-08-24 11:59:42 +01:00
|
|
|
(LangOpts.getOpenCLCompatibleVersion() > 100))
|
2021-01-26 09:35:32 +01:00
|
|
|
Diags.Report(diag::warn_option_invalid_ocl_version)
|
2021-08-06 13:50:13 +01:00
|
|
|
<< LangOpts.getOpenCLVersionString()
|
2021-01-26 09:35:32 +01:00
|
|
|
<< Args.getLastArg(OPT_cl_strict_aliasing)->getAsString(Args);
|
|
|
|
|
2021-01-05 17:00:46 +01:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_fdefault_calling_conv_EQ)) {
|
|
|
|
auto DefaultCC = LangOpts.getDefaultCallingConv();
|
|
|
|
|
|
|
|
bool emitError = (DefaultCC == LangOptions::DCC_FastCall ||
|
|
|
|
DefaultCC == LangOptions::DCC_StdCall) &&
|
|
|
|
Arch != llvm::Triple::x86;
|
|
|
|
emitError |= (DefaultCC == LangOptions::DCC_VectorCall ||
|
|
|
|
DefaultCC == LangOptions::DCC_RegCall) &&
|
|
|
|
!T.isX86();
|
|
|
|
if (emitError)
|
|
|
|
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< A->getSpelling() << T.getTriple();
|
|
|
|
}
|
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2020-11-16 12:17:29 +01:00
|
|
|
}
|
|
|
|
|
2011-11-17 23:01:24 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2012-11-01 03:48:49 +00:00
|
|
|
// Deserialization (from args)
|
2009-12-01 03:16:53 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-12-04 01:50:36 +00:00
|
|
|
static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
|
2011-09-25 23:23:43 +00:00
|
|
|
DiagnosticsEngine &Diags) {
|
2018-11-26 17:26:49 +00:00
|
|
|
unsigned DefaultOpt = llvm::CodeGenOpt::None;
|
2021-03-03 19:00:55 +00:00
|
|
|
if ((IK.getLanguage() == Language::OpenCL ||
|
|
|
|
IK.getLanguage() == Language::OpenCLCXX) &&
|
|
|
|
!Args.hasArg(OPT_cl_opt_disable))
|
2018-11-26 17:26:49 +00:00
|
|
|
DefaultOpt = llvm::CodeGenOpt::Default;
|
2012-05-01 14:57:16 +00:00
|
|
|
|
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
|
|
|
|
if (A->getOption().matches(options::OPT_O0))
|
2018-11-26 17:26:49 +00:00
|
|
|
return llvm::CodeGenOpt::None;
|
2012-05-01 14:57:16 +00:00
|
|
|
|
2013-04-10 21:26:02 +00:00
|
|
|
if (A->getOption().matches(options::OPT_Ofast))
|
2018-11-26 17:26:49 +00:00
|
|
|
return llvm::CodeGenOpt::Aggressive;
|
2013-04-10 21:26:02 +00:00
|
|
|
|
2018-03-26 21:45:04 +00:00
|
|
|
assert(A->getOption().matches(options::OPT_O));
|
2012-05-01 14:57:16 +00:00
|
|
|
|
2013-01-12 19:30:44 +00:00
|
|
|
StringRef S(A->getValue());
|
2020-05-13 17:25:04 -07:00
|
|
|
if (S == "s" || S == "z")
|
2018-11-26 17:26:49 +00:00
|
|
|
return llvm::CodeGenOpt::Default;
|
2012-05-01 14:57:16 +00:00
|
|
|
|
Add a new optimization option -Og
Summary:
Just like gcc, we should have the -Og option as more and more software are using it:
https://llvm.org/bugs/show_bug.cgi?id=20765
Reviewers: echristo, dberlin, dblaikie, keith.walker.arm, rengolin
Subscribers: aprantl, friss, mehdi_amini, RKSimon, probinson, majnemer, cfe-commits
Differential Revision: https://reviews.llvm.org/D24998
llvm-svn: 286602
2016-11-11 17:29:56 +00:00
|
|
|
if (S == "g")
|
2018-11-26 17:26:49 +00:00
|
|
|
return llvm::CodeGenOpt::Less;
|
Add a new optimization option -Og
Summary:
Just like gcc, we should have the -Og option as more and more software are using it:
https://llvm.org/bugs/show_bug.cgi?id=20765
Reviewers: echristo, dberlin, dblaikie, keith.walker.arm, rengolin
Subscribers: aprantl, friss, mehdi_amini, RKSimon, probinson, majnemer, cfe-commits
Differential Revision: https://reviews.llvm.org/D24998
llvm-svn: 286602
2016-11-11 17:29:56 +00:00
|
|
|
|
2013-06-14 17:17:23 +00:00
|
|
|
return getLastArgIntValue(Args, OPT_O, DefaultOpt, Diags);
|
2012-05-01 14:57:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return DefaultOpt;
|
|
|
|
}
|
|
|
|
|
2013-04-10 21:30:03 +00:00
|
|
|
static unsigned getOptimizationLevelSize(ArgList &Args) {
|
2012-05-01 14:57:16 +00:00
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
|
|
|
|
if (A->getOption().matches(options::OPT_O)) {
|
2012-11-01 04:30:05 +00:00
|
|
|
switch (A->getValue()[0]) {
|
2012-05-01 14:57:16 +00:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
case 's':
|
|
|
|
return 1;
|
|
|
|
case 'z':
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-02-04 09:49:59 +01:00
|
|
|
static void GenerateArg(SmallVectorImpl<const char *> &Args,
|
|
|
|
llvm::opt::OptSpecifier OptSpecifier,
|
|
|
|
CompilerInvocation::StringAllocator SA) {
|
|
|
|
Option Opt = getDriverOptTable().getOption(OptSpecifier);
|
|
|
|
denormalizeSimpleFlag(Args, SA(Opt.getPrefix() + Opt.getName()), SA,
|
|
|
|
Option::OptionClass::FlagClass, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void GenerateArg(SmallVectorImpl<const char *> &Args,
|
|
|
|
llvm::opt::OptSpecifier OptSpecifier,
|
|
|
|
const Twine &Value,
|
|
|
|
CompilerInvocation::StringAllocator SA) {
|
|
|
|
Option Opt = getDriverOptTable().getOption(OptSpecifier);
|
|
|
|
denormalizeString(Args, SA(Opt.getPrefix() + Opt.getName()), SA,
|
|
|
|
Opt.getKind(), 0, Value);
|
|
|
|
}
|
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
// Parse command line arguments into CompilerInvocation.
|
|
|
|
using ParseFn =
|
|
|
|
llvm::function_ref<bool(CompilerInvocation &, ArrayRef<const char *>,
|
|
|
|
DiagnosticsEngine &, const char *)>;
|
2021-02-04 09:49:59 +01:00
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
// Generate command line arguments from CompilerInvocation.
|
2021-02-04 09:49:59 +01:00
|
|
|
using GenerateFn = llvm::function_ref<void(
|
|
|
|
CompilerInvocation &, SmallVectorImpl<const char *> &,
|
|
|
|
CompilerInvocation::StringAllocator)>;
|
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
// May perform round-trip of command line arguments. By default, the round-trip
|
2021-11-17 16:32:33 -05:00
|
|
|
// is enabled in assert builds. This can be overwritten at run-time via the
|
|
|
|
// "-round-trip-args" and "-no-round-trip-args" command line flags.
|
2021-02-25 10:10:40 +01:00
|
|
|
// During round-trip, the command line arguments are parsed into a dummy
|
|
|
|
// instance of CompilerInvocation which is used to generate the command line
|
|
|
|
// arguments again. The real CompilerInvocation instance is then created by
|
|
|
|
// parsing the generated arguments, not the original ones.
|
|
|
|
static bool RoundTrip(ParseFn Parse, GenerateFn Generate,
|
|
|
|
CompilerInvocation &RealInvocation,
|
|
|
|
CompilerInvocation &DummyInvocation,
|
|
|
|
ArrayRef<const char *> CommandLineArgs,
|
|
|
|
DiagnosticsEngine &Diags, const char *Argv0) {
|
2021-11-17 16:32:33 -05:00
|
|
|
#ifndef NDEBUG
|
2021-02-04 09:49:59 +01:00
|
|
|
bool DoRoundTripDefault = true;
|
|
|
|
#else
|
|
|
|
bool DoRoundTripDefault = false;
|
|
|
|
#endif
|
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
bool DoRoundTrip = DoRoundTripDefault;
|
|
|
|
for (const auto *Arg : CommandLineArgs) {
|
|
|
|
if (Arg == StringRef("-round-trip-args"))
|
|
|
|
DoRoundTrip = true;
|
|
|
|
if (Arg == StringRef("-no-round-trip-args"))
|
|
|
|
DoRoundTrip = false;
|
|
|
|
}
|
2021-02-04 09:49:59 +01:00
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
// If round-trip was not requested, simply run the parser with the real
|
|
|
|
// invocation diagnostics.
|
2021-02-04 09:49:59 +01:00
|
|
|
if (!DoRoundTrip)
|
2021-02-25 10:10:40 +01:00
|
|
|
return Parse(RealInvocation, CommandLineArgs, Diags, Argv0);
|
2021-02-04 09:49:59 +01:00
|
|
|
|
|
|
|
// Serializes quoted (and potentially escaped) arguments.
|
2021-02-25 10:10:40 +01:00
|
|
|
auto SerializeArgs = [](ArrayRef<const char *> Args) {
|
2021-02-04 09:49:59 +01:00
|
|
|
std::string Buffer;
|
|
|
|
llvm::raw_string_ostream OS(Buffer);
|
|
|
|
for (const char *Arg : Args) {
|
|
|
|
llvm::sys::printArg(OS, Arg, /*Quote=*/true);
|
|
|
|
OS << ' ';
|
|
|
|
}
|
|
|
|
OS.flush();
|
|
|
|
return Buffer;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Setup a dummy DiagnosticsEngine.
|
|
|
|
DiagnosticsEngine DummyDiags(new DiagnosticIDs(), new DiagnosticOptions());
|
|
|
|
DummyDiags.setClient(new TextDiagnosticBuffer());
|
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
// Run the first parse on the original arguments with the dummy invocation and
|
2021-02-04 09:49:59 +01:00
|
|
|
// diagnostics.
|
2021-02-25 10:10:40 +01:00
|
|
|
if (!Parse(DummyInvocation, CommandLineArgs, DummyDiags, Argv0) ||
|
2021-02-09 11:42:01 +01:00
|
|
|
DummyDiags.getNumWarnings() != 0) {
|
2021-02-04 09:49:59 +01:00
|
|
|
// If the first parse did not succeed, it must be user mistake (invalid
|
|
|
|
// command line arguments). We won't be able to generate arguments that
|
2021-02-25 10:10:40 +01:00
|
|
|
// would reproduce the same result. Let's fail again with the real
|
|
|
|
// invocation and diagnostics, so all side-effects of parsing are visible.
|
2021-02-09 11:42:01 +01:00
|
|
|
unsigned NumWarningsBefore = Diags.getNumWarnings();
|
2021-02-25 10:10:40 +01:00
|
|
|
auto Success = Parse(RealInvocation, CommandLineArgs, Diags, Argv0);
|
2021-02-09 11:42:01 +01:00
|
|
|
if (!Success || Diags.getNumWarnings() != NumWarningsBefore)
|
|
|
|
return Success;
|
2021-02-04 09:49:59 +01:00
|
|
|
|
|
|
|
// Parse with original options and diagnostics succeeded even though it
|
|
|
|
// shouldn't have. Something is off.
|
2021-02-25 10:10:40 +01:00
|
|
|
Diags.Report(diag::err_cc1_round_trip_fail_then_ok);
|
2021-02-04 09:49:59 +01:00
|
|
|
Diags.Report(diag::note_cc1_round_trip_original)
|
2021-02-25 10:10:40 +01:00
|
|
|
<< SerializeArgs(CommandLineArgs);
|
2021-02-04 09:49:59 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup string allocator.
|
|
|
|
llvm::BumpPtrAllocator Alloc;
|
|
|
|
llvm::StringSaver StringPool(Alloc);
|
|
|
|
auto SA = [&StringPool](const Twine &Arg) {
|
|
|
|
return StringPool.save(Arg).data();
|
|
|
|
};
|
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
// Generate arguments from the dummy invocation. If Generate is the
|
|
|
|
// inverse of Parse, the newly generated arguments must have the same
|
|
|
|
// semantics as the original.
|
2021-03-12 15:19:43 -06:00
|
|
|
SmallVector<const char *> GeneratedArgs1;
|
2021-02-25 10:10:40 +01:00
|
|
|
Generate(DummyInvocation, GeneratedArgs1, SA);
|
|
|
|
|
|
|
|
// Run the second parse, now on the generated arguments, and with the real
|
|
|
|
// invocation and diagnostics. The result is what we will end up using for the
|
2021-02-04 09:49:59 +01:00
|
|
|
// rest of compilation, so if Generate is not inverse of Parse, something down
|
|
|
|
// the line will break.
|
2021-02-25 10:10:40 +01:00
|
|
|
bool Success2 = Parse(RealInvocation, GeneratedArgs1, Diags, Argv0);
|
2021-02-04 09:49:59 +01:00
|
|
|
|
|
|
|
// The first parse on original arguments succeeded, but second parse of
|
|
|
|
// generated arguments failed. Something must be wrong with the generator.
|
|
|
|
if (!Success2) {
|
2021-02-25 10:10:40 +01:00
|
|
|
Diags.Report(diag::err_cc1_round_trip_ok_then_fail);
|
2021-02-04 09:49:59 +01:00
|
|
|
Diags.Report(diag::note_cc1_round_trip_generated)
|
2021-02-25 10:10:40 +01:00
|
|
|
<< 1 << SerializeArgs(GeneratedArgs1);
|
2021-02-04 09:49:59 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate arguments again, this time from the options we will end up using
|
|
|
|
// for the rest of the compilation.
|
2021-03-12 15:19:43 -06:00
|
|
|
SmallVector<const char *> GeneratedArgs2;
|
2021-02-25 10:10:40 +01:00
|
|
|
Generate(RealInvocation, GeneratedArgs2, SA);
|
2021-02-04 09:49:59 +01:00
|
|
|
|
|
|
|
// Compares two lists of generated arguments.
|
2021-02-25 10:10:40 +01:00
|
|
|
auto Equal = [](const ArrayRef<const char *> A,
|
|
|
|
const ArrayRef<const char *> B) {
|
2021-02-04 09:49:59 +01:00
|
|
|
return std::equal(A.begin(), A.end(), B.begin(), B.end(),
|
|
|
|
[](const char *AElem, const char *BElem) {
|
|
|
|
return StringRef(AElem) == StringRef(BElem);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// If we generated different arguments from what we assume are two
|
|
|
|
// semantically equivalent CompilerInvocations, the Generate function may
|
|
|
|
// be non-deterministic.
|
2021-02-25 10:10:40 +01:00
|
|
|
if (!Equal(GeneratedArgs1, GeneratedArgs2)) {
|
|
|
|
Diags.Report(diag::err_cc1_round_trip_mismatch);
|
2021-02-04 09:49:59 +01:00
|
|
|
Diags.Report(diag::note_cc1_round_trip_generated)
|
2021-02-25 10:10:40 +01:00
|
|
|
<< 1 << SerializeArgs(GeneratedArgs1);
|
2021-02-04 09:49:59 +01:00
|
|
|
Diags.Report(diag::note_cc1_round_trip_generated)
|
2021-02-25 10:10:40 +01:00
|
|
|
<< 2 << SerializeArgs(GeneratedArgs2);
|
2021-02-04 09:49:59 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Diags.Report(diag::remark_cc1_round_trip_generated)
|
2021-02-25 10:10:40 +01:00
|
|
|
<< 1 << SerializeArgs(GeneratedArgs1);
|
2021-02-04 09:49:59 +01:00
|
|
|
Diags.Report(diag::remark_cc1_round_trip_generated)
|
2021-02-25 10:10:40 +01:00
|
|
|
<< 2 << SerializeArgs(GeneratedArgs2);
|
2021-02-04 09:49:59 +01:00
|
|
|
|
|
|
|
return Success2;
|
2021-01-15 14:47:55 +01:00
|
|
|
}
|
|
|
|
|
Use -Rblah, not -Wblah, to control remark diagnostics. This was always the
intent when we added remark support, but was never implemented in the general
case, because the first -R flags didn't need it. (-Rpass= had special handling
to accomodate its argument.)
-Rno-foo, -Reverything, and -Rno-everything can be used to turn off a remark,
or to turn on or off all remarks. Per discussion on cfe-commits, -Weverything
does not affect remarks, and -Reverything does not affect warnings or errors.
The only "real" -R flag we have right now is -Rmodule-build; that flag is
effectively renamed from -Wmodule-build to -Rmodule-build by this change.
-Wpass and -Wno-pass (and their friends) are also renamed to -Rpass and
-Rno-pass by this change; it's not completely clear whether we intended to have
a -Rpass (with no =pattern), but that is unchanged by this commit, other than
the flag name. The default pattern is effectively one which matches no passes.
In future, we may want to make the default pattern be .*, so that -Reverything
works for -Rpass properly.
llvm-svn: 215046
2014-08-07 00:24:21 +00:00
|
|
|
static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group,
|
|
|
|
OptSpecifier GroupWithValue,
|
|
|
|
std::vector<std::string> &Diagnostics) {
|
2018-03-26 21:45:04 +00:00
|
|
|
for (auto *A : Args.filtered(Group)) {
|
2012-05-01 14:57:16 +00:00
|
|
|
if (A->getOption().getKind() == Option::FlagClass) {
|
Use -Rblah, not -Wblah, to control remark diagnostics. This was always the
intent when we added remark support, but was never implemented in the general
case, because the first -R flags didn't need it. (-Rpass= had special handling
to accomodate its argument.)
-Rno-foo, -Reverything, and -Rno-everything can be used to turn off a remark,
or to turn on or off all remarks. Per discussion on cfe-commits, -Weverything
does not affect remarks, and -Reverything does not affect warnings or errors.
The only "real" -R flag we have right now is -Rmodule-build; that flag is
effectively renamed from -Wmodule-build to -Rmodule-build by this change.
-Wpass and -Wno-pass (and their friends) are also renamed to -Rpass and
-Rno-pass by this change; it's not completely clear whether we intended to have
a -Rpass (with no =pattern), but that is unchanged by this commit, other than
the flag name. The default pattern is effectively one which matches no passes.
In future, we may want to make the default pattern be .*, so that -Reverything
works for -Rpass properly.
llvm-svn: 215046
2014-08-07 00:24:21 +00:00
|
|
|
// The argument is a pure flag (such as OPT_Wall or OPT_Wdeprecated). Add
|
2021-02-10 12:24:19 +01:00
|
|
|
// its name (minus the "W" or "R" at the beginning) to the diagnostics.
|
2020-01-28 20:23:46 +01:00
|
|
|
Diagnostics.push_back(
|
|
|
|
std::string(A->getOption().getName().drop_front(1)));
|
Use -Rblah, not -Wblah, to control remark diagnostics. This was always the
intent when we added remark support, but was never implemented in the general
case, because the first -R flags didn't need it. (-Rpass= had special handling
to accomodate its argument.)
-Rno-foo, -Reverything, and -Rno-everything can be used to turn off a remark,
or to turn on or off all remarks. Per discussion on cfe-commits, -Weverything
does not affect remarks, and -Reverything does not affect warnings or errors.
The only "real" -R flag we have right now is -Rmodule-build; that flag is
effectively renamed from -Wmodule-build to -Rmodule-build by this change.
-Wpass and -Wno-pass (and their friends) are also renamed to -Rpass and
-Rno-pass by this change; it's not completely clear whether we intended to have
a -Rpass (with no =pattern), but that is unchanged by this commit, other than
the flag name. The default pattern is effectively one which matches no passes.
In future, we may want to make the default pattern be .*, so that -Reverything
works for -Rpass properly.
llvm-svn: 215046
2014-08-07 00:24:21 +00:00
|
|
|
} else if (A->getOption().matches(GroupWithValue)) {
|
2021-02-10 12:24:19 +01:00
|
|
|
// This is -Wfoo= or -Rfoo=, where foo is the name of the diagnostic
|
|
|
|
// group. Add only the group name to the diagnostics.
|
2020-01-28 20:23:46 +01:00
|
|
|
Diagnostics.push_back(
|
|
|
|
std::string(A->getOption().getName().drop_front(1).rtrim("=-")));
|
2012-05-01 14:57:16 +00:00
|
|
|
} else {
|
Use -Rblah, not -Wblah, to control remark diagnostics. This was always the
intent when we added remark support, but was never implemented in the general
case, because the first -R flags didn't need it. (-Rpass= had special handling
to accomodate its argument.)
-Rno-foo, -Reverything, and -Rno-everything can be used to turn off a remark,
or to turn on or off all remarks. Per discussion on cfe-commits, -Weverything
does not affect remarks, and -Reverything does not affect warnings or errors.
The only "real" -R flag we have right now is -Rmodule-build; that flag is
effectively renamed from -Wmodule-build to -Rmodule-build by this change.
-Wpass and -Wno-pass (and their friends) are also renamed to -Rpass and
-Rno-pass by this change; it's not completely clear whether we intended to have
a -Rpass (with no =pattern), but that is unchanged by this commit, other than
the flag name. The default pattern is effectively one which matches no passes.
In future, we may want to make the default pattern be .*, so that -Reverything
works for -Rpass properly.
llvm-svn: 215046
2014-08-07 00:24:21 +00:00
|
|
|
// Otherwise, add its value (for OPT_W_Joined and similar).
|
2021-02-10 12:24:19 +01:00
|
|
|
Diagnostics.push_back(A->getValue());
|
2012-05-01 14:57:16 +00:00
|
|
|
}
|
|
|
|
}
|
2010-12-04 01:50:36 +00:00
|
|
|
}
|
|
|
|
|
2018-11-30 21:24:31 +00:00
|
|
|
// Parse the Static Analyzer configuration. If \p Diags is set to nullptr,
|
|
|
|
// it won't verify the input.
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts,
|
2018-11-30 21:24:31 +00:00
|
|
|
DiagnosticsEngine *Diags);
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
|
2016-01-06 14:35:46 +00:00
|
|
|
static void getAllNoBuiltinFuncValues(ArgList &Args,
|
|
|
|
std::vector<std::string> &Funcs) {
|
2021-02-09 11:42:01 +01:00
|
|
|
std::vector<std::string> Values = Args.getAllArgValues(OPT_fno_builtin_);
|
2021-12-17 20:55:10 -08:00
|
|
|
auto BuiltinEnd = llvm::partition(Values, Builtin::Context::isBuiltinFunc);
|
2021-02-09 11:42:01 +01:00
|
|
|
Funcs.insert(Funcs.end(), Values.begin(), BuiltinEnd);
|
2016-01-06 14:35:46 +00:00
|
|
|
}
|
|
|
|
|
2021-02-08 09:04:21 +01:00
|
|
|
static void GenerateAnalyzerArgs(AnalyzerOptions &Opts,
|
|
|
|
SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA) {
|
|
|
|
const AnalyzerOptions *AnalyzerOpts = &Opts;
|
|
|
|
|
|
|
|
#define ANALYZER_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef ANALYZER_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
if (Opts.AnalysisStoreOpt != RegionStoreModel) {
|
|
|
|
switch (Opts.AnalysisStoreOpt) {
|
|
|
|
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
|
|
|
|
case NAME##Model: \
|
|
|
|
GenerateArg(Args, OPT_analyzer_store, CMDFLAG, SA); \
|
|
|
|
break;
|
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Tried to generate unknown analysis store.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) {
|
|
|
|
switch (Opts.AnalysisConstraintsOpt) {
|
|
|
|
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
|
|
|
|
case NAME##Model: \
|
|
|
|
GenerateArg(Args, OPT_analyzer_constraints, CMDFLAG, SA); \
|
|
|
|
break;
|
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Tried to generate unknown analysis constraint.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.AnalysisDiagOpt != PD_HTML) {
|
|
|
|
switch (Opts.AnalysisDiagOpt) {
|
|
|
|
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) \
|
|
|
|
case PD_##NAME: \
|
|
|
|
GenerateArg(Args, OPT_analyzer_output, CMDFLAG, SA); \
|
|
|
|
break;
|
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Tried to generate unknown analysis diagnostic client.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.AnalysisPurgeOpt != PurgeStmt) {
|
|
|
|
switch (Opts.AnalysisPurgeOpt) {
|
|
|
|
#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
|
|
|
|
case NAME: \
|
|
|
|
GenerateArg(Args, OPT_analyzer_purge, CMDFLAG, SA); \
|
|
|
|
break;
|
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Tried to generate unknown analysis purge mode.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.InliningMode != NoRedundancy) {
|
|
|
|
switch (Opts.InliningMode) {
|
|
|
|
#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) \
|
|
|
|
case NAME: \
|
|
|
|
GenerateArg(Args, OPT_analyzer_inlining_mode, CMDFLAG, SA); \
|
|
|
|
break;
|
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Tried to generate unknown analysis inlining mode.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &CP : Opts.CheckersAndPackages) {
|
|
|
|
OptSpecifier Opt =
|
|
|
|
CP.second ? OPT_analyzer_checker : OPT_analyzer_disable_checker;
|
|
|
|
GenerateArg(Args, Opt, CP.first, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
AnalyzerOptions ConfigOpts;
|
|
|
|
parseAnalyzerConfigs(ConfigOpts, nullptr);
|
|
|
|
|
|
|
|
for (const auto &C : Opts.Config) {
|
|
|
|
// Don't generate anything that came from parseAnalyzerConfigs. It would be
|
|
|
|
// redundant and may not be valid on the command line.
|
|
|
|
auto Entry = ConfigOpts.Config.find(C.getKey());
|
|
|
|
if (Entry != ConfigOpts.Config.end() && Entry->getValue() == C.getValue())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
GenerateArg(Args, OPT_analyzer_config, C.getKey() + "=" + C.getValue(), SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nothing to generate for FullCompilerInvocation.
|
|
|
|
}
|
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
|
|
|
|
DiagnosticsEngine &Diags) {
|
2021-04-16 15:30:28 +02:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
|
|
|
|
2021-02-08 09:04:21 +01:00
|
|
|
AnalyzerOptions *AnalyzerOpts = &Opts;
|
|
|
|
|
|
|
|
#define ANALYZER_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-02-08 09:04:21 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef ANALYZER_OPTION_WITH_MARSHALLING
|
|
|
|
|
2009-12-01 03:16:53 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_analyzer_store)) {
|
2012-11-01 04:30:05 +00:00
|
|
|
StringRef Name = A->getValue();
|
2009-12-01 03:16:53 +00:00
|
|
|
AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name)
|
|
|
|
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
|
|
|
|
.Case(CMDFLAG, NAME##Model)
|
2012-08-31 04:35:58 +00:00
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
2009-12-01 03:16:53 +00:00
|
|
|
.Default(NumStores);
|
2011-12-23 03:05:38 +00:00
|
|
|
if (Value == NumStores) {
|
2009-12-01 03:16:53 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
2010-06-09 22:30:54 +00:00
|
|
|
<< A->getAsString(Args) << Name;
|
2011-12-23 03:05:38 +00:00
|
|
|
} else {
|
2009-12-01 03:16:53 +00:00
|
|
|
Opts.AnalysisStoreOpt = Value;
|
2011-12-23 03:05:38 +00:00
|
|
|
}
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) {
|
2012-11-01 04:30:05 +00:00
|
|
|
StringRef Name = A->getValue();
|
2009-12-01 03:16:53 +00:00
|
|
|
AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name)
|
|
|
|
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
|
|
|
|
.Case(CMDFLAG, NAME##Model)
|
2012-08-31 04:35:58 +00:00
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
2009-12-01 03:16:53 +00:00
|
|
|
.Default(NumConstraints);
|
2011-12-23 03:05:38 +00:00
|
|
|
if (Value == NumConstraints) {
|
2009-12-01 03:16:53 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
2010-06-09 22:30:54 +00:00
|
|
|
<< A->getAsString(Args) << Name;
|
2011-12-23 03:05:38 +00:00
|
|
|
} else {
|
2022-02-22 15:30:47 +01:00
|
|
|
#ifndef LLVM_WITH_Z3
|
|
|
|
if (Value == AnalysisConstraints::Z3ConstraintsModel) {
|
|
|
|
Diags.Report(diag::err_analyzer_not_built_with_z3);
|
|
|
|
}
|
|
|
|
#endif // LLVM_WITH_Z3
|
2009-12-01 03:16:53 +00:00
|
|
|
Opts.AnalysisConstraintsOpt = Value;
|
2011-12-23 03:05:38 +00:00
|
|
|
}
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Arg *A = Args.getLastArg(OPT_analyzer_output)) {
|
2012-11-01 04:30:05 +00:00
|
|
|
StringRef Name = A->getValue();
|
2009-12-01 03:16:53 +00:00
|
|
|
AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name)
|
2013-08-16 01:06:30 +00:00
|
|
|
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) \
|
2009-12-01 03:16:53 +00:00
|
|
|
.Case(CMDFLAG, PD_##NAME)
|
2021-01-08 14:17:18 +01:00
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
2009-12-01 03:16:53 +00:00
|
|
|
.Default(NUM_ANALYSIS_DIAG_CLIENTS);
|
2011-12-23 03:05:38 +00:00
|
|
|
if (Value == NUM_ANALYSIS_DIAG_CLIENTS) {
|
2009-12-01 03:16:53 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
2010-06-09 22:30:54 +00:00
|
|
|
<< A->getAsString(Args) << Name;
|
2011-12-23 03:05:38 +00:00
|
|
|
} else {
|
2009-12-01 03:16:53 +00:00
|
|
|
Opts.AnalysisDiagOpt = Value;
|
2011-12-23 03:05:38 +00:00
|
|
|
}
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
2011-09-30 02:03:00 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) {
|
2012-11-01 04:30:05 +00:00
|
|
|
StringRef Name = A->getValue();
|
2011-09-30 02:03:00 +00:00
|
|
|
AnalysisPurgeMode Value = llvm::StringSwitch<AnalysisPurgeMode>(Name)
|
|
|
|
#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
|
|
|
|
.Case(CMDFLAG, NAME)
|
2012-08-31 04:35:58 +00:00
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
2011-09-30 02:03:00 +00:00
|
|
|
.Default(NumPurgeModes);
|
2011-12-23 03:05:38 +00:00
|
|
|
if (Value == NumPurgeModes) {
|
2011-09-30 02:03:00 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << Name;
|
2011-12-23 03:05:38 +00:00
|
|
|
} else {
|
2011-09-30 02:03:00 +00:00
|
|
|
Opts.AnalysisPurgeOpt = Value;
|
2011-12-23 03:05:38 +00:00
|
|
|
}
|
2011-09-30 02:03:00 +00:00
|
|
|
}
|
|
|
|
|
2012-03-08 23:16:35 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) {
|
2012-11-01 04:30:05 +00:00
|
|
|
StringRef Name = A->getValue();
|
2012-03-08 23:16:35 +00:00
|
|
|
AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name)
|
|
|
|
#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) \
|
|
|
|
.Case(CMDFLAG, NAME)
|
2012-08-31 04:35:58 +00:00
|
|
|
#include "clang/StaticAnalyzer/Core/Analyses.def"
|
2012-03-08 23:16:35 +00:00
|
|
|
.Default(NumInliningModes);
|
|
|
|
if (Value == NumInliningModes) {
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << Name;
|
|
|
|
} else {
|
|
|
|
Opts.InliningMode = Value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-16 01:53:14 +00:00
|
|
|
Opts.CheckersAndPackages.clear();
|
2015-06-09 01:57:17 +00:00
|
|
|
for (const Arg *A :
|
|
|
|
Args.filtered(OPT_analyzer_checker, OPT_analyzer_disable_checker)) {
|
2011-02-14 18:13:31 +00:00
|
|
|
A->claim();
|
2019-08-16 01:53:14 +00:00
|
|
|
bool IsEnabled = A->getOption().getID() == OPT_analyzer_checker;
|
2011-02-24 08:42:20 +00:00
|
|
|
// We can have a list of comma separated checker names, e.g:
|
|
|
|
// '-analyzer-checker=cocoa,unix'
|
2019-08-16 01:53:14 +00:00
|
|
|
StringRef CheckerAndPackageList = A->getValue();
|
|
|
|
SmallVector<StringRef, 16> CheckersAndPackages;
|
|
|
|
CheckerAndPackageList.split(CheckersAndPackages, ",");
|
2019-12-17 21:52:47 +01:00
|
|
|
for (const StringRef &CheckerOrPackage : CheckersAndPackages)
|
2020-01-29 02:48:15 +01:00
|
|
|
Opts.CheckersAndPackages.emplace_back(std::string(CheckerOrPackage),
|
|
|
|
IsEnabled);
|
2011-02-14 18:13:31 +00:00
|
|
|
}
|
2015-02-24 21:45:33 +00:00
|
|
|
|
2012-08-29 05:55:00 +00:00
|
|
|
// Go through the analyzer configuration options.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_analyzer_config)) {
|
2018-11-30 21:24:31 +00:00
|
|
|
|
2012-08-29 05:55:00 +00:00
|
|
|
// We can have a list of comma separated config names, e.g:
|
2012-08-30 05:49:16 +00:00
|
|
|
// '-analyzer-config key1=val1,key2=val2'
|
2012-11-01 04:30:05 +00:00
|
|
|
StringRef configList = A->getValue();
|
2012-08-29 05:55:00 +00:00
|
|
|
SmallVector<StringRef, 4> configVals;
|
|
|
|
configList.split(configVals, ",");
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto &configVal : configVals) {
|
2012-08-29 05:55:00 +00:00
|
|
|
StringRef key, val;
|
2018-03-26 21:45:04 +00:00
|
|
|
std::tie(key, val) = configVal.split("=");
|
2012-08-29 05:55:00 +00:00
|
|
|
if (val.empty()) {
|
|
|
|
Diags.Report(SourceLocation(),
|
2018-03-26 21:45:04 +00:00
|
|
|
diag::err_analyzer_config_no_value) << configVal;
|
2012-08-29 05:55:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2021-10-19 08:54:02 -07:00
|
|
|
if (val.contains('=')) {
|
2012-08-29 05:55:00 +00:00
|
|
|
Diags.Report(SourceLocation(),
|
|
|
|
diag::err_analyzer_config_multiple_values)
|
2018-03-26 21:45:04 +00:00
|
|
|
<< configVal;
|
2012-08-29 05:55:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-11-30 21:24:31 +00:00
|
|
|
|
|
|
|
// TODO: Check checker options too, possibly in CheckerRegistry.
|
|
|
|
// Leave unknown non-checker configs unclaimed.
|
|
|
|
if (!key.contains(":") && Opts.isUnknownAnalyzerConfig(key)) {
|
2021-04-16 15:30:28 +02:00
|
|
|
if (Opts.ShouldEmitErrorsOnInvalidConfigValue)
|
2018-11-30 21:24:31 +00:00
|
|
|
Diags.Report(diag::err_analyzer_config_unknown) << key;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
A->claim();
|
2020-01-28 20:23:46 +01:00
|
|
|
Opts.Config[key] = std::string(val);
|
2012-08-29 05:55:00 +00:00
|
|
|
}
|
|
|
|
}
|
2011-12-23 03:05:38 +00:00
|
|
|
|
2018-11-30 21:24:31 +00:00
|
|
|
if (Opts.ShouldEmitErrorsOnInvalidConfigValue)
|
|
|
|
parseAnalyzerConfigs(Opts, &Diags);
|
|
|
|
else
|
|
|
|
parseAnalyzerConfigs(Opts, nullptr);
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
|
2018-01-23 19:28:52 +00:00
|
|
|
llvm::raw_string_ostream os(Opts.FullCompilerInvocation);
|
2018-03-26 21:45:04 +00:00
|
|
|
for (unsigned i = 0; i < Args.getNumInputArgStrings(); ++i) {
|
2018-01-23 19:28:52 +00:00
|
|
|
if (i != 0)
|
|
|
|
os << " ";
|
|
|
|
os << Args.getArgString(i);
|
|
|
|
}
|
|
|
|
os.flush();
|
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
static StringRef getStringOption(AnalyzerOptions::ConfigTable &Config,
|
|
|
|
StringRef OptionName, StringRef DefaultVal) {
|
2020-01-28 20:23:46 +01:00
|
|
|
return Config.insert({OptionName, std::string(DefaultVal)}).first->second;
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void initOption(AnalyzerOptions::ConfigTable &Config,
|
2018-11-30 21:24:31 +00:00
|
|
|
DiagnosticsEngine *Diags,
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
StringRef &OptionField, StringRef Name,
|
|
|
|
StringRef DefaultVal) {
|
2018-11-30 21:24:31 +00:00
|
|
|
// String options may be known to invalid (e.g. if the expected string is a
|
|
|
|
// file name, but the file does not exist), those will have to be checked in
|
|
|
|
// parseConfigs.
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
OptionField = getStringOption(Config, Name, DefaultVal);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void initOption(AnalyzerOptions::ConfigTable &Config,
|
2018-11-30 21:24:31 +00:00
|
|
|
DiagnosticsEngine *Diags,
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
bool &OptionField, StringRef Name, bool DefaultVal) {
|
2018-11-30 21:24:31 +00:00
|
|
|
auto PossiblyInvalidVal = llvm::StringSwitch<Optional<bool>>(
|
|
|
|
getStringOption(Config, Name, (DefaultVal ? "true" : "false")))
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
.Case("true", true)
|
|
|
|
.Case("false", false)
|
2018-11-30 21:24:31 +00:00
|
|
|
.Default(None);
|
|
|
|
|
|
|
|
if (!PossiblyInvalidVal) {
|
|
|
|
if (Diags)
|
|
|
|
Diags->Report(diag::err_analyzer_config_invalid_input)
|
|
|
|
<< Name << "a boolean";
|
|
|
|
else
|
|
|
|
OptionField = DefaultVal;
|
|
|
|
} else
|
|
|
|
OptionField = PossiblyInvalidVal.getValue();
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void initOption(AnalyzerOptions::ConfigTable &Config,
|
2018-11-30 21:24:31 +00:00
|
|
|
DiagnosticsEngine *Diags,
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
unsigned &OptionField, StringRef Name,
|
|
|
|
unsigned DefaultVal) {
|
2018-11-30 21:24:31 +00:00
|
|
|
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
OptionField = DefaultVal;
|
|
|
|
bool HasFailed = getStringOption(Config, Name, std::to_string(DefaultVal))
|
[analyzer][NFC] Reimplement checker options
TL;DR:
* Add checker and package options to the TableGen files
* Added a new class called CmdLineOption, and both Package and Checker recieved
a list<CmdLineOption> field.
* Added every existing checker and package option to Checkers.td.
* The CheckerRegistry class
* Received some comments to most of it's inline classes
* Received the CmdLineOption and PackageInfo inline classes, a list of
CmdLineOption was added to CheckerInfo and PackageInfo
* Added addCheckerOption and addPackageOption
* Added a new field called Packages, used in addPackageOptions, filled up in
addPackage
Detailed description:
In the last couple months, a lot of effort was put into tightening the
analyzer's command line interface. The main issue is that it's spectacularly
easy to mess up a lenghty enough invocation of the analyzer, and the user was
given no warnings or errors at all in that case.
We can divide the effort of resolving this into several chapters:
* Non-checker analyzer configurations:
Gather every analyzer configuration into a dedicated file. Emit errors for
non-existent configurations or incorrect values. Be able to list these
configurations. Tighten AnalyzerOptions interface to disallow making such
a mistake in the future.
* Fix the "Checker Naming Bug" by reimplementing checker dependencies:
When cplusplus.InnerPointer was enabled, it implicitly registered
unix.Malloc, which implicitly registered some sort of a modeling checker
from the CStringChecker family. This resulted in all of these checker
objects recieving the name "cplusplus.InnerPointer", making AnalyzerOptions
asking for the wrong checker options from the command line:
cplusplus.InnerPointer:Optimisic
istead of
unix.Malloc:Optimistic.
This was resolved by making CheckerRegistry responsible for checker
dependency handling, instead of checkers themselves.
* Checker options: (this patch included!)
Same as the first item, but for checkers.
(+ minor fixes here and there, and everything else that is yet to come)
There were several issues regarding checker options, that non-checker
configurations didn't suffer from: checker plugins are loaded runtime, and they
could add new checkers and new options, meaning that unlike for non-checker
configurations, we can't collect every checker option purely by generating code.
Also, as seen from the "Checker Naming Bug" issue raised above, they are very
rarely used in practice, and all sorts of skeletons fell out of the closet while
working on this project.
They were extremely problematic for users as well, purely because of how long
they were. Consider the following monster of a checker option:
alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=false
While we were able to verify whether the checker itself (the part before the
colon) existed, any errors past that point were unreported, easily resulting
in 7+ hours of analyses going to waste.
This patch, similarly to how dependencies were reimplemented, uses TableGen to
register checker options into Checkers.td, so that Checkers.inc now contains
entries for both checker and package options. Using the preprocessor,
Checkers.inc is converted into code in CheckerRegistry, adding every builtin
(checkers and packages that have an entry in the Checkers.td file) checker and
package option to the registry. The new addPackageOption and addCheckerOption
functions expose the same functionality to statically-linked non-builtin and
plugin checkers and packages as well.
Emitting errors for incorrect user input, being able to list these options, and
some other functionalies will land in later patches.
Differential Revision: https://reviews.llvm.org/D57855
llvm-svn: 358752
2019-04-19 12:32:10 +00:00
|
|
|
.getAsInteger(0, OptionField);
|
2018-11-30 21:24:31 +00:00
|
|
|
if (Diags && HasFailed)
|
|
|
|
Diags->Report(diag::err_analyzer_config_invalid_input)
|
|
|
|
<< Name << "an unsigned";
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts,
|
2018-11-30 21:24:31 +00:00
|
|
|
DiagnosticsEngine *Diags) {
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
// TODO: There's no need to store the entire configtable, it'd be plenty
|
|
|
|
// enough tostore checker options.
|
|
|
|
|
|
|
|
#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \
|
2018-11-30 21:24:31 +00:00
|
|
|
initOption(AnOpts.Config, Diags, AnOpts.NAME, CMDFLAG, DEFAULT_VAL);
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
|
|
|
|
#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \
|
|
|
|
SHALLOW_VAL, DEEP_VAL) \
|
|
|
|
switch (AnOpts.getUserMode()) { \
|
|
|
|
case UMK_Shallow: \
|
2018-11-30 21:24:31 +00:00
|
|
|
initOption(AnOpts.Config, Diags, AnOpts.NAME, CMDFLAG, SHALLOW_VAL); \
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
break; \
|
|
|
|
case UMK_Deep: \
|
2018-11-30 21:24:31 +00:00
|
|
|
initOption(AnOpts.Config, Diags, AnOpts.NAME, CMDFLAG, DEEP_VAL); \
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
|
|
|
|
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
|
|
|
|
#undef ANALYZER_OPTION
|
|
|
|
#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
|
2018-11-30 21:24:31 +00:00
|
|
|
|
|
|
|
// At this point, AnalyzerOptions is configured. Let's validate some options.
|
|
|
|
|
2019-08-16 01:53:14 +00:00
|
|
|
// FIXME: Here we try to validate the silenced checkers or packages are valid.
|
|
|
|
// The current approach only validates the registered checkers which does not
|
|
|
|
// contain the runtime enabled checkers and optimally we would validate both.
|
|
|
|
if (!AnOpts.RawSilencedCheckersAndPackages.empty()) {
|
|
|
|
std::vector<StringRef> Checkers =
|
|
|
|
AnOpts.getRegisteredCheckers(/*IncludeExperimental=*/true);
|
|
|
|
std::vector<StringRef> Packages =
|
|
|
|
AnOpts.getRegisteredPackages(/*IncludeExperimental=*/true);
|
|
|
|
|
|
|
|
SmallVector<StringRef, 16> CheckersAndPackages;
|
|
|
|
AnOpts.RawSilencedCheckersAndPackages.split(CheckersAndPackages, ";");
|
|
|
|
|
2019-12-17 21:52:47 +01:00
|
|
|
for (const StringRef &CheckerOrPackage : CheckersAndPackages) {
|
2019-08-24 12:17:49 +00:00
|
|
|
if (Diags) {
|
|
|
|
bool IsChecker = CheckerOrPackage.contains('.');
|
2021-10-13 20:41:54 -07:00
|
|
|
bool IsValidName = IsChecker
|
|
|
|
? llvm::is_contained(Checkers, CheckerOrPackage)
|
|
|
|
: llvm::is_contained(Packages, CheckerOrPackage);
|
2019-08-24 12:17:49 +00:00
|
|
|
|
|
|
|
if (!IsValidName)
|
|
|
|
Diags->Report(diag::err_unknown_analyzer_checker_or_package)
|
|
|
|
<< CheckerOrPackage;
|
|
|
|
}
|
2019-08-16 01:53:14 +00:00
|
|
|
|
|
|
|
AnOpts.SilencedCheckersAndPackages.emplace_back(CheckerOrPackage);
|
|
|
|
}
|
|
|
|
}
|
2019-08-24 12:17:49 +00:00
|
|
|
|
|
|
|
if (!Diags)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (AnOpts.ShouldTrackConditionsDebug && !AnOpts.ShouldTrackConditions)
|
|
|
|
Diags->Report(diag::err_analyzer_config_invalid_input)
|
|
|
|
<< "track-conditions-debug" << "'track-conditions' to also be enabled";
|
|
|
|
|
|
|
|
if (!AnOpts.CTUDir.empty() && !llvm::sys::fs::is_directory(AnOpts.CTUDir))
|
|
|
|
Diags->Report(diag::err_analyzer_config_invalid_input) << "ctu-dir"
|
|
|
|
<< "a filename";
|
|
|
|
|
|
|
|
if (!AnOpts.ModelPath.empty() &&
|
|
|
|
!llvm::sys::fs::is_directory(AnOpts.ModelPath))
|
|
|
|
Diags->Report(diag::err_analyzer_config_invalid_input) << "model-path"
|
|
|
|
<< "a filename";
|
[analyzer] Evaluate all non-checker config options before analysis
In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.
Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.
However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.
Also, almost all options related class have a similar interface, so uniformity
is also a benefit.
The implementation for errors on invalid input will be commited shorty.
Differential Revision: https://reviews.llvm.org/D53692
llvm-svn: 348031
2018-11-30 20:44:00 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 09:05:08 +01:00
|
|
|
/// Generate a remark argument. This is an inverse of `ParseOptimizationRemark`.
|
|
|
|
static void
|
|
|
|
GenerateOptimizationRemark(SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA,
|
|
|
|
OptSpecifier OptEQ, StringRef Name,
|
|
|
|
const CodeGenOptions::OptRemark &Remark) {
|
|
|
|
if (Remark.hasValidPattern()) {
|
|
|
|
GenerateArg(Args, OptEQ, Remark.Pattern, SA);
|
|
|
|
} else if (Remark.Kind == CodeGenOptions::RK_Enabled) {
|
|
|
|
GenerateArg(Args, OPT_R_Joined, Name, SA);
|
|
|
|
} else if (Remark.Kind == CodeGenOptions::RK_Disabled) {
|
|
|
|
GenerateArg(Args, OPT_R_Joined, StringRef("no-") + Name, SA);
|
|
|
|
}
|
2021-02-25 14:50:56 +02:00
|
|
|
}
|
2021-02-25 09:05:08 +01:00
|
|
|
|
|
|
|
/// Parse a remark command line argument. It may be missing, disabled/enabled by
|
|
|
|
/// '-R[no-]group' or specified with a regular expression by '-Rgroup=regexp'.
|
|
|
|
/// On top of that, it can be disabled/enabled globally by '-R[no-]everything'.
|
|
|
|
static CodeGenOptions::OptRemark
|
|
|
|
ParseOptimizationRemark(DiagnosticsEngine &Diags, ArgList &Args,
|
|
|
|
OptSpecifier OptEQ, StringRef Name) {
|
|
|
|
CodeGenOptions::OptRemark Result;
|
|
|
|
|
2021-09-21 14:09:17 -07:00
|
|
|
auto InitializeResultPattern = [&Diags, &Args, &Result](const Arg *A,
|
|
|
|
StringRef Pattern) {
|
|
|
|
Result.Pattern = Pattern.str();
|
2021-02-25 09:05:08 +01:00
|
|
|
|
|
|
|
std::string RegexError;
|
|
|
|
Result.Regex = std::make_shared<llvm::Regex>(Result.Pattern);
|
|
|
|
if (!Result.Regex->isValid(RegexError)) {
|
|
|
|
Diags.Report(diag::err_drv_optimization_remark_pattern)
|
|
|
|
<< RegexError << A->getAsString(Args);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
for (Arg *A : Args) {
|
|
|
|
if (A->getOption().matches(OPT_R_Joined)) {
|
|
|
|
StringRef Value = A->getValue();
|
|
|
|
|
|
|
|
if (Value == Name)
|
|
|
|
Result.Kind = CodeGenOptions::RK_Enabled;
|
|
|
|
else if (Value == "everything")
|
|
|
|
Result.Kind = CodeGenOptions::RK_EnabledEverything;
|
|
|
|
else if (Value.split('-') == std::make_pair(StringRef("no"), Name))
|
|
|
|
Result.Kind = CodeGenOptions::RK_Disabled;
|
|
|
|
else if (Value == "no-everything")
|
|
|
|
Result.Kind = CodeGenOptions::RK_DisabledEverything;
|
2021-09-28 18:33:26 -07:00
|
|
|
else
|
|
|
|
continue;
|
2021-09-21 14:09:17 -07:00
|
|
|
|
|
|
|
if (Result.Kind == CodeGenOptions::RK_Disabled ||
|
|
|
|
Result.Kind == CodeGenOptions::RK_DisabledEverything) {
|
|
|
|
Result.Pattern = "";
|
|
|
|
Result.Regex = nullptr;
|
|
|
|
} else {
|
|
|
|
InitializeResultPattern(A, ".*");
|
|
|
|
}
|
2021-02-25 09:05:08 +01:00
|
|
|
} else if (A->getOption().matches(OptEQ)) {
|
|
|
|
Result.Kind = CodeGenOptions::RK_WithPattern;
|
2021-09-21 14:09:17 -07:00
|
|
|
if (!InitializeResultPattern(A, A->getValue()))
|
2021-02-25 09:05:08 +01:00
|
|
|
return CodeGenOptions::OptRemark();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
2014-05-29 19:55:06 +00:00
|
|
|
}
|
|
|
|
|
2015-06-13 07:11:40 +00:00
|
|
|
static bool parseDiagnosticLevelMask(StringRef FlagName,
|
|
|
|
const std::vector<std::string> &Levels,
|
2020-12-22 15:05:16 +01:00
|
|
|
DiagnosticsEngine &Diags,
|
2015-06-13 07:11:40 +00:00
|
|
|
DiagnosticLevelMask &M) {
|
|
|
|
bool Success = true;
|
|
|
|
for (const auto &Level : Levels) {
|
|
|
|
DiagnosticLevelMask const PM =
|
|
|
|
llvm::StringSwitch<DiagnosticLevelMask>(Level)
|
|
|
|
.Case("note", DiagnosticLevelMask::Note)
|
|
|
|
.Case("remark", DiagnosticLevelMask::Remark)
|
|
|
|
.Case("warning", DiagnosticLevelMask::Warning)
|
|
|
|
.Case("error", DiagnosticLevelMask::Error)
|
|
|
|
.Default(DiagnosticLevelMask::None);
|
|
|
|
if (PM == DiagnosticLevelMask::None) {
|
|
|
|
Success = false;
|
2020-12-22 15:05:16 +01:00
|
|
|
Diags.Report(diag::err_drv_invalid_value) << FlagName << Level;
|
2015-06-13 07:11:40 +00:00
|
|
|
}
|
|
|
|
M = M | PM;
|
|
|
|
}
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-12 22:39:12 +00:00
|
|
|
static void parseSanitizerKinds(StringRef FlagName,
|
|
|
|
const std::vector<std::string> &Sanitizers,
|
|
|
|
DiagnosticsEngine &Diags, SanitizerSet &S) {
|
|
|
|
for (const auto &Sanitizer : Sanitizers) {
|
2015-05-11 21:39:20 +00:00
|
|
|
SanitizerMask K = parseSanitizerValue(Sanitizer, /*AllowGroups=*/false);
|
2019-03-01 10:05:15 +00:00
|
|
|
if (K == SanitizerMask())
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-12 22:39:12 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value) << FlagName << Sanitizer;
|
|
|
|
else
|
|
|
|
S.set(K, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-09 10:17:04 +01:00
|
|
|
static SmallVector<StringRef, 4> serializeSanitizerKinds(SanitizerSet S) {
|
|
|
|
SmallVector<StringRef, 4> Values;
|
|
|
|
serializeSanitizerSet(S, Values);
|
|
|
|
return Values;
|
|
|
|
}
|
|
|
|
|
2018-04-13 02:31:58 +00:00
|
|
|
static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle,
|
|
|
|
ArgList &Args, DiagnosticsEngine &D,
|
|
|
|
XRayInstrSet &S) {
|
|
|
|
llvm::SmallVector<StringRef, 2> BundleParts;
|
|
|
|
llvm::SplitString(Bundle, BundleParts, ",");
|
2019-12-17 21:52:47 +01:00
|
|
|
for (const auto &B : BundleParts) {
|
2018-04-13 02:31:58 +00:00
|
|
|
auto Mask = parseXRayInstrValue(B);
|
|
|
|
if (Mask == XRayInstrKind::None)
|
|
|
|
if (B != "none")
|
|
|
|
D.Report(diag::err_drv_invalid_value) << FlagName << Bundle;
|
|
|
|
else
|
|
|
|
S.Mask = Mask;
|
|
|
|
else if (Mask == XRayInstrKind::All)
|
|
|
|
S.Mask = Mask;
|
|
|
|
else
|
|
|
|
S.set(Mask, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-09 11:42:01 +01:00
|
|
|
static std::string serializeXRayInstrumentationBundle(const XRayInstrSet &S) {
|
|
|
|
llvm::SmallVector<StringRef, 2> BundleParts;
|
|
|
|
serializeXRayInstrValue(S, BundleParts);
|
|
|
|
std::string Buffer;
|
|
|
|
llvm::raw_string_ostream OS(Buffer);
|
|
|
|
llvm::interleave(BundleParts, OS, [&OS](StringRef Part) { OS << Part; }, ",");
|
2021-12-09 15:02:35 -08:00
|
|
|
return Buffer;
|
2021-02-09 11:42:01 +01:00
|
|
|
}
|
|
|
|
|
2016-03-02 20:59:36 +00:00
|
|
|
// Set the profile kind using fprofile-instrument-use-path.
|
|
|
|
static void setPGOUseInstrumentor(CodeGenOptions &Opts,
|
2016-05-29 11:04:56 +00:00
|
|
|
const Twine &ProfileName) {
|
2016-03-02 20:59:36 +00:00
|
|
|
auto ReaderOrErr = llvm::IndexedInstrProfReader::create(ProfileName);
|
|
|
|
// In error, return silently and let Clang PGOUse report the error message.
|
2016-05-19 03:54:54 +00:00
|
|
|
if (auto E = ReaderOrErr.takeError()) {
|
|
|
|
llvm::consumeError(std::move(E));
|
2016-03-02 20:59:36 +00:00
|
|
|
Opts.setProfileUse(CodeGenOptions::ProfileClangInstr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader =
|
|
|
|
std::move(ReaderOrErr.get());
|
2019-03-04 20:21:31 +00:00
|
|
|
if (PGOReader->isIRLevelProfile()) {
|
|
|
|
if (PGOReader->hasCSIRLevelProfile())
|
|
|
|
Opts.setProfileUse(CodeGenOptions::ProfileCSIRInstr);
|
|
|
|
else
|
|
|
|
Opts.setProfileUse(CodeGenOptions::ProfileIRInstr);
|
|
|
|
} else
|
2016-03-02 20:59:36 +00:00
|
|
|
Opts.setProfileUse(CodeGenOptions::ProfileClangInstr);
|
|
|
|
}
|
|
|
|
|
2021-02-09 11:42:01 +01:00
|
|
|
void CompilerInvocation::GenerateCodeGenArgs(
|
|
|
|
const CodeGenOptions &Opts, SmallVectorImpl<const char *> &Args,
|
|
|
|
StringAllocator SA, const llvm::Triple &T, const std::string &OutputFile,
|
|
|
|
const LangOptions *LangOpts) {
|
|
|
|
const CodeGenOptions &CodeGenOpts = Opts;
|
|
|
|
|
|
|
|
if (Opts.OptimizationLevel == 0)
|
|
|
|
GenerateArg(Args, OPT_O0, SA);
|
|
|
|
else
|
|
|
|
GenerateArg(Args, OPT_O, Twine(Opts.OptimizationLevel), SA);
|
|
|
|
|
|
|
|
#define CODEGEN_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef CODEGEN_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
if (Opts.OptimizationLevel > 0) {
|
|
|
|
if (Opts.Inlining == CodeGenOptions::NormalInlining)
|
|
|
|
GenerateArg(Args, OPT_finline_functions, SA);
|
|
|
|
else if (Opts.Inlining == CodeGenOptions::OnlyHintInlining)
|
|
|
|
GenerateArg(Args, OPT_finline_hint_functions, SA);
|
|
|
|
else if (Opts.Inlining == CodeGenOptions::OnlyAlwaysInlining)
|
|
|
|
GenerateArg(Args, OPT_fno_inline, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.DirectAccessExternalData && LangOpts->PICLevel != 0)
|
|
|
|
GenerateArg(Args, OPT_fdirect_access_external_data, SA);
|
|
|
|
else if (!Opts.DirectAccessExternalData && LangOpts->PICLevel == 0)
|
|
|
|
GenerateArg(Args, OPT_fno_direct_access_external_data, SA);
|
|
|
|
|
|
|
|
Optional<StringRef> DebugInfoVal;
|
|
|
|
switch (Opts.DebugInfo) {
|
|
|
|
case codegenoptions::DebugLineTablesOnly:
|
|
|
|
DebugInfoVal = "line-tables-only";
|
|
|
|
break;
|
|
|
|
case codegenoptions::DebugDirectivesOnly:
|
|
|
|
DebugInfoVal = "line-directives-only";
|
|
|
|
break;
|
|
|
|
case codegenoptions::DebugInfoConstructor:
|
|
|
|
DebugInfoVal = "constructor";
|
|
|
|
break;
|
|
|
|
case codegenoptions::LimitedDebugInfo:
|
|
|
|
DebugInfoVal = "limited";
|
|
|
|
break;
|
|
|
|
case codegenoptions::FullDebugInfo:
|
|
|
|
DebugInfoVal = "standalone";
|
|
|
|
break;
|
|
|
|
case codegenoptions::UnusedTypeInfo:
|
|
|
|
DebugInfoVal = "unused-types";
|
|
|
|
break;
|
|
|
|
case codegenoptions::NoDebugInfo: // default value
|
|
|
|
DebugInfoVal = None;
|
|
|
|
break;
|
|
|
|
case codegenoptions::LocTrackingOnly: // implied value
|
|
|
|
DebugInfoVal = None;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (DebugInfoVal)
|
|
|
|
GenerateArg(Args, OPT_debug_info_kind_EQ, *DebugInfoVal, SA);
|
|
|
|
|
|
|
|
for (const auto &Prefix : Opts.DebugPrefixMap)
|
|
|
|
GenerateArg(Args, OPT_fdebug_prefix_map_EQ,
|
|
|
|
Prefix.first + "=" + Prefix.second, SA);
|
|
|
|
|
2021-02-24 19:04:36 -08:00
|
|
|
for (const auto &Prefix : Opts.CoveragePrefixMap)
|
|
|
|
GenerateArg(Args, OPT_fcoverage_prefix_map_EQ,
|
2021-02-09 11:42:01 +01:00
|
|
|
Prefix.first + "=" + Prefix.second, SA);
|
|
|
|
|
|
|
|
if (Opts.NewStructPathTBAA)
|
|
|
|
GenerateArg(Args, OPT_new_struct_path_tbaa, SA);
|
|
|
|
|
|
|
|
if (Opts.OptimizeSize == 1)
|
|
|
|
GenerateArg(Args, OPT_O, "s", SA);
|
|
|
|
else if (Opts.OptimizeSize == 2)
|
|
|
|
GenerateArg(Args, OPT_O, "z", SA);
|
|
|
|
|
|
|
|
// SimplifyLibCalls is set only in the absence of -fno-builtin and
|
|
|
|
// -ffreestanding. We'll consider that when generating them.
|
|
|
|
|
|
|
|
// NoBuiltinFuncs are generated by LangOptions.
|
|
|
|
|
|
|
|
if (Opts.UnrollLoops && Opts.OptimizationLevel <= 1)
|
|
|
|
GenerateArg(Args, OPT_funroll_loops, SA);
|
|
|
|
else if (!Opts.UnrollLoops && Opts.OptimizationLevel > 1)
|
|
|
|
GenerateArg(Args, OPT_fno_unroll_loops, SA);
|
|
|
|
|
|
|
|
if (!Opts.BinutilsVersion.empty())
|
|
|
|
GenerateArg(Args, OPT_fbinutils_version_EQ, Opts.BinutilsVersion, SA);
|
|
|
|
|
|
|
|
if (Opts.DebugNameTable ==
|
|
|
|
static_cast<unsigned>(llvm::DICompileUnit::DebugNameTableKind::GNU))
|
|
|
|
GenerateArg(Args, OPT_ggnu_pubnames, SA);
|
|
|
|
else if (Opts.DebugNameTable ==
|
|
|
|
static_cast<unsigned>(
|
|
|
|
llvm::DICompileUnit::DebugNameTableKind::Default))
|
|
|
|
GenerateArg(Args, OPT_gpubnames, SA);
|
|
|
|
|
2021-09-21 20:25:13 -07:00
|
|
|
auto TNK = Opts.getDebugSimpleTemplateNames();
|
|
|
|
if (TNK != codegenoptions::DebugTemplateNamesKind::Full) {
|
|
|
|
if (TNK == codegenoptions::DebugTemplateNamesKind::Simple)
|
|
|
|
GenerateArg(Args, OPT_gsimple_template_names_EQ, "simple", SA);
|
2021-09-24 11:15:53 -07:00
|
|
|
else if (TNK == codegenoptions::DebugTemplateNamesKind::Mangled)
|
2021-09-21 20:25:13 -07:00
|
|
|
GenerateArg(Args, OPT_gsimple_template_names_EQ, "mangled", SA);
|
|
|
|
}
|
2021-02-09 11:42:01 +01:00
|
|
|
// ProfileInstrumentUsePath is marshalled automatically, no need to generate
|
|
|
|
// it or PGOUseInstrumentor.
|
|
|
|
|
|
|
|
if (Opts.TimePasses) {
|
|
|
|
if (Opts.TimePassesPerRun)
|
|
|
|
GenerateArg(Args, OPT_ftime_report_EQ, "per-pass-run", SA);
|
|
|
|
else
|
|
|
|
GenerateArg(Args, OPT_ftime_report, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.PrepareForLTO && !Opts.PrepareForThinLTO)
|
2021-09-08 15:52:19 -07:00
|
|
|
GenerateArg(Args, OPT_flto_EQ, "full", SA);
|
2021-02-09 11:42:01 +01:00
|
|
|
|
|
|
|
if (Opts.PrepareForThinLTO)
|
|
|
|
GenerateArg(Args, OPT_flto_EQ, "thin", SA);
|
|
|
|
|
|
|
|
if (!Opts.ThinLTOIndexFile.empty())
|
|
|
|
GenerateArg(Args, OPT_fthinlto_index_EQ, Opts.ThinLTOIndexFile, SA);
|
|
|
|
|
|
|
|
if (Opts.SaveTempsFilePrefix == OutputFile)
|
|
|
|
GenerateArg(Args, OPT_save_temps_EQ, "obj", SA);
|
|
|
|
|
|
|
|
StringRef MemProfileBasename("memprof.profraw");
|
|
|
|
if (!Opts.MemoryProfileOutput.empty()) {
|
|
|
|
if (Opts.MemoryProfileOutput == MemProfileBasename) {
|
|
|
|
GenerateArg(Args, OPT_fmemory_profile, SA);
|
|
|
|
} else {
|
|
|
|
size_t ArgLength =
|
|
|
|
Opts.MemoryProfileOutput.size() - MemProfileBasename.size();
|
|
|
|
GenerateArg(Args, OPT_fmemory_profile_EQ,
|
|
|
|
Opts.MemoryProfileOutput.substr(0, ArgLength), SA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(Opts.CoverageVersion, "408*", 4) != 0)
|
2021-02-25 10:10:40 +01:00
|
|
|
GenerateArg(Args, OPT_coverage_version_EQ,
|
|
|
|
StringRef(Opts.CoverageVersion, 4), SA);
|
2021-02-09 11:42:01 +01:00
|
|
|
|
|
|
|
// TODO: Check if we need to generate arguments stored in CmdArgs. (Namely
|
|
|
|
// '-fembed_bitcode', which does not map to any CompilerInvocation field and
|
|
|
|
// won't be generated.)
|
|
|
|
|
|
|
|
if (Opts.XRayInstrumentationBundle.Mask != XRayInstrKind::All) {
|
|
|
|
std::string InstrBundle =
|
|
|
|
serializeXRayInstrumentationBundle(Opts.XRayInstrumentationBundle);
|
|
|
|
if (!InstrBundle.empty())
|
|
|
|
GenerateArg(Args, OPT_fxray_instrumentation_bundle, InstrBundle, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.CFProtectionReturn && Opts.CFProtectionBranch)
|
|
|
|
GenerateArg(Args, OPT_fcf_protection_EQ, "full", SA);
|
|
|
|
else if (Opts.CFProtectionReturn)
|
|
|
|
GenerateArg(Args, OPT_fcf_protection_EQ, "return", SA);
|
|
|
|
else if (Opts.CFProtectionBranch)
|
|
|
|
GenerateArg(Args, OPT_fcf_protection_EQ, "branch", SA);
|
|
|
|
|
2022-04-29 14:32:48 +08:00
|
|
|
if (Opts.IBTSeal)
|
|
|
|
GenerateArg(Args, OPT_mibt_seal, SA);
|
|
|
|
|
2021-02-09 11:42:01 +01:00
|
|
|
for (const auto &F : Opts.LinkBitcodeFiles) {
|
|
|
|
bool Builtint = F.LinkFlags == llvm::Linker::Flags::LinkOnlyNeeded &&
|
|
|
|
F.PropagateAttrs && F.Internalize;
|
|
|
|
GenerateArg(Args,
|
|
|
|
Builtint ? OPT_mlink_builtin_bitcode : OPT_mlink_bitcode_file,
|
|
|
|
F.Filename, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Consider removing marshalling annotations from f[no_]emulated_tls.
|
|
|
|
// That would make it easy to generate the option only **once** if it was
|
|
|
|
// explicitly set to non-default value.
|
|
|
|
if (Opts.ExplicitEmulatedTLS) {
|
|
|
|
GenerateArg(
|
|
|
|
Args, Opts.EmulatedTLS ? OPT_femulated_tls : OPT_fno_emulated_tls, SA);
|
|
|
|
}
|
|
|
|
|
2021-03-02 13:02:04 +01:00
|
|
|
if (Opts.FPDenormalMode != llvm::DenormalMode::getIEEE())
|
|
|
|
GenerateArg(Args, OPT_fdenormal_fp_math_EQ, Opts.FPDenormalMode.str(), SA);
|
2021-02-09 11:42:01 +01:00
|
|
|
|
Additionally set f32 mode with denormal-fp-math
When the denormal-fp-math option is used, this should set the
denormal handling mode for all floating point types. However,
currently 32-bit float types can ignore this setting as there is a
variant of the option, denormal-fp-math-f32, specifically for that type
which takes priority when checking the mode based on type and remains
at the default of IEEE. From the description, denormal-fp-math would
be expected to set the mode for floats unless overridden by the f32
variant, and code in the front end only emits the f32 option if it is
different to the general one, so setting just denormal-fp-math should
be valid.
This patch changes the denormal-fp-math option to also set the f32
mode. If denormal-fp-math-f32 is also specified, this is then
overridden as expected, but if it is absent floats will be set to the
mode specified by the former option, rather than remain on the default.
Reviewed By: arsenm
Differential Revision: https://reviews.llvm.org/D122589
2022-04-29 15:06:12 +01:00
|
|
|
if ((Opts.FPDenormalMode != Opts.FP32DenormalMode) ||
|
|
|
|
(Opts.FP32DenormalMode != llvm::DenormalMode::getIEEE()))
|
2021-03-02 13:02:04 +01:00
|
|
|
GenerateArg(Args, OPT_fdenormal_fp_math_f32_EQ, Opts.FP32DenormalMode.str(),
|
|
|
|
SA);
|
2021-02-09 11:42:01 +01:00
|
|
|
|
|
|
|
if (Opts.StructReturnConvention == CodeGenOptions::SRCK_OnStack) {
|
|
|
|
OptSpecifier Opt =
|
|
|
|
T.isPPC32() ? OPT_maix_struct_return : OPT_fpcc_struct_return;
|
|
|
|
GenerateArg(Args, Opt, SA);
|
|
|
|
} else if (Opts.StructReturnConvention == CodeGenOptions::SRCK_InRegs) {
|
|
|
|
OptSpecifier Opt =
|
|
|
|
T.isPPC32() ? OPT_msvr4_struct_return : OPT_freg_struct_return;
|
|
|
|
GenerateArg(Args, Opt, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.EnableAIXExtendedAltivecABI)
|
|
|
|
GenerateArg(Args, OPT_mabi_EQ_vec_extabi, SA);
|
|
|
|
|
|
|
|
if (!Opts.OptRecordPasses.empty())
|
|
|
|
GenerateArg(Args, OPT_opt_record_passes, Opts.OptRecordPasses, SA);
|
|
|
|
|
|
|
|
if (!Opts.OptRecordFormat.empty())
|
|
|
|
GenerateArg(Args, OPT_opt_record_format, Opts.OptRecordFormat, SA);
|
|
|
|
|
2021-02-25 09:05:08 +01:00
|
|
|
GenerateOptimizationRemark(Args, SA, OPT_Rpass_EQ, "pass",
|
|
|
|
Opts.OptimizationRemark);
|
2021-02-09 11:42:01 +01:00
|
|
|
|
2021-02-25 09:05:08 +01:00
|
|
|
GenerateOptimizationRemark(Args, SA, OPT_Rpass_missed_EQ, "pass-missed",
|
|
|
|
Opts.OptimizationRemarkMissed);
|
2021-02-09 11:42:01 +01:00
|
|
|
|
2021-02-25 09:05:08 +01:00
|
|
|
GenerateOptimizationRemark(Args, SA, OPT_Rpass_analysis_EQ, "pass-analysis",
|
|
|
|
Opts.OptimizationRemarkAnalysis);
|
2021-02-09 11:42:01 +01:00
|
|
|
|
|
|
|
GenerateArg(Args, OPT_fdiagnostics_hotness_threshold_EQ,
|
|
|
|
Opts.DiagnosticsHotnessThreshold
|
|
|
|
? Twine(*Opts.DiagnosticsHotnessThreshold)
|
|
|
|
: "auto",
|
|
|
|
SA);
|
|
|
|
|
2022-04-01 22:03:48 +00:00
|
|
|
GenerateArg(Args, OPT_fdiagnostics_misexpect_tolerance_EQ,
|
|
|
|
Twine(*Opts.DiagnosticsMisExpectTolerance), SA);
|
|
|
|
|
2021-02-09 11:42:01 +01:00
|
|
|
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeRecover))
|
|
|
|
GenerateArg(Args, OPT_fsanitize_recover_EQ, Sanitizer, SA);
|
|
|
|
|
|
|
|
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeTrap))
|
|
|
|
GenerateArg(Args, OPT_fsanitize_trap_EQ, Sanitizer, SA);
|
|
|
|
|
|
|
|
if (!Opts.EmitVersionIdentMetadata)
|
|
|
|
GenerateArg(Args, OPT_Qn, SA);
|
2021-02-16 14:27:21 +01:00
|
|
|
|
|
|
|
switch (Opts.FiniteLoops) {
|
|
|
|
case CodeGenOptions::FiniteLoopsKind::Language:
|
|
|
|
break;
|
|
|
|
case CodeGenOptions::FiniteLoopsKind::Always:
|
|
|
|
GenerateArg(Args, OPT_ffinite_loops, SA);
|
|
|
|
break;
|
|
|
|
case CodeGenOptions::FiniteLoopsKind::Never:
|
|
|
|
GenerateArg(Args, OPT_fno_finite_loops, SA);
|
|
|
|
break;
|
|
|
|
}
|
2021-02-09 11:42:01 +01:00
|
|
|
}
|
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
|
|
|
|
InputKind IK,
|
|
|
|
DiagnosticsEngine &Diags,
|
|
|
|
const llvm::Triple &T,
|
|
|
|
const std::string &OutputFile,
|
|
|
|
const LangOptions &LangOptsRef) {
|
2021-02-09 11:42:01 +01:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
|
|
|
|
2014-12-16 21:57:03 +00:00
|
|
|
unsigned OptimizationLevel = getOptimizationLevel(Args, IK, Diags);
|
2013-11-18 13:23:07 +00:00
|
|
|
// TODO: This could be done in Driver
|
|
|
|
unsigned MaxOptLevel = 3;
|
2014-12-16 21:57:03 +00:00
|
|
|
if (OptimizationLevel > MaxOptLevel) {
|
|
|
|
// If the optimization level is not supported, fall back on the default
|
|
|
|
// optimization
|
2013-11-18 13:23:07 +00:00
|
|
|
Diags.Report(diag::warn_drv_optimization_value)
|
|
|
|
<< Args.getLastArg(OPT_O)->getAsString(Args) << "-O" << MaxOptLevel;
|
2014-12-16 21:57:03 +00:00
|
|
|
OptimizationLevel = MaxOptLevel;
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
2014-12-16 21:57:03 +00:00
|
|
|
Opts.OptimizationLevel = OptimizationLevel;
|
2009-12-01 03:16:53 +00:00
|
|
|
|
2021-01-15 17:55:03 +01:00
|
|
|
// The key paths of codegen options defined in Options.td start with
|
|
|
|
// "CodeGenOpts.". Let's provide the expected variable name and type.
|
|
|
|
CodeGenOptions &CodeGenOpts = Opts;
|
|
|
|
// Some codegen options depend on language options. Let's provide the expected
|
|
|
|
// variable name and type.
|
|
|
|
const LangOptions *LangOpts = &LangOptsRef;
|
|
|
|
|
2021-01-28 10:48:26 +01:00
|
|
|
#define CODEGEN_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-01-15 17:55:03 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef CODEGEN_OPTION_WITH_MARSHALLING
|
|
|
|
|
Cleanup the handling of noinline function attributes, -fno-inline,
-fno-inline-functions, -O0, and optnone.
These were really, really tangled together:
- We used the noinline LLVM attribute for -fno-inline
- But not for -fno-inline-functions (breaking LTO)
- But we did use it for -finline-hint-functions (yay, LTO is happy!)
- But we didn't for -O0 (LTO is sad yet again...)
- We had weird structuring of CodeGenOpts with both an inlining
enumeration and a boolean. They interacted in weird ways and
needlessly.
- A *lot* of set smashing went on with setting these, and then got worse
when we considered optnone and other inlining-effecting attributes.
- A bunch of inline affecting attributes were managed in a completely
different place from -fno-inline.
- Even with -fno-inline we failed to put the LLVM noinline attribute
onto many generated function definitions because they didn't show up
as AST-level functions.
- If you passed -O0 but -finline-functions we would run the normal
inliner pass in LLVM despite it being in the O0 pipeline, which really
doesn't make much sense.
- Lastly, we used things like '-fno-inline' to manipulate the pass
pipeline which forced the pass pipeline to be much more
parameterizable than it really needs to be. Instead we can *just* use
the optimization level to select a pipeline and control the rest via
attributes.
Sadly, this causes a bunch of churn in tests because we don't run the
optimizer in the tests and check the contents of attribute sets. It
would be awesome if attribute sets were a bit more FileCheck friendly,
but oh well.
I think this is a significant improvement and should remove the semantic
need to change what inliner pass we run in order to comply with the
requested inlining semantics by relying completely on attributes. It
also cleans up tho optnone and related handling a bit.
One unfortunate aspect of this is that for generating alwaysinline
routines like those in OpenMP we end up removing noinline and then
adding alwaysinline. I tried a bunch of other approaches, but because we
recompute function attributes from scratch and don't have a declaration
here I couldn't find anything substantially cleaner than this.
Differential Revision: https://reviews.llvm.org/D28053
llvm-svn: 290398
2016-12-23 01:24:49 +00:00
|
|
|
// At O0 we want to fully disable inlining outside of cases marked with
|
|
|
|
// 'alwaysinline' that are required for correctness.
|
2022-04-10 00:31:25 -07:00
|
|
|
if (Opts.OptimizationLevel == 0) {
|
|
|
|
Opts.setInlining(CodeGenOptions::OnlyAlwaysInlining);
|
|
|
|
} else if (const Arg *A = Args.getLastArg(options::OPT_finline_functions,
|
|
|
|
options::OPT_finline_hint_functions,
|
|
|
|
options::OPT_fno_inline_functions,
|
|
|
|
options::OPT_fno_inline)) {
|
|
|
|
// Explicit inlining flags can disable some or all inlining even at
|
|
|
|
// optimization levels above zero.
|
|
|
|
if (A->getOption().matches(options::OPT_finline_functions))
|
|
|
|
Opts.setInlining(CodeGenOptions::NormalInlining);
|
|
|
|
else if (A->getOption().matches(options::OPT_finline_hint_functions))
|
|
|
|
Opts.setInlining(CodeGenOptions::OnlyHintInlining);
|
|
|
|
else
|
|
|
|
Opts.setInlining(CodeGenOptions::OnlyAlwaysInlining);
|
|
|
|
} else {
|
|
|
|
Opts.setInlining(CodeGenOptions::NormalInlining);
|
2016-05-24 20:40:51 +00:00
|
|
|
}
|
2009-12-01 03:16:53 +00:00
|
|
|
|
2021-01-09 00:29:09 -08:00
|
|
|
// PIC defaults to -fno-direct-access-external-data while non-PIC defaults to
|
|
|
|
// -fdirect-access-external-data.
|
|
|
|
Opts.DirectAccessExternalData =
|
|
|
|
Args.hasArg(OPT_fdirect_access_external_data) ||
|
|
|
|
(!Args.hasArg(OPT_fno_direct_access_external_data) &&
|
2021-02-09 11:42:01 +01:00
|
|
|
LangOpts->PICLevel == 0);
|
|
|
|
|
|
|
|
if (Arg *A = Args.getLastArg(OPT_debug_info_kind_EQ)) {
|
|
|
|
unsigned Val =
|
|
|
|
llvm::StringSwitch<unsigned>(A->getValue())
|
|
|
|
.Case("line-tables-only", codegenoptions::DebugLineTablesOnly)
|
|
|
|
.Case("line-directives-only", codegenoptions::DebugDirectivesOnly)
|
|
|
|
.Case("constructor", codegenoptions::DebugInfoConstructor)
|
|
|
|
.Case("limited", codegenoptions::LimitedDebugInfo)
|
|
|
|
.Case("standalone", codegenoptions::FullDebugInfo)
|
|
|
|
.Case("unused-types", codegenoptions::UnusedTypeInfo)
|
|
|
|
.Default(~0U);
|
|
|
|
if (Val == ~0U)
|
|
|
|
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
|
|
|
|
<< A->getValue();
|
|
|
|
else
|
|
|
|
Opts.setDebugInfo(static_cast<codegenoptions::DebugInfoKind>(Val));
|
|
|
|
}
|
2021-01-09 00:29:09 -08:00
|
|
|
|
2020-08-13 15:48:55 -07:00
|
|
|
// If -fuse-ctor-homing is set and limited debug info is already on, then use
|
2021-07-22 11:26:03 -07:00
|
|
|
// constructor homing, and vice versa for -fno-use-ctor-homing.
|
|
|
|
if (const Arg *A =
|
|
|
|
Args.getLastArg(OPT_fuse_ctor_homing, OPT_fno_use_ctor_homing)) {
|
|
|
|
if (A->getOption().matches(OPT_fuse_ctor_homing) &&
|
|
|
|
Opts.getDebugInfo() == codegenoptions::LimitedDebugInfo)
|
2020-08-13 15:48:55 -07:00
|
|
|
Opts.setDebugInfo(codegenoptions::DebugInfoConstructor);
|
2021-07-22 11:26:03 -07:00
|
|
|
if (A->getOption().matches(OPT_fno_use_ctor_homing) &&
|
|
|
|
Opts.getDebugInfo() == codegenoptions::DebugInfoConstructor)
|
|
|
|
Opts.setDebugInfo(codegenoptions::LimitedDebugInfo);
|
|
|
|
}
|
2020-08-13 15:48:55 -07:00
|
|
|
|
2020-01-29 00:42:56 +01:00
|
|
|
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
|
|
|
|
auto Split = StringRef(Arg).split('=');
|
|
|
|
Opts.DebugPrefixMap.insert(
|
|
|
|
{std::string(Split.first), std::string(Split.second)});
|
|
|
|
}
|
2015-10-12 20:21:08 +00:00
|
|
|
|
2021-02-24 19:04:36 -08:00
|
|
|
for (const auto &Arg : Args.getAllArgValues(OPT_fcoverage_prefix_map_EQ)) {
|
2021-01-25 10:03:07 -08:00
|
|
|
auto Split = StringRef(Arg).split('=');
|
2021-02-24 19:04:36 -08:00
|
|
|
Opts.CoveragePrefixMap.insert(
|
2021-01-25 10:03:07 -08:00
|
|
|
{std::string(Split.first), std::string(Split.second)});
|
|
|
|
}
|
|
|
|
|
2020-02-20 13:43:01 +01:00
|
|
|
const llvm::Triple::ArchType DebugEntryValueArchs[] = {
|
|
|
|
llvm::Triple::x86, llvm::Triple::x86_64, llvm::Triple::aarch64,
|
2020-05-15 09:24:02 +02:00
|
|
|
llvm::Triple::arm, llvm::Triple::armeb, llvm::Triple::mips,
|
|
|
|
llvm::Triple::mipsel, llvm::Triple::mips64, llvm::Triple::mips64el};
|
2020-02-20 13:43:01 +01:00
|
|
|
|
|
|
|
if (Opts.OptimizationLevel > 0 && Opts.hasReducedDebugInfo() &&
|
2020-03-19 12:13:18 +01:00
|
|
|
llvm::is_contained(DebugEntryValueArchs, T.getArch()))
|
2020-03-09 11:02:35 +01:00
|
|
|
Opts.EmitCallSiteInfo = true;
|
2020-02-20 13:43:01 +01:00
|
|
|
|
2021-03-11 06:55:13 -08:00
|
|
|
if (!Opts.EnableDIPreservationVerify && Opts.DIBugsReportFilePath.size()) {
|
|
|
|
Diags.Report(diag::warn_ignoring_verify_debuginfo_preserve_export)
|
|
|
|
<< Opts.DIBugsReportFilePath;
|
|
|
|
Opts.DIBugsReportFilePath = "";
|
|
|
|
}
|
|
|
|
|
2017-11-20 11:16:16 +00:00
|
|
|
Opts.NewStructPathTBAA = !Args.hasArg(OPT_no_struct_path_tbaa) &&
|
|
|
|
Args.hasArg(OPT_new_struct_path_tbaa);
|
2013-04-10 21:30:03 +00:00
|
|
|
Opts.OptimizeSize = getOptimizationLevelSize(Args);
|
2021-02-09 11:42:01 +01:00
|
|
|
Opts.SimplifyLibCalls = !LangOpts->NoBuiltin;
|
2016-01-06 14:35:46 +00:00
|
|
|
if (Opts.SimplifyLibCalls)
|
2021-02-09 11:42:01 +01:00
|
|
|
Opts.NoBuiltinFuncs = LangOpts->NoBuiltinFuncs;
|
2013-08-08 08:34:35 +00:00
|
|
|
Opts.UnrollLoops =
|
|
|
|
Args.hasFlag(OPT_funroll_loops, OPT_fno_unroll_loops,
|
2016-05-04 15:26:28 +00:00
|
|
|
(Opts.OptimizationLevel > 1));
|
Add -fbinutils-version= to gate ELF features on the specified binutils version
There are two use cases.
Assembler
We have accrued some code gated on MCAsmInfo::useIntegratedAssembler(). Some
features are supported by latest GNU as, but we have to use
MCAsmInfo::useIntegratedAs() because the newer versions have not been widely
adopted (e.g. SHF_LINK_ORDER 'o' and 'unique' linkage in 2.35, --compress-debug-sections= in 2.26).
Linker
We want to use features supported only by LLD or very new GNU ld, or don't want
to work around older GNU ld. We currently can't represent that "we don't care
about old GNU ld". You can find such workarounds in a few other places, e.g.
Mips/MipsAsmprinter.cpp PowerPC/PPCTOCRegDeps.cpp X86/X86MCInstrLower.cpp
AArch64 TLS workaround for R_AARCH64_TLSLD_MOVW_DTPREL_* (PR ld/18276),
R_AARCH64_TLSLE_LDST8_TPREL_LO12 (https://bugs.llvm.org/show_bug.cgi?id=36727 https://sourceware.org/bugzilla/show_bug.cgi?id=22969)
Mixed SHF_LINK_ORDER and non-SHF_LINK_ORDER components (supported by LLD in D84001;
GNU ld feature request https://sourceware.org/bugzilla/show_bug.cgi?id=16833 may take a while before available).
This feature allows to garbage collect some unused sections (e.g. fragmented .gcc_except_table).
This patch adds `-fbinutils-version=` to clang and `-binutils-version` to llc.
It changes one codegen place in SHF_MERGE to demonstrate its usage.
`-fbinutils-version=2.35` means the produced object file does not care about GNU
ld<2.35 compatibility. When `-fno-integrated-as` is specified, the produced
assembly can be consumed by GNU as>=2.35, but older versions may not work.
`-fbinutils-version=none` means that we can use all ELF features, regardless of
GNU as/ld support.
Both clang and llc need `parseBinutilsVersion`. Such command line parsing is
usually implemented in `llvm/lib/CodeGen/CommandFlags.cpp` (LLVMCodeGen),
however, ClangCodeGen does not depend on LLVMCodeGen. So I add
`parseBinutilsVersion` to `llvm/lib/Target/TargetMachine.cpp` (LLVMTarget).
Differential Revision: https://reviews.llvm.org/D85474
2021-01-26 12:28:23 -08:00
|
|
|
Opts.BinutilsVersion =
|
|
|
|
std::string(Args.getLastArgValue(OPT_fbinutils_version_EQ));
|
|
|
|
|
2018-08-20 20:14:08 +00:00
|
|
|
Opts.DebugNameTable = static_cast<unsigned>(
|
|
|
|
Args.hasArg(OPT_ggnu_pubnames)
|
|
|
|
? llvm::DICompileUnit::DebugNameTableKind::GNU
|
|
|
|
: Args.hasArg(OPT_gpubnames)
|
|
|
|
? llvm::DICompileUnit::DebugNameTableKind::Default
|
|
|
|
: llvm::DICompileUnit::DebugNameTableKind::None);
|
2021-09-21 20:25:13 -07:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_gsimple_template_names_EQ)) {
|
2021-09-24 11:15:53 -07:00
|
|
|
StringRef Value = A->getValue();
|
|
|
|
if (Value != "simple" && Value != "mangled")
|
|
|
|
Diags.Report(diag::err_drv_unsupported_option_argument)
|
|
|
|
<< A->getOption().getName() << A->getValue();
|
2021-09-21 20:25:13 -07:00
|
|
|
Opts.setDebugSimpleTemplateNames(
|
|
|
|
StringRef(A->getValue()) == "simple"
|
|
|
|
? codegenoptions::DebugTemplateNamesKind::Simple
|
|
|
|
: codegenoptions::DebugTemplateNamesKind::Mangled);
|
|
|
|
}
|
2021-01-05 17:00:46 +01:00
|
|
|
|
2016-03-02 20:59:36 +00:00
|
|
|
if (!Opts.ProfileInstrumentUsePath.empty())
|
|
|
|
setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath);
|
2016-02-04 18:39:09 +00:00
|
|
|
|
2020-12-02 10:18:18 -08:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ)) {
|
|
|
|
Opts.TimePasses = true;
|
|
|
|
|
|
|
|
// -ftime-report= is only for new pass manager.
|
|
|
|
if (A->getOption().getID() == OPT_ftime_report_EQ) {
|
|
|
|
StringRef Val = A->getValue();
|
|
|
|
if (Val == "per-pass")
|
|
|
|
Opts.TimePassesPerRun = false;
|
|
|
|
else if (Val == "per-pass-run")
|
|
|
|
Opts.TimePassesPerRun = true;
|
|
|
|
else
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << A->getValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-08 15:52:19 -07:00
|
|
|
Opts.PrepareForLTO = false;
|
2018-06-22 20:23:21 +00:00
|
|
|
Opts.PrepareForThinLTO = false;
|
2017-06-14 15:37:11 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_flto_EQ)) {
|
2021-09-08 15:52:19 -07:00
|
|
|
Opts.PrepareForLTO = true;
|
2017-06-14 15:37:11 +00:00
|
|
|
StringRef S = A->getValue();
|
|
|
|
if (S == "thin")
|
2018-06-22 20:23:21 +00:00
|
|
|
Opts.PrepareForThinLTO = true;
|
2017-06-14 15:37:11 +00:00
|
|
|
else if (S != "full")
|
|
|
|
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
|
|
|
|
}
|
2015-12-07 19:21:34 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) {
|
2019-08-05 13:59:26 +00:00
|
|
|
if (IK.getLanguage() != Language::LLVM_IR)
|
2015-12-07 19:21:34 +00:00
|
|
|
Diags.Report(diag::err_drv_argument_only_allowed_with)
|
|
|
|
<< A->getAsString(Args) << "-x ir";
|
2020-01-28 20:23:46 +01:00
|
|
|
Opts.ThinLTOIndexFile =
|
|
|
|
std::string(Args.getLastArgValue(OPT_fthinlto_index_EQ));
|
2015-12-07 19:21:34 +00:00
|
|
|
}
|
2018-04-17 16:39:25 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_save_temps_EQ))
|
|
|
|
Opts.SaveTempsFilePrefix =
|
|
|
|
llvm::StringSwitch<std::string>(A->getValue())
|
2021-01-14 08:34:17 +01:00
|
|
|
.Case("obj", OutputFile)
|
|
|
|
.Default(llvm::sys::path::filename(OutputFile).str());
|
2018-04-17 16:39:25 +00:00
|
|
|
|
2020-09-29 15:53:41 -07:00
|
|
|
// The memory profile runtime appends the pid to make this name more unique.
|
|
|
|
const char *MemProfileBasename = "memprof.profraw";
|
|
|
|
if (Args.hasArg(OPT_fmemory_profile_EQ)) {
|
|
|
|
SmallString<128> Path(
|
|
|
|
std::string(Args.getLastArgValue(OPT_fmemory_profile_EQ)));
|
|
|
|
llvm::sys::path::append(Path, MemProfileBasename);
|
|
|
|
Opts.MemoryProfileOutput = std::string(Path);
|
|
|
|
} else if (Args.hasArg(OPT_fmemory_profile))
|
|
|
|
Opts.MemoryProfileOutput = MemProfileBasename;
|
2020-08-13 16:29:38 -07:00
|
|
|
|
2021-02-09 11:42:01 +01:00
|
|
|
memcpy(Opts.CoverageVersion, "408*", 4);
|
2013-03-07 08:28:53 +00:00
|
|
|
if (Opts.EmitGcovArcs || Opts.EmitGcovNotes) {
|
|
|
|
if (Args.hasArg(OPT_coverage_version_EQ)) {
|
|
|
|
StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ);
|
|
|
|
if (CoverageVersion.size() != 4) {
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< Args.getLastArg(OPT_coverage_version_EQ)->getAsString(Args)
|
|
|
|
<< CoverageVersion;
|
|
|
|
} else {
|
2013-03-14 05:14:01 +00:00
|
|
|
memcpy(Opts.CoverageVersion, CoverageVersion.data(), 4);
|
2013-03-07 08:28:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-11 16:26:03 +00:00
|
|
|
// FIXME: For backend options that are not yet recorded as function
|
|
|
|
// attributes in the IR, keep track of them so we can embed them in a
|
|
|
|
// separate data section and use them when building the bitcode.
|
2020-10-28 20:16:51 -07:00
|
|
|
for (const auto &A : Args) {
|
|
|
|
// Do not encode output and input.
|
|
|
|
if (A->getOption().getID() == options::OPT_o ||
|
|
|
|
A->getOption().getID() == options::OPT_INPUT ||
|
|
|
|
A->getOption().getID() == options::OPT_x ||
|
|
|
|
A->getOption().getID() == options::OPT_fembed_bitcode ||
|
|
|
|
A->getOption().matches(options::OPT_W_Group))
|
|
|
|
continue;
|
|
|
|
ArgStringList ASL;
|
|
|
|
A->render(Args, ASL);
|
|
|
|
for (const auto &arg : ASL) {
|
|
|
|
StringRef ArgStr(arg);
|
|
|
|
Opts.CmdArgs.insert(Opts.CmdArgs.end(), ArgStr.begin(), ArgStr.end());
|
|
|
|
// using \00 to separate each commandline options.
|
|
|
|
Opts.CmdArgs.push_back('\0');
|
2016-05-11 16:26:03 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-07 08:28:53 +00:00
|
|
|
|
2018-04-13 02:31:58 +00:00
|
|
|
auto XRayInstrBundles =
|
|
|
|
Args.getAllArgValues(OPT_fxray_instrumentation_bundle);
|
|
|
|
if (XRayInstrBundles.empty())
|
|
|
|
Opts.XRayInstrumentationBundle.Mask = XRayInstrKind::All;
|
|
|
|
else
|
|
|
|
for (const auto &A : XRayInstrBundles)
|
|
|
|
parseXRayInstrumentationBundle("-fxray-instrumentation-bundle=", A, Args,
|
|
|
|
Diags, Opts.XRayInstrumentationBundle);
|
|
|
|
|
2018-01-09 08:53:59 +00:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) {
|
|
|
|
StringRef Name = A->getValue();
|
|
|
|
if (Name == "full") {
|
|
|
|
Opts.CFProtectionReturn = 1;
|
|
|
|
Opts.CFProtectionBranch = 1;
|
|
|
|
} else if (Name == "return")
|
|
|
|
Opts.CFProtectionReturn = 1;
|
|
|
|
else if (Name == "branch")
|
|
|
|
Opts.CFProtectionBranch = 1;
|
2021-04-16 15:30:28 +02:00
|
|
|
else if (Name != "none")
|
2018-01-09 08:53:59 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
|
|
|
|
}
|
|
|
|
|
[X86] Enable ibt-seal optimization when LTO is used in Kernel
Intel's CET/IBT requires every indirect branch target to be an ENDBR instruction. Because of that, the compiler needs to correctly emit these instruction on function's prologues. Because this is a security feature, it is desirable that only actual indirect-branch-targeted functions are emitted with ENDBRs. While it is possible to identify address-taken functions through LTO, minimizing these ENDBR instructions remains a hard task for user-space binaries because exported functions may end being reachable through PLT entries, that will use an indirect branch for such. Because this cannot be determined during compilation-time, the compiler currently emits ENDBRs to every non-local-linkage function.
Despite the challenge presented for user-space, the kernel landscape is different as no PLTs are used. With the intent of providing the most fit ENDBR emission for the kernel, kernel developers proposed an optimization named "ibt-seal" which replaces the ENDBRs for NOPs directly in the binary. The discussion of this feature can be seen in [1].
This diff brings the enablement of the flag -mibt-seal, which in combination with LTO enforces a different policy for ENDBR placement in when the code-model is set to "kernel". In this scenario, the compiler will only emit ENDBRs to address taken functions, ignoring non-address taken functions that are don't have local linkage.
A comparison between an LTO-compiled kernel binaries without and with the -mibt-seal feature enabled shows that when -mibt-seal was used, the number of ENDBRs in the vmlinux.o binary patched by objtool decreased from 44383 to 33192, and that the number of superfluous ENDBR instructions nopped-out decreased from 11730 to 540.
The 540 missed superfluous ENDBRs need to be investigated further, but hypotheses are: assembly code not being taken care of by the compiler, kernel exported symbols mechanisms creating bogus address taken situations or even these being removed due to other binary optimizations like kernel's static_calls. For now, I assume that the large drop in the number of ENDBR instructions already justifies the feature being merged.
[1] - https://lkml.org/lkml/2021/11/22/591
Reviewed By: xiangzhangllvm
Differential Revision: https://reviews.llvm.org/D116070
2022-01-21 09:31:21 +08:00
|
|
|
if (Opts.PrepareForLTO && Args.hasArg(OPT_mibt_seal))
|
|
|
|
Opts.IBTSeal = 1;
|
|
|
|
|
2018-03-26 21:45:04 +00:00
|
|
|
for (auto *A :
|
2018-08-20 18:16:48 +00:00
|
|
|
Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_builtin_bitcode)) {
|
[CodeGen] [CUDA] Add the ability set default attrs on functions in linked modules.
Summary:
Now when you ask clang to link in a bitcode module, you can tell it to
set attributes on that module's functions to match what we would have
set if we'd emitted those functions ourselves.
This is particularly important for fast-math attributes in CUDA
compilations.
Each CUDA compilation links in libdevice, a bitcode library provided by
nvidia as part of the CUDA distribution. Without this patch, if we have
a user-function F that is compiled with -ffast-math that calls a
function G from libdevice, F will have the unsafe-fp-math=true (etc.)
attributes, but G will have no attributes.
Since F calls G, the inliner will merge G's attributes into F's. It
considers the lack of an unsafe-fp-math=true attribute on G to be
tantamount to unsafe-fp-math=false, so it "merges" these by setting
unsafe-fp-math=false on F.
This then continues up the call graph, until every function that
(transitively) calls something in libdevice gets unsafe-fp-math=false
set, thus disabling fastmath in almost all CUDA code.
Reviewers: echristo
Subscribers: hfinkel, llvm-commits, mehdi_amini
Differential Revision: https://reviews.llvm.org/D28538
llvm-svn: 293097
2017-01-25 21:29:48 +00:00
|
|
|
CodeGenOptions::BitcodeFileToLink F;
|
|
|
|
F.Filename = A->getValue();
|
2018-08-20 18:16:48 +00:00
|
|
|
if (A->getOption().matches(OPT_mlink_builtin_bitcode)) {
|
2017-03-13 18:08:11 +00:00
|
|
|
F.LinkFlags = llvm::Linker::Flags::LinkOnlyNeeded;
|
[CodeGen] [CUDA] Add the ability set default attrs on functions in linked modules.
Summary:
Now when you ask clang to link in a bitcode module, you can tell it to
set attributes on that module's functions to match what we would have
set if we'd emitted those functions ourselves.
This is particularly important for fast-math attributes in CUDA
compilations.
Each CUDA compilation links in libdevice, a bitcode library provided by
nvidia as part of the CUDA distribution. Without this patch, if we have
a user-function F that is compiled with -ffast-math that calls a
function G from libdevice, F will have the unsafe-fp-math=true (etc.)
attributes, but G will have no attributes.
Since F calls G, the inliner will merge G's attributes into F's. It
considers the lack of an unsafe-fp-math=true attribute on G to be
tantamount to unsafe-fp-math=false, so it "merges" these by setting
unsafe-fp-math=false on F.
This then continues up the call graph, until every function that
(transitively) calls something in libdevice gets unsafe-fp-math=false
set, thus disabling fastmath in almost all CUDA code.
Reviewers: echristo
Subscribers: hfinkel, llvm-commits, mehdi_amini
Differential Revision: https://reviews.llvm.org/D28538
llvm-svn: 293097
2017-01-25 21:29:48 +00:00
|
|
|
// When linking CUDA bitcode, propagate function attributes so that
|
|
|
|
// e.g. libdevice gets fast-math attrs if we're building with fast-math.
|
|
|
|
F.PropagateAttrs = true;
|
2017-03-13 18:08:11 +00:00
|
|
|
F.Internalize = true;
|
[CodeGen] [CUDA] Add the ability set default attrs on functions in linked modules.
Summary:
Now when you ask clang to link in a bitcode module, you can tell it to
set attributes on that module's functions to match what we would have
set if we'd emitted those functions ourselves.
This is particularly important for fast-math attributes in CUDA
compilations.
Each CUDA compilation links in libdevice, a bitcode library provided by
nvidia as part of the CUDA distribution. Without this patch, if we have
a user-function F that is compiled with -ffast-math that calls a
function G from libdevice, F will have the unsafe-fp-math=true (etc.)
attributes, but G will have no attributes.
Since F calls G, the inliner will merge G's attributes into F's. It
considers the lack of an unsafe-fp-math=true attribute on G to be
tantamount to unsafe-fp-math=false, so it "merges" these by setting
unsafe-fp-math=false on F.
This then continues up the call graph, until every function that
(transitively) calls something in libdevice gets unsafe-fp-math=false
set, thus disabling fastmath in almost all CUDA code.
Reviewers: echristo
Subscribers: hfinkel, llvm-commits, mehdi_amini
Differential Revision: https://reviews.llvm.org/D28538
llvm-svn: 293097
2017-01-25 21:29:48 +00:00
|
|
|
}
|
|
|
|
Opts.LinkBitcodeFiles.push_back(F);
|
2015-10-27 17:56:59 +00:00
|
|
|
}
|
2020-10-22 09:46:42 +08:00
|
|
|
|
2018-03-01 22:26:19 +00:00
|
|
|
if (Args.getLastArg(OPT_femulated_tls) ||
|
|
|
|
Args.getLastArg(OPT_fno_emulated_tls)) {
|
|
|
|
Opts.ExplicitEmulatedTLS = true;
|
|
|
|
}
|
2015-07-28 16:27:56 +00:00
|
|
|
|
2021-05-11 16:35:13 -05:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) {
|
|
|
|
if (T.isOSAIX()) {
|
|
|
|
StringRef Name = A->getValue();
|
|
|
|
if (Name != "global-dynamic")
|
|
|
|
Diags.Report(diag::err_aix_unsupported_tls_model) << Name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-30 08:09:45 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_EQ)) {
|
|
|
|
StringRef Val = A->getValue();
|
2019-10-29 16:16:05 -07:00
|
|
|
Opts.FPDenormalMode = llvm::parseDenormalFPAttribute(Val);
|
Additionally set f32 mode with denormal-fp-math
When the denormal-fp-math option is used, this should set the
denormal handling mode for all floating point types. However,
currently 32-bit float types can ignore this setting as there is a
variant of the option, denormal-fp-math-f32, specifically for that type
which takes priority when checking the mode based on type and remains
at the default of IEEE. From the description, denormal-fp-math would
be expected to set the mode for floats unless overridden by the f32
variant, and code in the front end only emits the f32 option if it is
different to the general one, so setting just denormal-fp-math should
be valid.
This patch changes the denormal-fp-math option to also set the f32
mode. If denormal-fp-math-f32 is also specified, this is then
overridden as expected, but if it is absent floats will be set to the
mode specified by the former option, rather than remain on the default.
Reviewed By: arsenm
Differential Revision: https://reviews.llvm.org/D122589
2022-04-29 15:06:12 +01:00
|
|
|
Opts.FP32DenormalMode = Opts.FPDenormalMode;
|
2019-11-06 17:10:52 -08:00
|
|
|
if (!Opts.FPDenormalMode.isValid())
|
2016-08-30 08:09:45 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
|
|
|
|
}
|
|
|
|
|
Consolidate internal denormal flushing controls
Currently there are 4 different mechanisms for controlling denormal
flushing behavior, and about as many equivalent frontend controls.
- AMDGPU uses the fp32-denormals and fp64-f16-denormals subtarget features
- NVPTX uses the nvptx-f32ftz attribute
- ARM directly uses the denormal-fp-math attribute
- Other targets indirectly use denormal-fp-math in one DAGCombine
- cl-denorms-are-zero has a corresponding denorms-are-zero attribute
AMDGPU wants a distinct control for f32 flushing from f16/f64, and as
far as I can tell the same is true for NVPTX (based on the attribute
name).
Work on consolidating these into the denormal-fp-math attribute, and a
new type specific denormal-fp-math-f32 variant. Only ARM seems to
support the two different flush modes, so this is overkill for the
other use cases. Ideally we would error on the unsupported
positive-zero mode on other targets from somewhere.
Move the logic for selecting the flush mode into the compiler driver,
instead of handling it in cc1. denormal-fp-math/denormal-fp-math-f32
are now both cc1 flags, but denormal-fp-math-f32 is not yet exposed as
a user flag.
-cl-denorms-are-zero, -fcuda-flush-denormals-to-zero and
-fno-cuda-flush-denormals-to-zero will be mapped to
-fp-denormal-math-f32=ieee or preserve-sign rather than the old
attributes.
Stop emitting the denorms-are-zero attribute for the OpenCL flag. It
has no in-tree users. The meaning would also be target dependent, such
as the AMDGPU choice to treat this as only meaning allow flushing of
f32 and not f16 or f64. The naming is also potentially confusing,
since DAZ in other contexts refers to instructions implicitly treating
input denormals as zero, not necessarily flushing output denormals to
zero.
This also does not attempt to change the behavior for the current
attribute. The LangRef now states that the default is ieee behavior,
but this is inaccurate for the current implementation. The clang
handling is slightly hacky to avoid touching the existing
denormal-fp-math uses. Fixing this will be left for a future patch.
AMDGPU is still using the subtarget feature to control the denormal
mode, but the new attribute are now emitted. A future change will
switch this and remove the subtarget features.
2019-11-01 17:57:29 -07:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_f32_EQ)) {
|
|
|
|
StringRef Val = A->getValue();
|
|
|
|
Opts.FP32DenormalMode = llvm::parseDenormalFPAttribute(Val);
|
2019-11-06 17:10:52 -08:00
|
|
|
if (!Opts.FP32DenormalMode.isValid())
|
Consolidate internal denormal flushing controls
Currently there are 4 different mechanisms for controlling denormal
flushing behavior, and about as many equivalent frontend controls.
- AMDGPU uses the fp32-denormals and fp64-f16-denormals subtarget features
- NVPTX uses the nvptx-f32ftz attribute
- ARM directly uses the denormal-fp-math attribute
- Other targets indirectly use denormal-fp-math in one DAGCombine
- cl-denorms-are-zero has a corresponding denorms-are-zero attribute
AMDGPU wants a distinct control for f32 flushing from f16/f64, and as
far as I can tell the same is true for NVPTX (based on the attribute
name).
Work on consolidating these into the denormal-fp-math attribute, and a
new type specific denormal-fp-math-f32 variant. Only ARM seems to
support the two different flush modes, so this is overkill for the
other use cases. Ideally we would error on the unsupported
positive-zero mode on other targets from somewhere.
Move the logic for selecting the flush mode into the compiler driver,
instead of handling it in cc1. denormal-fp-math/denormal-fp-math-f32
are now both cc1 flags, but denormal-fp-math-f32 is not yet exposed as
a user flag.
-cl-denorms-are-zero, -fcuda-flush-denormals-to-zero and
-fno-cuda-flush-denormals-to-zero will be mapped to
-fp-denormal-math-f32=ieee or preserve-sign rather than the old
attributes.
Stop emitting the denorms-are-zero attribute for the OpenCL flag. It
has no in-tree users. The meaning would also be target dependent, such
as the AMDGPU choice to treat this as only meaning allow flushing of
f32 and not f16 or f64. The naming is also potentially confusing,
since DAZ in other contexts refers to instructions implicitly treating
input denormals as zero, not necessarily flushing output denormals to
zero.
This also does not attempt to change the behavior for the current
attribute. The LangRef now states that the default is ieee behavior,
but this is inaccurate for the current implementation. The clang
handling is slightly hacky to avoid touching the existing
denormal-fp-math uses. Fixing this will be left for a future patch.
AMDGPU is still using the subtarget feature to control the denormal
mode, but the new attribute are now emitted. A future change will
switch this and remove the subtarget features.
2019-11-01 17:57:29 -07:00
|
|
|
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
|
|
|
|
}
|
|
|
|
|
2020-04-21 15:36:08 -05:00
|
|
|
// X86_32 has -fppc-struct-return and -freg-struct-return.
|
|
|
|
// PPC32 has -maix-struct-return and -msvr4-struct-return.
|
|
|
|
if (Arg *A =
|
|
|
|
Args.getLastArg(OPT_fpcc_struct_return, OPT_freg_struct_return,
|
|
|
|
OPT_maix_struct_return, OPT_msvr4_struct_return)) {
|
2020-05-19 14:56:56 +00:00
|
|
|
// TODO: We might want to consider enabling these options on AIX in the
|
|
|
|
// future.
|
|
|
|
if (T.isOSAIX())
|
|
|
|
Diags.Report(diag::err_drv_unsupported_opt_for_target)
|
|
|
|
<< A->getSpelling() << T.str();
|
|
|
|
|
2020-04-21 15:36:08 -05:00
|
|
|
const Option &O = A->getOption();
|
|
|
|
if (O.matches(OPT_fpcc_struct_return) ||
|
|
|
|
O.matches(OPT_maix_struct_return)) {
|
2013-06-18 02:46:29 +00:00
|
|
|
Opts.setStructReturnConvention(CodeGenOptions::SRCK_OnStack);
|
|
|
|
} else {
|
2020-04-21 15:36:08 -05:00
|
|
|
assert(O.matches(OPT_freg_struct_return) ||
|
|
|
|
O.matches(OPT_msvr4_struct_return));
|
2013-06-18 02:46:29 +00:00
|
|
|
Opts.setStructReturnConvention(CodeGenOptions::SRCK_InRegs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-24 18:11:46 -05:00
|
|
|
if (Arg *A =
|
|
|
|
Args.getLastArg(OPT_mabi_EQ_vec_default, OPT_mabi_EQ_vec_extabi)) {
|
|
|
|
if (!T.isOSAIX())
|
|
|
|
Diags.Report(diag::err_drv_unsupported_opt_for_target)
|
|
|
|
<< A->getSpelling() << T.str();
|
|
|
|
|
|
|
|
const Option &O = A->getOption();
|
2021-06-23 07:14:24 -04:00
|
|
|
Opts.EnableAIXExtendedAltivecABI = O.matches(OPT_mabi_EQ_vec_extabi);
|
2020-11-24 18:11:46 -05:00
|
|
|
}
|
|
|
|
|
2014-06-24 17:02:17 +00:00
|
|
|
bool NeedLocTracking = false;
|
2013-08-08 00:17:41 +00:00
|
|
|
|
2016-10-11 00:26:09 +00:00
|
|
|
if (!Opts.OptRecordFile.empty())
|
|
|
|
NeedLocTracking = true;
|
|
|
|
|
2019-03-12 21:22:27 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_opt_record_passes)) {
|
|
|
|
Opts.OptRecordPasses = A->getValue();
|
|
|
|
NeedLocTracking = true;
|
|
|
|
}
|
|
|
|
|
2019-06-17 16:06:00 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_opt_record_format)) {
|
|
|
|
Opts.OptRecordFormat = A->getValue();
|
|
|
|
NeedLocTracking = true;
|
|
|
|
}
|
|
|
|
|
2021-02-25 09:05:08 +01:00
|
|
|
Opts.OptimizationRemark =
|
|
|
|
ParseOptimizationRemark(Diags, Args, OPT_Rpass_EQ, "pass");
|
2014-05-29 19:55:06 +00:00
|
|
|
|
2021-02-25 09:05:08 +01:00
|
|
|
Opts.OptimizationRemarkMissed =
|
|
|
|
ParseOptimizationRemark(Diags, Args, OPT_Rpass_missed_EQ, "pass-missed");
|
2014-05-29 19:55:06 +00:00
|
|
|
|
2021-02-25 09:05:08 +01:00
|
|
|
Opts.OptimizationRemarkAnalysis = ParseOptimizationRemark(
|
|
|
|
Diags, Args, OPT_Rpass_analysis_EQ, "pass-analysis");
|
|
|
|
|
|
|
|
NeedLocTracking |= Opts.OptimizationRemark.hasValidPattern() ||
|
|
|
|
Opts.OptimizationRemarkMissed.hasValidPattern() ||
|
|
|
|
Opts.OptimizationRemarkAnalysis.hasValidPattern();
|
2014-06-24 17:02:17 +00:00
|
|
|
|
2017-06-23 02:38:45 +00:00
|
|
|
bool UsingSampleProfile = !Opts.SampleProfileFile.empty();
|
2017-07-01 05:45:26 +00:00
|
|
|
bool UsingProfile = UsingSampleProfile ||
|
|
|
|
(Opts.getProfileUse() != CodeGenOptions::ProfileNone);
|
|
|
|
|
2018-05-05 14:37:29 +00:00
|
|
|
if (Opts.DiagnosticsWithHotness && !UsingProfile &&
|
|
|
|
// An IR file will contain PGO as metadata
|
2019-08-05 13:59:26 +00:00
|
|
|
IK.getLanguage() != Language::LLVM_IR)
|
2017-07-01 05:45:26 +00:00
|
|
|
Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
|
|
|
|
<< "-fdiagnostics-show-hotness";
|
|
|
|
|
2020-11-17 10:43:02 -08:00
|
|
|
// Parse remarks hotness threshold. Valid value is either integer or 'auto'.
|
|
|
|
if (auto *arg =
|
|
|
|
Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) {
|
|
|
|
auto ResultOrErr =
|
|
|
|
llvm::remarks::parseHotnessThresholdOption(arg->getValue());
|
|
|
|
|
|
|
|
if (!ResultOrErr) {
|
|
|
|
Diags.Report(diag::err_drv_invalid_diagnotics_hotness_threshold)
|
|
|
|
<< "-fdiagnostics-hotness-threshold=";
|
|
|
|
} else {
|
|
|
|
Opts.DiagnosticsHotnessThreshold = *ResultOrErr;
|
|
|
|
if ((!Opts.DiagnosticsHotnessThreshold.hasValue() ||
|
|
|
|
Opts.DiagnosticsHotnessThreshold.getValue() > 0) &&
|
|
|
|
!UsingProfile)
|
|
|
|
Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
|
|
|
|
<< "-fdiagnostics-hotness-threshold=";
|
|
|
|
}
|
|
|
|
}
|
2016-09-13 04:32:40 +00:00
|
|
|
|
2022-04-01 22:03:48 +00:00
|
|
|
if (auto *arg =
|
|
|
|
Args.getLastArg(options::OPT_fdiagnostics_misexpect_tolerance_EQ)) {
|
|
|
|
auto ResultOrErr = parseToleranceOption(arg->getValue());
|
|
|
|
|
|
|
|
if (!ResultOrErr) {
|
|
|
|
Diags.Report(diag::err_drv_invalid_diagnotics_misexpect_tolerance)
|
|
|
|
<< "-fdiagnostics-misexpect-tolerance=";
|
|
|
|
} else {
|
|
|
|
Opts.DiagnosticsMisExpectTolerance = *ResultOrErr;
|
|
|
|
if ((!Opts.DiagnosticsMisExpectTolerance.hasValue() ||
|
|
|
|
Opts.DiagnosticsMisExpectTolerance.getValue() > 0) &&
|
|
|
|
!UsingProfile)
|
|
|
|
Diags.Report(diag::warn_drv_diagnostics_misexpect_requires_pgo)
|
|
|
|
<< "-fdiagnostics-misexpect-tolerance=";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-22 13:00:05 +00:00
|
|
|
// If the user requested to use a sample profile for PGO, then the
|
|
|
|
// backend will need to track source location information so the profile
|
|
|
|
// can be incorporated into the IR.
|
2017-06-23 02:38:45 +00:00
|
|
|
if (UsingSampleProfile)
|
2014-10-22 13:00:05 +00:00
|
|
|
NeedLocTracking = true;
|
|
|
|
|
2021-04-14 13:54:47 -07:00
|
|
|
if (!Opts.StackUsageOutput.empty())
|
|
|
|
NeedLocTracking = true;
|
|
|
|
|
2014-10-22 13:00:05 +00:00
|
|
|
// If the user requested a flag that requires source locations available in
|
|
|
|
// the backend, make sure that the backend tracks source location information.
|
2016-02-02 11:06:51 +00:00
|
|
|
if (NeedLocTracking && Opts.getDebugInfo() == codegenoptions::NoDebugInfo)
|
|
|
|
Opts.setDebugInfo(codegenoptions::LocTrackingOnly);
|
2014-05-29 19:55:06 +00:00
|
|
|
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-12 22:39:12 +00:00
|
|
|
// Parse -fsanitize-recover= arguments.
|
|
|
|
// FIXME: Report unrecoverable sanitizers incorrectly specified here.
|
|
|
|
parseSanitizerKinds("-fsanitize-recover=",
|
|
|
|
Args.getAllArgValues(OPT_fsanitize_recover_EQ), Diags,
|
|
|
|
Opts.SanitizeRecover);
|
2015-06-18 23:59:22 +00:00
|
|
|
parseSanitizerKinds("-fsanitize-trap=",
|
|
|
|
Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags,
|
|
|
|
Opts.SanitizeTrap);
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-12 22:39:12 +00:00
|
|
|
|
2018-04-23 10:08:46 +00:00
|
|
|
Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
|
|
|
|
|
2021-02-12 17:45:18 +00:00
|
|
|
if (Args.hasArg(options::OPT_ffinite_loops))
|
|
|
|
Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Always;
|
|
|
|
else if (Args.hasArg(options::OPT_fno_finite_loops))
|
|
|
|
Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Never;
|
|
|
|
|
2022-03-26 00:57:06 -07:00
|
|
|
Opts.EmitIEEENaNCompliantInsts = Args.hasFlag(
|
|
|
|
options::OPT_mamdgpu_ieee, options::OPT_mno_amdgpu_ieee, true);
|
2020-03-29 10:32:03 -04:00
|
|
|
if (!Opts.EmitIEEENaNCompliantInsts && !LangOptsRef.NoHonorNaNs)
|
|
|
|
Diags.Report(diag::err_drv_amdgpu_ieee_without_no_honor_nans);
|
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2021-02-09 11:42:01 +01:00
|
|
|
}
|
|
|
|
|
2021-02-10 11:47:33 +01:00
|
|
|
static void
|
|
|
|
GenerateDependencyOutputArgs(const DependencyOutputOptions &Opts,
|
|
|
|
SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA) {
|
|
|
|
const DependencyOutputOptions &DependencyOutputOpts = Opts;
|
|
|
|
#define DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
if (Opts.ShowIncludesDest != ShowIncludesDestination::None)
|
|
|
|
GenerateArg(Args, OPT_show_includes, SA);
|
|
|
|
|
|
|
|
for (const auto &Dep : Opts.ExtraDeps) {
|
|
|
|
switch (Dep.second) {
|
2021-05-04 09:50:43 -04:00
|
|
|
case EDK_SanitizeIgnorelist:
|
|
|
|
// Sanitizer ignorelist arguments are generated from LanguageOptions.
|
2021-02-10 11:47:33 +01:00
|
|
|
continue;
|
|
|
|
case EDK_ModuleFile:
|
|
|
|
// Module file arguments are generated from FrontendOptions and
|
|
|
|
// HeaderSearchOptions.
|
|
|
|
continue;
|
|
|
|
case EDK_ProfileList:
|
2021-02-25 10:10:40 +01:00
|
|
|
// Profile list arguments are generated from LanguageOptions via the
|
|
|
|
// marshalling infrastructure.
|
|
|
|
continue;
|
2021-02-10 11:47:33 +01:00
|
|
|
case EDK_DepFileEntry:
|
|
|
|
GenerateArg(Args, OPT_fdepfile_entry, Dep.first, SA);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
static bool ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
|
|
|
|
ArgList &Args, DiagnosticsEngine &Diags,
|
|
|
|
frontend::ActionKind Action,
|
|
|
|
bool ShowLineMarkers) {
|
2021-02-10 11:47:33 +01:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
|
|
|
|
|
|
|
DependencyOutputOptions &DependencyOutputOpts = Opts;
|
|
|
|
#define DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-02-10 11:47:33 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING
|
|
|
|
|
2018-05-04 15:58:31 +00:00
|
|
|
if (Args.hasArg(OPT_show_includes)) {
|
|
|
|
// Writing both /showIncludes and preprocessor output to stdout
|
|
|
|
// would produce interleaved output, so use stderr for /showIncludes.
|
|
|
|
// This behaves the same as cl.exe, when /E, /EP or /P are passed.
|
2021-02-10 11:47:33 +01:00
|
|
|
if (Action == frontend::PrintPreprocessedInput || !ShowLineMarkers)
|
2018-05-04 15:58:31 +00:00
|
|
|
Opts.ShowIncludesDest = ShowIncludesDestination::Stderr;
|
|
|
|
else
|
|
|
|
Opts.ShowIncludesDest = ShowIncludesDestination::Stdout;
|
|
|
|
} else {
|
|
|
|
Opts.ShowIncludesDest = ShowIncludesDestination::None;
|
|
|
|
}
|
2021-02-10 11:47:33 +01:00
|
|
|
|
2021-05-04 09:50:43 -04:00
|
|
|
// Add sanitizer ignorelists as extra dependencies.
|
2015-08-13 04:04:37 +00:00
|
|
|
// They won't be discovered by the regular preprocessor, so
|
|
|
|
// we let make / ninja to know about this implicit dependency.
|
2021-05-04 09:50:43 -04:00
|
|
|
if (!Args.hasArg(OPT_fno_sanitize_ignorelist)) {
|
|
|
|
for (const auto *A : Args.filtered(OPT_fsanitize_ignorelist_EQ)) {
|
2019-11-08 14:16:15 -08:00
|
|
|
StringRef Val = A->getValue();
|
2021-10-19 08:54:02 -07:00
|
|
|
if (!Val.contains('='))
|
2021-05-04 09:50:43 -04:00
|
|
|
Opts.ExtraDeps.emplace_back(std::string(Val), EDK_SanitizeIgnorelist);
|
2019-11-08 14:16:15 -08:00
|
|
|
}
|
|
|
|
if (Opts.IncludeSystemHeaders) {
|
2021-05-04 09:50:43 -04:00
|
|
|
for (const auto *A : Args.filtered(OPT_fsanitize_system_ignorelist_EQ)) {
|
2019-11-08 14:16:15 -08:00
|
|
|
StringRef Val = A->getValue();
|
2021-10-19 08:54:02 -07:00
|
|
|
if (!Val.contains('='))
|
2021-05-04 09:50:43 -04:00
|
|
|
Opts.ExtraDeps.emplace_back(std::string(Val), EDK_SanitizeIgnorelist);
|
2019-11-08 14:16:15 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-15 01:14:37 -08:00
|
|
|
// -fprofile-list= dependencies.
|
|
|
|
for (const auto &Filename : Args.getAllArgValues(OPT_fprofile_list_EQ))
|
2021-02-10 11:47:33 +01:00
|
|
|
Opts.ExtraDeps.emplace_back(Filename, EDK_ProfileList);
|
2021-01-15 01:14:37 -08:00
|
|
|
|
2019-11-08 14:16:15 -08:00
|
|
|
// Propagate the extra dependencies.
|
2021-02-10 11:47:33 +01:00
|
|
|
for (const auto *A : Args.filtered(OPT_fdepfile_entry))
|
|
|
|
Opts.ExtraDeps.emplace_back(A->getValue(), EDK_DepFileEntry);
|
2019-11-08 14:16:15 -08:00
|
|
|
|
2017-08-31 06:26:43 +00:00
|
|
|
// Only the -fmodule-file=<file> form.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_fmodule_file)) {
|
2017-08-31 06:26:43 +00:00
|
|
|
StringRef Val = A->getValue();
|
2021-10-19 08:54:02 -07:00
|
|
|
if (!Val.contains('='))
|
2021-02-10 11:47:33 +01:00
|
|
|
Opts.ExtraDeps.emplace_back(std::string(Val), EDK_ModuleFile);
|
2017-08-31 06:26:43 +00:00
|
|
|
}
|
2021-02-10 11:47:33 +01:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2021-02-10 11:47:33 +01:00
|
|
|
}
|
|
|
|
|
2016-05-27 20:43:00 +00:00
|
|
|
static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) {
|
|
|
|
// Color diagnostics default to auto ("on" if terminal supports) in the driver
|
|
|
|
// but default to off in cc1, needing an explicit OPT_fdiagnostics_color.
|
|
|
|
// Support both clang's -f[no-]color-diagnostics and gcc's
|
|
|
|
// -f[no-]diagnostics-colors[=never|always|auto].
|
|
|
|
enum {
|
|
|
|
Colors_On,
|
|
|
|
Colors_Off,
|
|
|
|
Colors_Auto
|
|
|
|
} ShowColors = DefaultColor ? Colors_Auto : Colors_Off;
|
2018-03-26 21:45:04 +00:00
|
|
|
for (auto *A : Args) {
|
2016-05-27 20:43:00 +00:00
|
|
|
const Option &O = A->getOption();
|
2022-04-10 01:07:44 -07:00
|
|
|
if (O.matches(options::OPT_fcolor_diagnostics)) {
|
2016-05-27 20:43:00 +00:00
|
|
|
ShowColors = Colors_On;
|
2022-04-10 01:07:44 -07:00
|
|
|
} else if (O.matches(options::OPT_fno_color_diagnostics)) {
|
2016-05-27 20:43:00 +00:00
|
|
|
ShowColors = Colors_Off;
|
2016-12-10 14:55:14 +00:00
|
|
|
} else if (O.matches(options::OPT_fdiagnostics_color_EQ)) {
|
2016-05-27 20:43:00 +00:00
|
|
|
StringRef Value(A->getValue());
|
|
|
|
if (Value == "always")
|
|
|
|
ShowColors = Colors_On;
|
|
|
|
else if (Value == "never")
|
|
|
|
ShowColors = Colors_Off;
|
|
|
|
else if (Value == "auto")
|
|
|
|
ShowColors = Colors_Auto;
|
|
|
|
}
|
|
|
|
}
|
2016-12-10 14:55:14 +00:00
|
|
|
return ShowColors == Colors_On ||
|
|
|
|
(ShowColors == Colors_Auto &&
|
|
|
|
llvm::sys::Process::StandardErrHasColors());
|
2016-05-27 20:43:00 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 02:23:22 +00:00
|
|
|
static bool checkVerifyPrefixes(const std::vector<std::string> &VerifyPrefixes,
|
2020-12-22 15:05:16 +01:00
|
|
|
DiagnosticsEngine &Diags) {
|
2017-12-16 02:23:22 +00:00
|
|
|
bool Success = true;
|
|
|
|
for (const auto &Prefix : VerifyPrefixes) {
|
|
|
|
// Every prefix must start with a letter and contain only alphanumeric
|
|
|
|
// characters, hyphens, and underscores.
|
2019-03-31 08:48:19 +00:00
|
|
|
auto BadChar = llvm::find_if(Prefix, [](char C) {
|
|
|
|
return !isAlphanumeric(C) && C != '-' && C != '_';
|
|
|
|
});
|
2017-12-16 02:23:22 +00:00
|
|
|
if (BadChar != Prefix.end() || !isLetter(Prefix[0])) {
|
|
|
|
Success = false;
|
2020-12-22 15:05:16 +01:00
|
|
|
Diags.Report(diag::err_drv_invalid_value) << "-verify=" << Prefix;
|
|
|
|
Diags.Report(diag::note_drv_verify_prefix_spelling);
|
2017-12-16 02:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
2021-02-10 13:54:08 +01:00
|
|
|
static void GenerateFileSystemArgs(const FileSystemOptions &Opts,
|
2021-02-10 12:47:06 +01:00
|
|
|
SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA) {
|
2021-02-10 13:54:08 +01:00
|
|
|
const FileSystemOptions &FileSystemOpts = Opts;
|
|
|
|
|
2021-02-10 12:47:06 +01:00
|
|
|
#define FILE_SYSTEM_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef FILE_SYSTEM_OPTION_WITH_MARSHALLING
|
|
|
|
}
|
|
|
|
|
2021-02-10 13:54:08 +01:00
|
|
|
static bool ParseFileSystemArgs(FileSystemOptions &Opts, const ArgList &Args,
|
|
|
|
DiagnosticsEngine &Diags) {
|
2021-04-16 15:30:28 +02:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
|
|
|
|
2021-02-10 13:54:08 +01:00
|
|
|
FileSystemOptions &FileSystemOpts = Opts;
|
2021-01-06 15:18:43 +01:00
|
|
|
|
2021-02-10 12:47:06 +01:00
|
|
|
#define FILE_SYSTEM_OPTION_WITH_MARSHALLING( \
|
2021-01-28 10:48:26 +01:00
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-01-06 14:58:19 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
2021-02-10 12:47:06 +01:00
|
|
|
#undef FILE_SYSTEM_OPTION_WITH_MARSHALLING
|
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2021-02-10 12:47:06 +01:00
|
|
|
}
|
|
|
|
|
2021-02-10 13:54:08 +01:00
|
|
|
static void GenerateMigratorArgs(const MigratorOptions &Opts,
|
2021-02-10 12:47:06 +01:00
|
|
|
SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA) {
|
2021-02-10 13:54:08 +01:00
|
|
|
const MigratorOptions &MigratorOpts = Opts;
|
2021-02-10 12:47:06 +01:00
|
|
|
#define MIGRATOR_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef MIGRATOR_OPTION_WITH_MARSHALLING
|
|
|
|
}
|
|
|
|
|
2021-02-10 13:54:08 +01:00
|
|
|
static bool ParseMigratorArgs(MigratorOptions &Opts, const ArgList &Args,
|
|
|
|
DiagnosticsEngine &Diags) {
|
2021-04-16 15:30:28 +02:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
|
|
|
|
2021-02-10 13:54:08 +01:00
|
|
|
MigratorOptions &MigratorOpts = Opts;
|
2021-02-10 12:47:06 +01:00
|
|
|
|
|
|
|
#define MIGRATOR_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-02-10 12:47:06 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef MIGRATOR_OPTION_WITH_MARSHALLING
|
2021-01-06 14:58:19 +01:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2021-01-06 14:58:19 +01:00
|
|
|
}
|
|
|
|
|
2021-02-10 12:24:19 +01:00
|
|
|
void CompilerInvocation::GenerateDiagnosticArgs(
|
|
|
|
const DiagnosticOptions &Opts, SmallVectorImpl<const char *> &Args,
|
|
|
|
StringAllocator SA, bool DefaultDiagColor) {
|
|
|
|
const DiagnosticOptions *DiagnosticOpts = &Opts;
|
|
|
|
#define DIAG_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef DIAG_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
if (!Opts.DiagnosticSerializationFile.empty())
|
|
|
|
GenerateArg(Args, OPT_diagnostic_serialized_file,
|
|
|
|
Opts.DiagnosticSerializationFile, SA);
|
|
|
|
|
|
|
|
if (Opts.ShowColors)
|
|
|
|
GenerateArg(Args, OPT_fcolor_diagnostics, SA);
|
|
|
|
|
|
|
|
if (Opts.VerifyDiagnostics &&
|
|
|
|
llvm::is_contained(Opts.VerifyPrefixes, "expected"))
|
|
|
|
GenerateArg(Args, OPT_verify, SA);
|
|
|
|
|
|
|
|
for (const auto &Prefix : Opts.VerifyPrefixes)
|
|
|
|
if (Prefix != "expected")
|
|
|
|
GenerateArg(Args, OPT_verify_EQ, Prefix, SA);
|
|
|
|
|
|
|
|
DiagnosticLevelMask VIU = Opts.getVerifyIgnoreUnexpected();
|
|
|
|
if (VIU == DiagnosticLevelMask::None) {
|
|
|
|
// This is the default, don't generate anything.
|
|
|
|
} else if (VIU == DiagnosticLevelMask::All) {
|
|
|
|
GenerateArg(Args, OPT_verify_ignore_unexpected, SA);
|
|
|
|
} else {
|
|
|
|
if (static_cast<unsigned>(VIU & DiagnosticLevelMask::Note) != 0)
|
|
|
|
GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "note", SA);
|
|
|
|
if (static_cast<unsigned>(VIU & DiagnosticLevelMask::Remark) != 0)
|
|
|
|
GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "remark", SA);
|
|
|
|
if (static_cast<unsigned>(VIU & DiagnosticLevelMask::Warning) != 0)
|
|
|
|
GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "warning", SA);
|
|
|
|
if (static_cast<unsigned>(VIU & DiagnosticLevelMask::Error) != 0)
|
|
|
|
GenerateArg(Args, OPT_verify_ignore_unexpected_EQ, "error", SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &Warning : Opts.Warnings) {
|
|
|
|
// This option is automatically generated from UndefPrefixes.
|
|
|
|
if (Warning == "undef-prefix")
|
|
|
|
continue;
|
|
|
|
Args.push_back(SA(StringRef("-W") + Warning));
|
|
|
|
}
|
|
|
|
|
2021-02-25 09:05:08 +01:00
|
|
|
for (const auto &Remark : Opts.Remarks) {
|
|
|
|
// These arguments are generated from OptimizationRemark fields of
|
|
|
|
// CodeGenOptions.
|
|
|
|
StringRef IgnoredRemarks[] = {"pass", "no-pass",
|
|
|
|
"pass-analysis", "no-pass-analysis",
|
|
|
|
"pass-missed", "no-pass-missed"};
|
|
|
|
if (llvm::is_contained(IgnoredRemarks, Remark))
|
|
|
|
continue;
|
|
|
|
|
2021-02-10 12:24:19 +01:00
|
|
|
Args.push_back(SA(StringRef("-R") + Remark));
|
2021-02-25 09:05:08 +01:00
|
|
|
}
|
2021-02-10 12:24:19 +01:00
|
|
|
}
|
|
|
|
|
2021-08-30 15:41:53 +02:00
|
|
|
std::unique_ptr<DiagnosticOptions>
|
|
|
|
clang::CreateAndPopulateDiagOpts(ArrayRef<const char *> Argv) {
|
|
|
|
auto DiagOpts = std::make_unique<DiagnosticOptions>();
|
|
|
|
unsigned MissingArgIndex, MissingArgCount;
|
|
|
|
InputArgList Args = getDriverOptTable().ParseArgs(
|
|
|
|
Argv.slice(1), MissingArgIndex, MissingArgCount);
|
|
|
|
// We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
|
|
|
|
// Any errors that would be diagnosed here will also be diagnosed later,
|
|
|
|
// when the DiagnosticsEngine actually exists.
|
|
|
|
(void)ParseDiagnosticArgs(*DiagOpts, Args);
|
|
|
|
return DiagOpts;
|
|
|
|
}
|
|
|
|
|
2012-03-13 20:09:56 +00:00
|
|
|
bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
|
2016-05-27 20:43:00 +00:00
|
|
|
DiagnosticsEngine *Diags,
|
2020-03-31 21:30:14 -07:00
|
|
|
bool DefaultDiagColor) {
|
2020-12-22 15:05:16 +01:00
|
|
|
Optional<DiagnosticsEngine> IgnoringDiags;
|
|
|
|
if (!Diags) {
|
|
|
|
IgnoringDiags.emplace(new DiagnosticIDs(), new DiagnosticOptions(),
|
|
|
|
new IgnoringDiagConsumer());
|
|
|
|
Diags = &*IgnoringDiags;
|
|
|
|
}
|
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
unsigned NumErrorsBefore = Diags->getNumErrors();
|
|
|
|
|
[clang][cli] Specify KeyPath prefixes via TableGen classes
It turns out we need to handle `LangOptions` separately from the rest of the options. `LangOptions` used to be conditionally parsed only when `!(DashX.getFormat() == InputKind::Precompiled || DashX.getLanguage() == Language::LLVM_IR)` and we need to restore this order (for more info, see D94682).
We could do this similarly to how `DiagnosticOptions` are handled: via a counterpart to the `IsDiag` mix-in (e.g. `IsLang`). These mix-ins would prefix the option key path with the appropriate `CompilerInvocation::XxxOpts` member. However, this solution would be problematic, as we'd now have two kinds of options (`Lang` and `Diag`) with seemingly incomplete key paths in the same file. To understand what `CompilerInvocation` member an option affects, one would need to read the whole option definition and notice the `IsDiag` or `IsLang` class.
Instead, this patch introduces more robust way to handle different kinds of options separately: via the `KeyPathAndMacroPrefix` class. We have one specialization of that class per `CompilerInvocation` member (e.g. `LangOpts`, `DiagnosticOpts`, etc.). Now, instead of specifying a key path with `"LangOpts->UndefPrefixes"`, we use `LangOpts<"UndefPrefixes">`. This keeps the readability intact (you don't have to look for the `IsLang` mix-in, the key path is complete on its own) and allows us to specify a custom macro prefix within `LangOpts`.
Reviewed By: Bigcheese
Differential Revision: https://reviews.llvm.org/D94676
2021-01-13 12:50:19 +01:00
|
|
|
// The key paths of diagnostic options defined in Options.td start with
|
|
|
|
// "DiagnosticOpts->". Let's provide the expected variable name and type.
|
|
|
|
DiagnosticOptions *DiagnosticOpts = &Opts;
|
2011-12-23 03:05:38 +00:00
|
|
|
|
2021-01-28 10:48:26 +01:00
|
|
|
#define DIAG_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, *Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-01-08 11:05:16 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef DIAG_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
llvm::sys::Process::UseANSIEscapeCodes(Opts.UseANSIEscapeCodes);
|
|
|
|
|
2014-10-23 22:20:11 +00:00
|
|
|
if (Arg *A =
|
|
|
|
Args.getLastArg(OPT_diagnostic_serialized_file, OPT__serialize_diags))
|
|
|
|
Opts.DiagnosticSerializationFile = A->getValue();
|
2016-05-27 20:43:00 +00:00
|
|
|
Opts.ShowColors = parseShowColorsArgs(Args, DefaultDiagColor);
|
2021-01-08 11:05:16 +01:00
|
|
|
|
2017-12-16 02:23:22 +00:00
|
|
|
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify) || Args.hasArg(OPT_verify_EQ);
|
2021-02-10 12:24:19 +01:00
|
|
|
Opts.VerifyPrefixes = Args.getAllArgValues(OPT_verify_EQ);
|
2017-12-16 02:23:22 +00:00
|
|
|
if (Args.hasArg(OPT_verify))
|
|
|
|
Opts.VerifyPrefixes.push_back("expected");
|
|
|
|
// Keep VerifyPrefixes in its original order for the sake of diagnostics, and
|
|
|
|
// then sort it to prepare for fast lookup using std::binary_search.
|
2021-04-16 15:30:28 +02:00
|
|
|
if (!checkVerifyPrefixes(Opts.VerifyPrefixes, *Diags))
|
2017-12-16 02:23:22 +00:00
|
|
|
Opts.VerifyDiagnostics = false;
|
|
|
|
else
|
2018-09-30 21:41:11 +00:00
|
|
|
llvm::sort(Opts.VerifyPrefixes);
|
2015-06-13 07:11:40 +00:00
|
|
|
DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None;
|
2021-04-16 15:30:28 +02:00
|
|
|
parseDiagnosticLevelMask(
|
|
|
|
"-verify-ignore-unexpected=",
|
|
|
|
Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ), *Diags, DiagMask);
|
2015-06-13 07:11:40 +00:00
|
|
|
if (Args.hasArg(OPT_verify_ignore_unexpected))
|
|
|
|
DiagMask = DiagnosticLevelMask::All;
|
|
|
|
Opts.setVerifyIgnoreUnexpected(DiagMask);
|
2010-01-13 03:06:50 +00:00
|
|
|
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
|
|
|
|
Opts.TabStop = DiagnosticOptions::DefaultTabStop;
|
2020-12-22 15:05:16 +01:00
|
|
|
Diags->Report(diag::warn_ignoring_ftabstop_value)
|
|
|
|
<< Opts.TabStop << DiagnosticOptions::DefaultTabStop;
|
2010-01-13 03:06:50 +00:00
|
|
|
}
|
[clang][diagnostics] Add '-Wundef-prefix' warning option
Summary:
Add an `-Wundef-prefix=<arg1>,<arg2>...` option, which is similar to `-Wundef`, but only give warnings for undefined macros with the given prefixes.
Reviewers: ributzka, steven_wu, cishida, bruno, arphaman, rsmith
Reviewed By: ributzka, arphaman
Subscribers: riccibruno, dexonsmith, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80751
This patch was authored by Zixu Wang <zixu_wang@apple.com>
2020-06-30 09:28:06 -07:00
|
|
|
|
Use -Rblah, not -Wblah, to control remark diagnostics. This was always the
intent when we added remark support, but was never implemented in the general
case, because the first -R flags didn't need it. (-Rpass= had special handling
to accomodate its argument.)
-Rno-foo, -Reverything, and -Rno-everything can be used to turn off a remark,
or to turn on or off all remarks. Per discussion on cfe-commits, -Weverything
does not affect remarks, and -Reverything does not affect warnings or errors.
The only "real" -R flag we have right now is -Rmodule-build; that flag is
effectively renamed from -Wmodule-build to -Rmodule-build by this change.
-Wpass and -Wno-pass (and their friends) are also renamed to -Rpass and
-Rno-pass by this change; it's not completely clear whether we intended to have
a -Rpass (with no =pattern), but that is unchanged by this commit, other than
the flag name. The default pattern is effectively one which matches no passes.
In future, we may want to make the default pattern be .*, so that -Reverything
works for -Rpass properly.
llvm-svn: 215046
2014-08-07 00:24:21 +00:00
|
|
|
addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings);
|
|
|
|
addDiagnosticArgs(Args, OPT_R_Group, OPT_R_value_Group, Opts.Remarks);
|
2011-12-23 03:05:38 +00:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags->getNumErrors() == NumErrorsBefore;
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
2015-11-03 18:33:07 +00:00
|
|
|
/// Parse the argument to the -ftest-module-file-extension
|
|
|
|
/// command-line argument.
|
|
|
|
///
|
|
|
|
/// \returns true on error, false on success.
|
|
|
|
static bool parseTestModuleFileExtensionArg(StringRef Arg,
|
|
|
|
std::string &BlockName,
|
|
|
|
unsigned &MajorVersion,
|
|
|
|
unsigned &MinorVersion,
|
|
|
|
bool &Hashed,
|
|
|
|
std::string &UserInfo) {
|
|
|
|
SmallVector<StringRef, 5> Args;
|
|
|
|
Arg.split(Args, ':', 5);
|
|
|
|
if (Args.size() < 5)
|
|
|
|
return true;
|
|
|
|
|
2020-01-28 20:23:46 +01:00
|
|
|
BlockName = std::string(Args[0]);
|
2015-11-03 18:33:07 +00:00
|
|
|
if (Args[1].getAsInteger(10, MajorVersion)) return true;
|
|
|
|
if (Args[2].getAsInteger(10, MinorVersion)) return true;
|
|
|
|
if (Args[3].getAsInteger(2, Hashed)) return true;
|
|
|
|
if (Args.size() > 4)
|
2020-01-28 20:23:46 +01:00
|
|
|
UserInfo = std::string(Args[4]);
|
2015-11-03 18:33:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-09 15:20:09 +01:00
|
|
|
/// Return a table that associates command line option specifiers with the
|
|
|
|
/// frontend action. Note: The pair {frontend::PluginAction, OPT_plugin} is
|
|
|
|
/// intentionally missing, as this case is handled separately from other
|
|
|
|
/// frontend options.
|
|
|
|
static const auto &getFrontendActionTable() {
|
2021-02-09 15:46:10 +01:00
|
|
|
static const std::pair<frontend::ActionKind, unsigned> Table[] = {
|
2021-02-09 15:20:09 +01:00
|
|
|
{frontend::ASTDeclList, OPT_ast_list},
|
|
|
|
|
|
|
|
{frontend::ASTDump, OPT_ast_dump_all_EQ},
|
|
|
|
{frontend::ASTDump, OPT_ast_dump_all},
|
|
|
|
{frontend::ASTDump, OPT_ast_dump_EQ},
|
|
|
|
{frontend::ASTDump, OPT_ast_dump},
|
|
|
|
{frontend::ASTDump, OPT_ast_dump_lookups},
|
|
|
|
{frontend::ASTDump, OPT_ast_dump_decl_types},
|
|
|
|
|
|
|
|
{frontend::ASTPrint, OPT_ast_print},
|
|
|
|
{frontend::ASTView, OPT_ast_view},
|
|
|
|
{frontend::DumpCompilerOptions, OPT_compiler_options_dump},
|
|
|
|
{frontend::DumpRawTokens, OPT_dump_raw_tokens},
|
|
|
|
{frontend::DumpTokens, OPT_dump_tokens},
|
|
|
|
{frontend::EmitAssembly, OPT_S},
|
|
|
|
{frontend::EmitBC, OPT_emit_llvm_bc},
|
|
|
|
{frontend::EmitHTML, OPT_emit_html},
|
|
|
|
{frontend::EmitLLVM, OPT_emit_llvm},
|
|
|
|
{frontend::EmitLLVMOnly, OPT_emit_llvm_only},
|
|
|
|
{frontend::EmitCodeGenOnly, OPT_emit_codegen_only},
|
|
|
|
{frontend::EmitObj, OPT_emit_obj},
|
2022-01-20 10:30:56 -08:00
|
|
|
{frontend::ExtractAPI, OPT_extract_api},
|
2021-02-09 15:20:09 +01:00
|
|
|
|
|
|
|
{frontend::FixIt, OPT_fixit_EQ},
|
|
|
|
{frontend::FixIt, OPT_fixit},
|
|
|
|
|
|
|
|
{frontend::GenerateModule, OPT_emit_module},
|
|
|
|
{frontend::GenerateModuleInterface, OPT_emit_module_interface},
|
|
|
|
{frontend::GenerateHeaderModule, OPT_emit_header_module},
|
2020-09-20 09:29:14 +01:00
|
|
|
{frontend::GenerateHeaderUnit, OPT_emit_header_unit},
|
2021-02-09 15:20:09 +01:00
|
|
|
{frontend::GeneratePCH, OPT_emit_pch},
|
|
|
|
{frontend::GenerateInterfaceStubs, OPT_emit_interface_stubs},
|
|
|
|
{frontend::InitOnly, OPT_init_only},
|
|
|
|
{frontend::ParseSyntaxOnly, OPT_fsyntax_only},
|
|
|
|
{frontend::ModuleFileInfo, OPT_module_file_info},
|
|
|
|
{frontend::VerifyPCH, OPT_verify_pch},
|
|
|
|
{frontend::PrintPreamble, OPT_print_preamble},
|
|
|
|
{frontend::PrintPreprocessedInput, OPT_E},
|
|
|
|
{frontend::TemplightDump, OPT_templight_dump},
|
|
|
|
{frontend::RewriteMacros, OPT_rewrite_macros},
|
|
|
|
{frontend::RewriteObjC, OPT_rewrite_objc},
|
|
|
|
{frontend::RewriteTest, OPT_rewrite_test},
|
|
|
|
{frontend::RunAnalysis, OPT_analyze},
|
|
|
|
{frontend::MigrateSource, OPT_migrate},
|
|
|
|
{frontend::RunPreprocessorOnly, OPT_Eonly},
|
|
|
|
{frontend::PrintDependencyDirectivesSourceMinimizerOutput,
|
2020-09-20 09:29:14 +01:00
|
|
|
OPT_print_dependency_directives_minimized_source},
|
2021-02-09 15:20:09 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
return Table;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Maps command line option to frontend action.
|
|
|
|
static Optional<frontend::ActionKind> getFrontendAction(OptSpecifier &Opt) {
|
|
|
|
for (const auto &ActionOpt : getFrontendActionTable())
|
2021-02-09 15:46:10 +01:00
|
|
|
if (ActionOpt.second == Opt.getID())
|
2021-02-09 15:20:09 +01:00
|
|
|
return ActionOpt.first;
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2021-02-09 16:30:14 +01:00
|
|
|
/// Maps frontend action to command line option.
|
|
|
|
static Optional<OptSpecifier>
|
|
|
|
getProgramActionOpt(frontend::ActionKind ProgramAction) {
|
|
|
|
for (const auto &ActionOpt : getFrontendActionTable())
|
|
|
|
if (ActionOpt.first == ProgramAction)
|
|
|
|
return OptSpecifier(ActionOpt.second);
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void GenerateFrontendArgs(const FrontendOptions &Opts,
|
|
|
|
SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA,
|
|
|
|
bool IsHeader) {
|
|
|
|
const FrontendOptions &FrontendOpts = Opts;
|
|
|
|
#define FRONTEND_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef FRONTEND_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
Optional<OptSpecifier> ProgramActionOpt =
|
|
|
|
getProgramActionOpt(Opts.ProgramAction);
|
|
|
|
|
|
|
|
// Generating a simple flag covers most frontend actions.
|
|
|
|
std::function<void()> GenerateProgramAction = [&]() {
|
|
|
|
GenerateArg(Args, *ProgramActionOpt, SA);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!ProgramActionOpt) {
|
|
|
|
// PluginAction is the only program action handled separately.
|
|
|
|
assert(Opts.ProgramAction == frontend::PluginAction &&
|
|
|
|
"Frontend action without option.");
|
|
|
|
GenerateProgramAction = [&]() {
|
|
|
|
GenerateArg(Args, OPT_plugin, Opts.ActionName, SA);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Simplify the complex 'AST dump' command line.
|
|
|
|
if (Opts.ProgramAction == frontend::ASTDump) {
|
|
|
|
GenerateProgramAction = [&]() {
|
|
|
|
// ASTDumpLookups, ASTDumpDeclTypes and ASTDumpFilter are generated via
|
|
|
|
// marshalling infrastructure.
|
|
|
|
|
|
|
|
if (Opts.ASTDumpFormat != ADOF_Default) {
|
|
|
|
StringRef Format;
|
|
|
|
switch (Opts.ASTDumpFormat) {
|
|
|
|
case ADOF_Default:
|
|
|
|
llvm_unreachable("Default AST dump format.");
|
|
|
|
case ADOF_JSON:
|
|
|
|
Format = "json";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.ASTDumpAll)
|
|
|
|
GenerateArg(Args, OPT_ast_dump_all_EQ, Format, SA);
|
|
|
|
if (Opts.ASTDumpDecls)
|
|
|
|
GenerateArg(Args, OPT_ast_dump_EQ, Format, SA);
|
|
|
|
} else {
|
|
|
|
if (Opts.ASTDumpAll)
|
|
|
|
GenerateArg(Args, OPT_ast_dump_all, SA);
|
|
|
|
if (Opts.ASTDumpDecls)
|
|
|
|
GenerateArg(Args, OPT_ast_dump, SA);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.ProgramAction == frontend::FixIt && !Opts.FixItSuffix.empty()) {
|
|
|
|
GenerateProgramAction = [&]() {
|
|
|
|
GenerateArg(Args, OPT_fixit_EQ, Opts.FixItSuffix, SA);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
GenerateProgramAction();
|
|
|
|
|
2021-03-30 18:33:10 +01:00
|
|
|
for (const auto &PluginArgs : Opts.PluginArgs) {
|
|
|
|
Option Opt = getDriverOptTable().getOption(OPT_plugin_arg);
|
|
|
|
const char *Spelling =
|
|
|
|
SA(Opt.getPrefix() + Opt.getName() + PluginArgs.first);
|
2021-02-09 16:30:14 +01:00
|
|
|
for (const auto &PluginArg : PluginArgs.second)
|
2021-03-30 18:33:10 +01:00
|
|
|
denormalizeString(Args, Spelling, SA, Opt.getKind(), 0, PluginArg);
|
|
|
|
}
|
2021-02-09 16:30:14 +01:00
|
|
|
|
2021-03-02 13:14:00 +01:00
|
|
|
for (const auto &Ext : Opts.ModuleFileExtensions)
|
|
|
|
if (auto *TestExt = dyn_cast_or_null<TestModuleFileExtension>(Ext.get()))
|
|
|
|
GenerateArg(Args, OPT_ftest_module_file_extension_EQ, TestExt->str(), SA);
|
2021-02-09 16:30:14 +01:00
|
|
|
|
|
|
|
if (!Opts.CodeCompletionAt.FileName.empty())
|
|
|
|
GenerateArg(Args, OPT_code_completion_at, Opts.CodeCompletionAt.ToString(),
|
|
|
|
SA);
|
|
|
|
|
|
|
|
for (const auto &Plugin : Opts.Plugins)
|
|
|
|
GenerateArg(Args, OPT_load, Plugin, SA);
|
|
|
|
|
|
|
|
// ASTDumpDecls and ASTDumpAll already handled with ProgramAction.
|
|
|
|
|
|
|
|
for (const auto &ModuleFile : Opts.ModuleFiles)
|
|
|
|
GenerateArg(Args, OPT_fmodule_file, ModuleFile, SA);
|
|
|
|
|
|
|
|
if (Opts.AuxTargetCPU.hasValue())
|
|
|
|
GenerateArg(Args, OPT_aux_target_cpu, *Opts.AuxTargetCPU, SA);
|
|
|
|
|
|
|
|
if (Opts.AuxTargetFeatures.hasValue())
|
|
|
|
for (const auto &Feature : *Opts.AuxTargetFeatures)
|
|
|
|
GenerateArg(Args, OPT_aux_target_feature, Feature, SA);
|
|
|
|
|
|
|
|
{
|
|
|
|
StringRef Preprocessed = Opts.DashX.isPreprocessed() ? "-cpp-output" : "";
|
|
|
|
StringRef ModuleMap =
|
|
|
|
Opts.DashX.getFormat() == InputKind::ModuleMap ? "-module-map" : "";
|
2021-01-10 13:50:26 +00:00
|
|
|
StringRef HeaderUnit = "";
|
|
|
|
switch (Opts.DashX.getHeaderUnitKind()) {
|
|
|
|
case InputKind::HeaderUnit_None:
|
|
|
|
break;
|
|
|
|
case InputKind::HeaderUnit_User:
|
|
|
|
HeaderUnit = "-user";
|
|
|
|
break;
|
|
|
|
case InputKind::HeaderUnit_System:
|
|
|
|
HeaderUnit = "-system";
|
|
|
|
break;
|
|
|
|
case InputKind::HeaderUnit_Abs:
|
|
|
|
HeaderUnit = "-header-unit";
|
|
|
|
break;
|
|
|
|
}
|
2021-02-09 16:30:14 +01:00
|
|
|
StringRef Header = IsHeader ? "-header" : "";
|
|
|
|
|
|
|
|
StringRef Lang;
|
|
|
|
switch (Opts.DashX.getLanguage()) {
|
|
|
|
case Language::C:
|
|
|
|
Lang = "c";
|
|
|
|
break;
|
|
|
|
case Language::OpenCL:
|
|
|
|
Lang = "cl";
|
|
|
|
break;
|
2021-03-03 19:00:55 +00:00
|
|
|
case Language::OpenCLCXX:
|
|
|
|
Lang = "clcpp";
|
|
|
|
break;
|
2021-02-09 16:30:14 +01:00
|
|
|
case Language::CUDA:
|
|
|
|
Lang = "cuda";
|
|
|
|
break;
|
|
|
|
case Language::HIP:
|
|
|
|
Lang = "hip";
|
|
|
|
break;
|
|
|
|
case Language::CXX:
|
|
|
|
Lang = "c++";
|
|
|
|
break;
|
|
|
|
case Language::ObjC:
|
|
|
|
Lang = "objective-c";
|
|
|
|
break;
|
|
|
|
case Language::ObjCXX:
|
|
|
|
Lang = "objective-c++";
|
|
|
|
break;
|
|
|
|
case Language::RenderScript:
|
|
|
|
Lang = "renderscript";
|
|
|
|
break;
|
|
|
|
case Language::Asm:
|
|
|
|
Lang = "assembler-with-cpp";
|
|
|
|
break;
|
|
|
|
case Language::Unknown:
|
|
|
|
assert(Opts.DashX.getFormat() == InputKind::Precompiled &&
|
|
|
|
"Generating -x argument for unknown language (not precompiled).");
|
|
|
|
Lang = "ast";
|
|
|
|
break;
|
|
|
|
case Language::LLVM_IR:
|
|
|
|
Lang = "ir";
|
|
|
|
break;
|
2022-03-28 15:01:41 -05:00
|
|
|
case Language::HLSL:
|
|
|
|
Lang = "hlsl";
|
|
|
|
break;
|
2021-02-09 16:30:14 +01:00
|
|
|
}
|
|
|
|
|
2021-01-10 13:50:26 +00:00
|
|
|
GenerateArg(Args, OPT_x,
|
|
|
|
Lang + HeaderUnit + Header + ModuleMap + Preprocessed, SA);
|
2021-02-09 16:30:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// OPT_INPUT has a unique class, generate it directly.
|
|
|
|
for (const auto &Input : Opts.Inputs)
|
|
|
|
Args.push_back(SA(Input.getFile()));
|
|
|
|
}
|
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
|
|
|
DiagnosticsEngine &Diags, bool &IsHeaderFile) {
|
2021-02-09 15:08:31 +01:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
2021-04-16 15:30:28 +02:00
|
|
|
|
|
|
|
FrontendOptions &FrontendOpts = Opts;
|
|
|
|
|
2021-02-09 16:30:14 +01:00
|
|
|
#define FRONTEND_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-02-09 16:30:14 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef FRONTEND_OPTION_WITH_MARSHALLING
|
2021-02-09 15:08:31 +01:00
|
|
|
|
2009-12-01 03:16:53 +00:00
|
|
|
Opts.ProgramAction = frontend::ParseSyntaxOnly;
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_Action_Group)) {
|
2021-02-09 15:20:09 +01:00
|
|
|
OptSpecifier Opt = OptSpecifier(A->getOption().getID());
|
|
|
|
Optional<frontend::ActionKind> ProgramAction = getFrontendAction(Opt);
|
|
|
|
assert(ProgramAction && "Option specifier not in Action_Group.");
|
|
|
|
|
|
|
|
if (ProgramAction == frontend::ASTDump &&
|
|
|
|
(Opt == OPT_ast_dump_all_EQ || Opt == OPT_ast_dump_EQ)) {
|
2019-05-13 21:39:55 +00:00
|
|
|
unsigned Val = llvm::StringSwitch<unsigned>(A->getValue())
|
|
|
|
.CaseLower("default", ADOF_Default)
|
|
|
|
.CaseLower("json", ADOF_JSON)
|
|
|
|
.Default(std::numeric_limits<unsigned>::max());
|
|
|
|
|
|
|
|
if (Val != std::numeric_limits<unsigned>::max())
|
|
|
|
Opts.ASTDumpFormat = static_cast<ASTDumpOutputFormat>(Val);
|
|
|
|
else {
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << A->getValue();
|
|
|
|
Opts.ASTDumpFormat = ADOF_Default;
|
|
|
|
}
|
|
|
|
}
|
2021-02-09 15:20:09 +01:00
|
|
|
|
|
|
|
if (ProgramAction == frontend::FixIt && Opt == OPT_fixit_EQ)
|
2012-11-01 04:30:05 +00:00
|
|
|
Opts.FixItSuffix = A->getValue();
|
2021-02-09 15:20:09 +01:00
|
|
|
|
|
|
|
if (ProgramAction == frontend::GenerateInterfaceStubs) {
|
2019-08-22 23:44:34 +00:00
|
|
|
StringRef ArgStr =
|
2019-10-12 06:25:07 +00:00
|
|
|
Args.hasArg(OPT_interface_stub_version_EQ)
|
|
|
|
? Args.getLastArgValue(OPT_interface_stub_version_EQ)
|
2021-04-07 15:50:12 -07:00
|
|
|
: "ifs-v1";
|
2019-10-08 15:23:14 +00:00
|
|
|
if (ArgStr == "experimental-yaml-elf-v1" ||
|
2021-04-07 15:50:12 -07:00
|
|
|
ArgStr == "experimental-ifs-v1" || ArgStr == "experimental-ifs-v2" ||
|
2019-10-08 15:23:14 +00:00
|
|
|
ArgStr == "experimental-tapi-elf-v1") {
|
2019-08-22 23:44:34 +00:00
|
|
|
std::string ErrorMessage =
|
|
|
|
"Invalid interface stub format: " + ArgStr.str() +
|
2019-10-08 15:23:14 +00:00
|
|
|
" is deprecated.";
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< "Must specify a valid interface stub format type, ie: "
|
2021-04-07 15:50:12 -07:00
|
|
|
"-interface-stub-version=ifs-v1"
|
2019-10-08 15:23:14 +00:00
|
|
|
<< ErrorMessage;
|
2021-02-09 15:20:09 +01:00
|
|
|
ProgramAction = frontend::ParseSyntaxOnly;
|
2021-04-07 15:50:12 -07:00
|
|
|
} else if (!ArgStr.startswith("ifs-")) {
|
2019-10-08 15:23:14 +00:00
|
|
|
std::string ErrorMessage =
|
|
|
|
"Invalid interface stub format: " + ArgStr.str() + ".";
|
2019-06-20 16:59:48 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
2019-08-22 23:44:34 +00:00
|
|
|
<< "Must specify a valid interface stub format type, ie: "
|
2021-04-07 15:50:12 -07:00
|
|
|
"-interface-stub-version=ifs-v1"
|
2019-08-22 23:44:34 +00:00
|
|
|
<< ErrorMessage;
|
2021-02-09 15:20:09 +01:00
|
|
|
ProgramAction = frontend::ParseSyntaxOnly;
|
2019-08-22 23:44:34 +00:00
|
|
|
}
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
2021-02-09 15:20:09 +01:00
|
|
|
|
|
|
|
Opts.ProgramAction = *ProgramAction;
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
2010-06-16 16:59:23 +00:00
|
|
|
|
|
|
|
if (const Arg* A = Args.getLastArg(OPT_plugin)) {
|
2015-05-29 19:42:19 +00:00
|
|
|
Opts.Plugins.emplace_back(A->getValue(0));
|
2009-12-01 03:16:53 +00:00
|
|
|
Opts.ProgramAction = frontend::PluginAction;
|
2012-11-01 04:30:05 +00:00
|
|
|
Opts.ActionName = A->getValue();
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *AA : Args.filtered(OPT_plugin_arg))
|
2016-03-15 12:51:40 +00:00
|
|
|
Opts.PluginArgs[AA->getValue(0)].emplace_back(AA->getValue(1));
|
2011-01-25 20:34:14 +00:00
|
|
|
|
2015-11-03 18:33:07 +00:00
|
|
|
for (const std::string &Arg :
|
|
|
|
Args.getAllArgValues(OPT_ftest_module_file_extension_EQ)) {
|
|
|
|
std::string BlockName;
|
|
|
|
unsigned MajorVersion;
|
|
|
|
unsigned MinorVersion;
|
|
|
|
bool Hashed;
|
|
|
|
std::string UserInfo;
|
|
|
|
if (parseTestModuleFileExtensionArg(Arg, BlockName, MajorVersion,
|
|
|
|
MinorVersion, Hashed, UserInfo)) {
|
|
|
|
Diags.Report(diag::err_test_module_file_extension_format) << Arg;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the testing module file extension.
|
|
|
|
Opts.ModuleFileExtensions.push_back(
|
2017-01-05 18:23:18 +00:00
|
|
|
std::make_shared<TestModuleFileExtension>(
|
|
|
|
BlockName, MajorVersion, MinorVersion, Hashed, UserInfo));
|
2015-11-03 18:33:07 +00:00
|
|
|
}
|
|
|
|
|
2009-12-01 03:16:53 +00:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) {
|
|
|
|
Opts.CodeCompletionAt =
|
2012-11-01 04:30:05 +00:00
|
|
|
ParsedSourceLocation::FromString(A->getValue());
|
2009-12-01 03:16:53 +00:00
|
|
|
if (Opts.CodeCompletionAt.FileName.empty())
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
2012-11-01 04:30:05 +00:00
|
|
|
<< A->getAsString(Args) << A->getValue();
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
2010-05-20 16:54:55 +00:00
|
|
|
Opts.Plugins = Args.getAllArgValues(OPT_load);
|
2019-05-13 21:39:55 +00:00
|
|
|
Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump, OPT_ast_dump_EQ);
|
|
|
|
Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all, OPT_ast_dump_all_EQ);
|
2017-08-31 06:26:43 +00:00
|
|
|
// Only the -fmodule-file=<file> form.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_fmodule_file)) {
|
2017-08-31 06:26:43 +00:00
|
|
|
StringRef Val = A->getValue();
|
2021-10-19 08:54:02 -07:00
|
|
|
if (!Val.contains('='))
|
2020-01-28 20:23:46 +01:00
|
|
|
Opts.ModuleFiles.push_back(std::string(Val));
|
2017-08-31 06:26:43 +00:00
|
|
|
}
|
2020-02-28 17:31:52 -08:00
|
|
|
|
|
|
|
if (Opts.ProgramAction != frontend::GenerateModule && Opts.IsSystemModule)
|
|
|
|
Diags.Report(diag::err_drv_argument_only_allowed_with) << "-fsystem-module"
|
|
|
|
<< "-emit-module";
|
2014-10-22 02:05:46 +00:00
|
|
|
|
[hip] Properly populate macros based on host processor.
Summary:
- The device compilation needs to have a consistent source code compared
to the corresponding host compilation. If macros based on the
host-specific target processor is not properly populated, the device
compilation may fail due to the inconsistent source after the
preprocessor. So far, only the host triple is used to build the
macros. If a detailed host CPU target or certain features are
specified, macros derived from them won't be populated properly, e.g.
`__SSE3__` won't be added unless `+sse3` feature is present. On
Windows compilation compatible with MSVC, that missing macros result
in that intrinsics are not included and cause device compilation
failure on the host-side source.
- This patch addresses this issue by introducing two `cc1` options,
i.e., `-aux-target-cpu` and `-aux-target-feature`. If a specific host
CPU target or certain features are specified, the compiler driver will
append them during the construction of the offline compilation
actions. Then, the toolchain in `cc1` phase will populate macros
accordingly.
- An internal option `--gpu-use-aux-triple-only` is added to fall back
the original behavior to help diagnosing potential issues from the new
behavior.
Reviewers: tra, yaxunl
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D73942
2020-02-03 15:35:18 -05:00
|
|
|
if (Args.hasArg(OPT_aux_target_cpu))
|
|
|
|
Opts.AuxTargetCPU = std::string(Args.getLastArgValue(OPT_aux_target_cpu));
|
|
|
|
if (Args.hasArg(OPT_aux_target_feature))
|
|
|
|
Opts.AuxTargetFeatures = Args.getAllArgValues(OPT_aux_target_feature);
|
2013-11-14 16:33:29 +00:00
|
|
|
|
2012-03-06 20:06:33 +00:00
|
|
|
if (Opts.ARCMTAction != FrontendOptions::ARCMT_None &&
|
|
|
|
Opts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
|
|
|
|
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< "ARC migration" << "ObjC migration";
|
|
|
|
}
|
|
|
|
|
2019-08-05 13:59:26 +00:00
|
|
|
InputKind DashX(Language::Unknown);
|
2009-12-01 03:16:53 +00:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_x)) {
|
2017-04-26 18:57:40 +00:00
|
|
|
StringRef XValue = A->getValue();
|
2017-04-28 01:49:42 +00:00
|
|
|
|
2021-01-10 13:50:26 +00:00
|
|
|
// Parse suffixes:
|
|
|
|
// '<lang>(-[{header-unit,user,system}-]header|[-module-map][-cpp-output])'.
|
2017-04-28 01:49:42 +00:00
|
|
|
// FIXME: Supporting '<lang>-header-cpp-output' would be useful.
|
|
|
|
bool Preprocessed = XValue.consume_back("-cpp-output");
|
|
|
|
bool ModuleMap = XValue.consume_back("-module-map");
|
2021-01-10 13:50:26 +00:00
|
|
|
// Detect and consume the header indicator.
|
|
|
|
bool IsHeader =
|
|
|
|
XValue != "precompiled-header" && XValue.consume_back("-header");
|
|
|
|
|
|
|
|
// If we have c++-{user,system}-header, that indicates a header unit input
|
|
|
|
// likewise, if the user put -fmodule-header together with a header with an
|
|
|
|
// absolute path (header-unit-header).
|
|
|
|
InputKind::HeaderUnitKind HUK = InputKind::HeaderUnit_None;
|
|
|
|
if (IsHeader || Preprocessed) {
|
|
|
|
if (XValue.consume_back("-header-unit"))
|
|
|
|
HUK = InputKind::HeaderUnit_Abs;
|
|
|
|
else if (XValue.consume_back("-system"))
|
|
|
|
HUK = InputKind::HeaderUnit_System;
|
|
|
|
else if (XValue.consume_back("-user"))
|
|
|
|
HUK = InputKind::HeaderUnit_User;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The value set by this processing is an un-preprocessed source which is
|
|
|
|
// not intended to be a module map or header unit.
|
|
|
|
IsHeaderFile = IsHeader && !Preprocessed && !ModuleMap &&
|
|
|
|
HUK == InputKind::HeaderUnit_None;
|
2017-04-28 01:49:42 +00:00
|
|
|
|
|
|
|
// Principal languages.
|
2017-04-26 18:57:40 +00:00
|
|
|
DashX = llvm::StringSwitch<InputKind>(XValue)
|
2019-08-05 13:59:26 +00:00
|
|
|
.Case("c", Language::C)
|
|
|
|
.Case("cl", Language::OpenCL)
|
2021-03-03 19:00:55 +00:00
|
|
|
.Case("clcpp", Language::OpenCLCXX)
|
2019-08-05 13:59:26 +00:00
|
|
|
.Case("cuda", Language::CUDA)
|
|
|
|
.Case("hip", Language::HIP)
|
|
|
|
.Case("c++", Language::CXX)
|
|
|
|
.Case("objective-c", Language::ObjC)
|
|
|
|
.Case("objective-c++", Language::ObjCXX)
|
|
|
|
.Case("renderscript", Language::RenderScript)
|
2022-03-28 15:01:41 -05:00
|
|
|
.Case("hlsl", Language::HLSL)
|
2019-08-05 13:59:26 +00:00
|
|
|
.Default(Language::Unknown);
|
2017-04-28 01:49:42 +00:00
|
|
|
|
|
|
|
// "objc[++]-cpp-output" is an acceptable synonym for
|
|
|
|
// "objective-c[++]-cpp-output".
|
2021-01-10 13:50:26 +00:00
|
|
|
if (DashX.isUnknown() && Preprocessed && !IsHeaderFile && !ModuleMap &&
|
|
|
|
HUK == InputKind::HeaderUnit_None)
|
2017-04-28 01:49:42 +00:00
|
|
|
DashX = llvm::StringSwitch<InputKind>(XValue)
|
2019-08-05 13:59:26 +00:00
|
|
|
.Case("objc", Language::ObjC)
|
|
|
|
.Case("objc++", Language::ObjCXX)
|
|
|
|
.Default(Language::Unknown);
|
2017-04-28 01:49:42 +00:00
|
|
|
|
|
|
|
// Some special cases cannot be combined with suffixes.
|
2021-01-10 13:50:26 +00:00
|
|
|
if (DashX.isUnknown() && !Preprocessed && !IsHeaderFile && !ModuleMap &&
|
|
|
|
HUK == InputKind::HeaderUnit_None)
|
2017-04-28 01:49:42 +00:00
|
|
|
DashX = llvm::StringSwitch<InputKind>(XValue)
|
2019-08-05 13:59:26 +00:00
|
|
|
.Case("cpp-output", InputKind(Language::C).getPreprocessed())
|
|
|
|
.Case("assembler-with-cpp", Language::Asm)
|
2020-07-13 22:24:44 +02:00
|
|
|
.Cases("ast", "pcm", "precompiled-header",
|
2019-08-05 13:59:26 +00:00
|
|
|
InputKind(Language::Unknown, InputKind::Precompiled))
|
|
|
|
.Case("ir", Language::LLVM_IR)
|
|
|
|
.Default(Language::Unknown);
|
2017-04-28 01:49:42 +00:00
|
|
|
|
2017-04-26 18:57:40 +00:00
|
|
|
if (DashX.isUnknown())
|
2009-12-01 03:16:53 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
2012-11-01 04:30:05 +00:00
|
|
|
<< A->getAsString(Args) << A->getValue();
|
2017-04-26 18:57:40 +00:00
|
|
|
|
2017-04-28 01:49:42 +00:00
|
|
|
if (Preprocessed)
|
2017-04-26 18:57:40 +00:00
|
|
|
DashX = DashX.getPreprocessed();
|
2021-01-10 13:50:26 +00:00
|
|
|
// A regular header is considered mutually exclusive with a header unit.
|
|
|
|
if (HUK != InputKind::HeaderUnit_None) {
|
|
|
|
DashX = DashX.withHeaderUnit(HUK);
|
|
|
|
IsHeaderFile = true;
|
|
|
|
} else if (IsHeaderFile)
|
|
|
|
DashX = DashX.getHeader();
|
2017-04-28 01:49:42 +00:00
|
|
|
if (ModuleMap)
|
|
|
|
DashX = DashX.withFormat(InputKind::ModuleMap);
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// '-' is the default input if none is given.
|
2010-05-20 16:54:55 +00:00
|
|
|
std::vector<std::string> Inputs = Args.getAllArgValues(OPT_INPUT);
|
2009-12-01 03:16:53 +00:00
|
|
|
Opts.Inputs.clear();
|
|
|
|
if (Inputs.empty())
|
|
|
|
Inputs.push_back("-");
|
2021-01-10 13:50:26 +00:00
|
|
|
|
|
|
|
if (DashX.getHeaderUnitKind() != InputKind::HeaderUnit_None &&
|
|
|
|
Inputs.size() > 1)
|
|
|
|
Diags.Report(diag::err_drv_header_unit_extra_inputs) << Inputs[1];
|
|
|
|
|
2009-12-01 03:16:53 +00:00
|
|
|
for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
|
2010-06-07 23:22:09 +00:00
|
|
|
InputKind IK = DashX;
|
2017-04-26 18:57:40 +00:00
|
|
|
if (IK.isUnknown()) {
|
2009-12-01 03:16:53 +00:00
|
|
|
IK = FrontendOptions::getInputKindForExtension(
|
2011-07-23 10:55:15 +00:00
|
|
|
StringRef(Inputs[i]).rsplit('.').second);
|
2017-04-26 18:57:40 +00:00
|
|
|
// FIXME: Warn on this?
|
|
|
|
if (IK.isUnknown())
|
2019-08-05 13:59:26 +00:00
|
|
|
IK = Language::C;
|
2009-12-01 03:16:53 +00:00
|
|
|
// FIXME: Remove this hack.
|
|
|
|
if (i == 0)
|
|
|
|
DashX = IK;
|
|
|
|
}
|
2017-04-28 01:49:42 +00:00
|
|
|
|
2020-02-28 17:31:52 -08:00
|
|
|
bool IsSystem = false;
|
|
|
|
|
2017-04-28 01:49:42 +00:00
|
|
|
// The -emit-module action implicitly takes a module map.
|
|
|
|
if (Opts.ProgramAction == frontend::GenerateModule &&
|
2020-02-28 17:31:52 -08:00
|
|
|
IK.getFormat() == InputKind::Source) {
|
2017-04-28 01:49:42 +00:00
|
|
|
IK = IK.withFormat(InputKind::ModuleMap);
|
2020-02-28 17:31:52 -08:00
|
|
|
IsSystem = Opts.IsSystemModule;
|
|
|
|
}
|
2017-04-28 01:49:42 +00:00
|
|
|
|
2020-02-28 17:31:52 -08:00
|
|
|
Opts.Inputs.emplace_back(std::move(Inputs[i]), IK, IsSystem);
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 15:08:31 +01:00
|
|
|
Opts.DashX = DashX;
|
|
|
|
|
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
2009-12-15 00:06:45 +00:00
|
|
|
std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
|
|
|
|
void *MainAddr) {
|
2014-12-29 21:28:15 +00:00
|
|
|
std::string ClangExecutable =
|
|
|
|
llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
|
2019-01-31 22:15:32 +00:00
|
|
|
return Driver::GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR);
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
|
|
|
|
SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA) {
|
2021-01-27 14:50:09 +01:00
|
|
|
const HeaderSearchOptions *HeaderSearchOpts = &Opts;
|
2021-01-28 10:48:26 +01:00
|
|
|
#define HEADER_SEARCH_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
2021-01-27 14:50:09 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef HEADER_SEARCH_OPTION_WITH_MARSHALLING
|
2021-02-04 09:49:59 +01:00
|
|
|
|
|
|
|
if (Opts.UseLibcxx)
|
|
|
|
GenerateArg(Args, OPT_stdlib_EQ, "libc++", SA);
|
|
|
|
|
|
|
|
if (!Opts.ModuleCachePath.empty())
|
|
|
|
GenerateArg(Args, OPT_fmodules_cache_path, Opts.ModuleCachePath, SA);
|
|
|
|
|
|
|
|
for (const auto &File : Opts.PrebuiltModuleFiles)
|
|
|
|
GenerateArg(Args, OPT_fmodule_file, File.first + "=" + File.second, SA);
|
|
|
|
|
|
|
|
for (const auto &Path : Opts.PrebuiltModulePaths)
|
|
|
|
GenerateArg(Args, OPT_fprebuilt_module_path, Path, SA);
|
|
|
|
|
|
|
|
for (const auto &Macro : Opts.ModulesIgnoreMacros)
|
|
|
|
GenerateArg(Args, OPT_fmodules_ignore_macro, Macro.val(), SA);
|
|
|
|
|
|
|
|
auto Matches = [](const HeaderSearchOptions::Entry &Entry,
|
|
|
|
llvm::ArrayRef<frontend::IncludeDirGroup> Groups,
|
|
|
|
llvm::Optional<bool> IsFramework,
|
|
|
|
llvm::Optional<bool> IgnoreSysRoot) {
|
2021-10-13 20:41:54 -07:00
|
|
|
return llvm::is_contained(Groups, Entry.Group) &&
|
2021-02-04 09:49:59 +01:00
|
|
|
(!IsFramework || (Entry.IsFramework == *IsFramework)) &&
|
|
|
|
(!IgnoreSysRoot || (Entry.IgnoreSysRoot == *IgnoreSysRoot));
|
|
|
|
};
|
|
|
|
|
|
|
|
auto It = Opts.UserEntries.begin();
|
|
|
|
auto End = Opts.UserEntries.end();
|
|
|
|
|
|
|
|
// Add -I..., -F..., and -index-header-map options in order.
|
|
|
|
for (; It < End &&
|
|
|
|
Matches(*It, {frontend::IndexHeaderMap, frontend::Angled}, None, true);
|
|
|
|
++It) {
|
|
|
|
OptSpecifier Opt = [It, Matches]() {
|
|
|
|
if (Matches(*It, frontend::IndexHeaderMap, true, true))
|
|
|
|
return OPT_F;
|
|
|
|
if (Matches(*It, frontend::IndexHeaderMap, false, true))
|
|
|
|
return OPT_I;
|
|
|
|
if (Matches(*It, frontend::Angled, true, true))
|
|
|
|
return OPT_F;
|
|
|
|
if (Matches(*It, frontend::Angled, false, true))
|
|
|
|
return OPT_I;
|
|
|
|
llvm_unreachable("Unexpected HeaderSearchOptions::Entry.");
|
|
|
|
}();
|
|
|
|
|
|
|
|
if (It->Group == frontend::IndexHeaderMap)
|
|
|
|
GenerateArg(Args, OPT_index_header_map, SA);
|
|
|
|
GenerateArg(Args, Opt, It->Path, SA);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Note: some paths that came from "[-iprefix=xx] -iwithprefixbefore=yy" may
|
|
|
|
// have already been generated as "-I[xx]yy". If that's the case, their
|
|
|
|
// position on command line was such that this has no semantic impact on
|
|
|
|
// include paths.
|
|
|
|
for (; It < End &&
|
|
|
|
Matches(*It, {frontend::After, frontend::Angled}, false, true);
|
|
|
|
++It) {
|
|
|
|
OptSpecifier Opt =
|
|
|
|
It->Group == frontend::After ? OPT_iwithprefix : OPT_iwithprefixbefore;
|
|
|
|
GenerateArg(Args, Opt, It->Path, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: Some paths that came from "-idirafter=xxyy" may have already been
|
|
|
|
// generated as "-iwithprefix=xxyy". If that's the case, their position on
|
|
|
|
// command line was such that this has no semantic impact on include paths.
|
|
|
|
for (; It < End && Matches(*It, {frontend::After}, false, true); ++It)
|
|
|
|
GenerateArg(Args, OPT_idirafter, It->Path, SA);
|
|
|
|
for (; It < End && Matches(*It, {frontend::Quoted}, false, true); ++It)
|
|
|
|
GenerateArg(Args, OPT_iquote, It->Path, SA);
|
|
|
|
for (; It < End && Matches(*It, {frontend::System}, false, None); ++It)
|
|
|
|
GenerateArg(Args, It->IgnoreSysRoot ? OPT_isystem : OPT_iwithsysroot,
|
|
|
|
It->Path, SA);
|
|
|
|
for (; It < End && Matches(*It, {frontend::System}, true, true); ++It)
|
|
|
|
GenerateArg(Args, OPT_iframework, It->Path, SA);
|
|
|
|
for (; It < End && Matches(*It, {frontend::System}, true, false); ++It)
|
|
|
|
GenerateArg(Args, OPT_iframeworkwithsysroot, It->Path, SA);
|
|
|
|
|
|
|
|
// Add the paths for the various language specific isystem flags.
|
|
|
|
for (; It < End && Matches(*It, {frontend::CSystem}, false, true); ++It)
|
|
|
|
GenerateArg(Args, OPT_c_isystem, It->Path, SA);
|
|
|
|
for (; It < End && Matches(*It, {frontend::CXXSystem}, false, true); ++It)
|
|
|
|
GenerateArg(Args, OPT_cxx_isystem, It->Path, SA);
|
|
|
|
for (; It < End && Matches(*It, {frontend::ObjCSystem}, false, true); ++It)
|
|
|
|
GenerateArg(Args, OPT_objc_isystem, It->Path, SA);
|
|
|
|
for (; It < End && Matches(*It, {frontend::ObjCXXSystem}, false, true); ++It)
|
|
|
|
GenerateArg(Args, OPT_objcxx_isystem, It->Path, SA);
|
|
|
|
|
|
|
|
// Add the internal paths from a driver that detects standard include paths.
|
|
|
|
// Note: Some paths that came from "-internal-isystem" arguments may have
|
|
|
|
// already been generated as "-isystem". If that's the case, their position on
|
|
|
|
// command line was such that this has no semantic impact on include paths.
|
|
|
|
for (; It < End &&
|
|
|
|
Matches(*It, {frontend::System, frontend::ExternCSystem}, false, true);
|
|
|
|
++It) {
|
|
|
|
OptSpecifier Opt = It->Group == frontend::System
|
|
|
|
? OPT_internal_isystem
|
|
|
|
: OPT_internal_externc_isystem;
|
|
|
|
GenerateArg(Args, Opt, It->Path, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(It == End && "Unhandled HeaderSearchOption::Entry.");
|
|
|
|
|
|
|
|
// Add the path prefixes which are implicitly treated as being system headers.
|
|
|
|
for (const auto &P : Opts.SystemHeaderPrefixes) {
|
|
|
|
OptSpecifier Opt = P.IsSystemHeader ? OPT_system_header_prefix
|
|
|
|
: OPT_no_system_header_prefix;
|
|
|
|
GenerateArg(Args, Opt, P.Prefix, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const std::string &F : Opts.VFSOverlayFiles)
|
|
|
|
GenerateArg(Args, OPT_ivfsoverlay, F, SA);
|
2021-01-27 14:50:09 +01:00
|
|
|
}
|
|
|
|
|
2021-02-04 09:49:59 +01:00
|
|
|
static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
|
2021-01-27 14:34:09 +01:00
|
|
|
DiagnosticsEngine &Diags,
|
2017-03-14 23:07:49 +00:00
|
|
|
const std::string &WorkingDir) {
|
2021-04-16 15:30:28 +02:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
|
|
|
|
2021-01-27 14:34:09 +01:00
|
|
|
HeaderSearchOptions *HeaderSearchOpts = &Opts;
|
|
|
|
|
2021-01-28 10:48:26 +01:00
|
|
|
#define HEADER_SEARCH_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-01-27 14:34:09 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef HEADER_SEARCH_OPTION_WITH_MARSHALLING
|
|
|
|
|
2011-06-21 21:12:29 +00:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ))
|
2012-11-01 04:30:05 +00:00
|
|
|
Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0);
|
2017-03-14 23:07:49 +00:00
|
|
|
|
|
|
|
// Canonicalize -fmodules-cache-path before storing it.
|
|
|
|
SmallString<128> P(Args.getLastArgValue(OPT_fmodules_cache_path));
|
|
|
|
if (!(P.empty() || llvm::sys::path::is_absolute(P))) {
|
|
|
|
if (WorkingDir.empty())
|
|
|
|
llvm::sys::fs::make_absolute(P);
|
|
|
|
else
|
|
|
|
llvm::sys::fs::make_absolute(WorkingDir, P);
|
|
|
|
}
|
|
|
|
llvm::sys::path::remove_dots(P);
|
2020-01-28 20:23:46 +01:00
|
|
|
Opts.ModuleCachePath = std::string(P.str());
|
2017-03-14 23:07:49 +00:00
|
|
|
|
2017-08-31 06:26:43 +00:00
|
|
|
// Only the -fmodule-file=<name>=<file> form.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_fmodule_file)) {
|
2017-08-31 06:26:43 +00:00
|
|
|
StringRef Val = A->getValue();
|
2021-10-19 08:54:02 -07:00
|
|
|
if (Val.contains('=')) {
|
2020-01-29 00:42:56 +01:00
|
|
|
auto Split = Val.split('=');
|
|
|
|
Opts.PrebuiltModuleFiles.insert(
|
|
|
|
{std::string(Split.first), std::string(Split.second)});
|
|
|
|
}
|
2017-08-31 06:26:43 +00:00
|
|
|
}
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_fprebuilt_module_path))
|
2016-08-18 17:42:15 +00:00
|
|
|
Opts.AddPrebuiltModulePath(A->getValue());
|
2014-03-12 00:06:17 +00:00
|
|
|
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_fmodules_ignore_macro)) {
|
2015-06-09 01:57:17 +00:00
|
|
|
StringRef MacroDef = A->getValue();
|
2016-10-21 21:45:01 +00:00
|
|
|
Opts.ModulesIgnoreMacros.insert(
|
|
|
|
llvm::CachedHashString(MacroDef.split('=').first));
|
2013-02-07 00:21:12 +00:00
|
|
|
}
|
|
|
|
|
2011-07-28 04:45:53 +00:00
|
|
|
// Add -I..., -F..., and -index-header-map options in order.
|
|
|
|
bool IsIndexHeaderMap = false;
|
2016-05-06 19:13:55 +00:00
|
|
|
bool IsSysrootSpecified =
|
|
|
|
Args.hasArg(OPT__sysroot_EQ) || Args.hasArg(OPT_isysroot);
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_I, OPT_F, OPT_index_header_map)) {
|
2015-06-09 01:57:17 +00:00
|
|
|
if (A->getOption().matches(OPT_index_header_map)) {
|
2011-07-28 04:45:53 +00:00
|
|
|
// -index-header-map applies to the next -I or -F.
|
|
|
|
IsIndexHeaderMap = true;
|
|
|
|
continue;
|
|
|
|
}
|
2015-06-09 01:57:17 +00:00
|
|
|
|
|
|
|
frontend::IncludeDirGroup Group =
|
|
|
|
IsIndexHeaderMap ? frontend::IndexHeaderMap : frontend::Angled;
|
|
|
|
|
2016-05-06 19:13:55 +00:00
|
|
|
bool IsFramework = A->getOption().matches(OPT_F);
|
|
|
|
std::string Path = A->getValue();
|
|
|
|
|
|
|
|
if (IsSysrootSpecified && !IsFramework && A->getValue()[0] == '=') {
|
|
|
|
SmallString<32> Buffer;
|
|
|
|
llvm::sys::path::append(Buffer, Opts.Sysroot,
|
|
|
|
llvm::StringRef(A->getValue()).substr(1));
|
2020-01-28 20:23:46 +01:00
|
|
|
Path = std::string(Buffer.str());
|
2016-05-06 19:13:55 +00:00
|
|
|
}
|
|
|
|
|
2016-11-02 10:39:27 +00:00
|
|
|
Opts.AddPath(Path, Group, IsFramework,
|
2016-05-06 19:13:55 +00:00
|
|
|
/*IgnoreSysroot*/ true);
|
2011-07-28 04:45:53 +00:00
|
|
|
IsIndexHeaderMap = false;
|
|
|
|
}
|
2009-12-01 03:16:53 +00:00
|
|
|
|
2013-01-25 01:50:34 +00:00
|
|
|
// Add -iprefix/-iwithprefix/-iwithprefixbefore options.
|
2011-07-23 10:55:15 +00:00
|
|
|
StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A :
|
2015-06-09 01:57:17 +00:00
|
|
|
Args.filtered(OPT_iprefix, OPT_iwithprefix, OPT_iwithprefixbefore)) {
|
2010-06-11 22:00:13 +00:00
|
|
|
if (A->getOption().matches(OPT_iprefix))
|
2012-11-01 04:30:05 +00:00
|
|
|
Prefix = A->getValue();
|
2010-06-11 22:00:13 +00:00
|
|
|
else if (A->getOption().matches(OPT_iwithprefix))
|
2015-06-09 01:57:17 +00:00
|
|
|
Opts.AddPath(Prefix.str() + A->getValue(), frontend::After, false, true);
|
2009-12-01 03:16:53 +00:00
|
|
|
else
|
2015-06-09 01:57:17 +00:00
|
|
|
Opts.AddPath(Prefix.str() + A->getValue(), frontend::Angled, false, true);
|
|
|
|
}
|
|
|
|
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_idirafter))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddPath(A->getValue(), frontend::After, false, true);
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_iquote))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddPath(A->getValue(), frontend::Quoted, false, true);
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_isystem, OPT_iwithsysroot))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddPath(A->getValue(), frontend::System, false,
|
|
|
|
!A->getOption().matches(OPT_iwithsysroot));
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_iframework))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddPath(A->getValue(), frontend::System, true, true);
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_iframeworkwithsysroot))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddPath(A->getValue(), frontend::System, /*IsFramework=*/true,
|
|
|
|
/*IgnoreSysRoot=*/false);
|
2017-12-07 23:04:11 +00:00
|
|
|
|
2017-12-07 21:46:26 +00:00
|
|
|
// Add the paths for the various language specific isystem flags.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_c_isystem))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddPath(A->getValue(), frontend::CSystem, false, true);
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_cxx_isystem))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddPath(A->getValue(), frontend::CXXSystem, false, true);
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_objc_isystem))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddPath(A->getValue(), frontend::ObjCSystem, false,true);
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_objcxx_isystem))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddPath(A->getValue(), frontend::ObjCXXSystem, false, true);
|
2017-12-07 23:04:11 +00:00
|
|
|
|
2017-12-07 21:46:26 +00:00
|
|
|
// Add the internal paths from a driver that detects standard include paths.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A :
|
2017-12-07 21:46:26 +00:00
|
|
|
Args.filtered(OPT_internal_isystem, OPT_internal_externc_isystem)) {
|
|
|
|
frontend::IncludeDirGroup Group = frontend::System;
|
|
|
|
if (A->getOption().matches(OPT_internal_externc_isystem))
|
|
|
|
Group = frontend::ExternCSystem;
|
|
|
|
Opts.AddPath(A->getValue(), Group, false, true);
|
|
|
|
}
|
2017-12-07 23:04:11 +00:00
|
|
|
|
2017-12-07 21:46:26 +00:00
|
|
|
// Add the path prefixes which are implicitly treated as being system headers.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A :
|
2017-12-07 21:46:26 +00:00
|
|
|
Args.filtered(OPT_system_header_prefix, OPT_no_system_header_prefix))
|
|
|
|
Opts.AddSystemHeaderPrefix(
|
|
|
|
A->getValue(), A->getOption().matches(OPT_system_header_prefix));
|
2017-12-07 23:04:11 +00:00
|
|
|
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_ivfsoverlay))
|
2017-12-07 21:46:26 +00:00
|
|
|
Opts.AddVFSOverlayFile(A->getValue());
|
2021-02-04 09:49:59 +01:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2021-02-04 09:49:59 +01:00
|
|
|
}
|
|
|
|
|
2017-12-07 21:46:26 +00:00
|
|
|
/// Check if input file kind and language standard are compatible.
|
|
|
|
static bool IsInputCompatibleWithStandard(InputKind IK,
|
|
|
|
const LangStandard &S) {
|
|
|
|
switch (IK.getLanguage()) {
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::Unknown:
|
|
|
|
case Language::LLVM_IR:
|
2017-12-07 21:46:26 +00:00
|
|
|
llvm_unreachable("should not parse language flags for this input");
|
2017-12-07 23:04:11 +00:00
|
|
|
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::C:
|
|
|
|
case Language::ObjC:
|
|
|
|
case Language::RenderScript:
|
|
|
|
return S.getLanguage() == Language::C;
|
2017-12-07 23:04:11 +00:00
|
|
|
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::OpenCL:
|
2021-03-03 19:00:55 +00:00
|
|
|
return S.getLanguage() == Language::OpenCL ||
|
|
|
|
S.getLanguage() == Language::OpenCLCXX;
|
|
|
|
|
|
|
|
case Language::OpenCLCXX:
|
|
|
|
return S.getLanguage() == Language::OpenCLCXX;
|
2017-12-07 23:04:11 +00:00
|
|
|
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::CXX:
|
|
|
|
case Language::ObjCXX:
|
|
|
|
return S.getLanguage() == Language::CXX;
|
2017-04-26 18:57:40 +00:00
|
|
|
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::CUDA:
|
2017-04-26 23:44:33 +00:00
|
|
|
// FIXME: What -std= values should be permitted for CUDA compilations?
|
2019-08-05 13:59:26 +00:00
|
|
|
return S.getLanguage() == Language::CUDA ||
|
|
|
|
S.getLanguage() == Language::CXX;
|
2017-04-26 18:57:40 +00:00
|
|
|
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::HIP:
|
|
|
|
return S.getLanguage() == Language::CXX || S.getLanguage() == Language::HIP;
|
2018-04-25 01:10:37 +00:00
|
|
|
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::Asm:
|
2017-04-26 18:57:40 +00:00
|
|
|
// Accept (and ignore) all -std= values.
|
|
|
|
// FIXME: The -std= value is not ignored; it affects the tokenization
|
|
|
|
// and preprocessing rules if we're preprocessing this asm input.
|
2017-02-14 23:41:38 +00:00
|
|
|
return true;
|
2022-03-28 15:01:41 -05:00
|
|
|
|
|
|
|
case Language::HLSL:
|
|
|
|
return S.getLanguage() == Language::HLSL;
|
2017-02-14 22:44:20 +00:00
|
|
|
}
|
2017-04-26 18:57:40 +00:00
|
|
|
|
|
|
|
llvm_unreachable("unexpected input language");
|
2017-02-14 22:44:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get language name for given input kind.
|
2021-12-28 10:01:39 -08:00
|
|
|
static StringRef GetInputKindName(InputKind IK) {
|
2017-04-26 18:57:40 +00:00
|
|
|
switch (IK.getLanguage()) {
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::C:
|
2017-04-26 23:44:33 +00:00
|
|
|
return "C";
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::ObjC:
|
2017-04-26 23:44:33 +00:00
|
|
|
return "Objective-C";
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::CXX:
|
2017-04-26 23:44:33 +00:00
|
|
|
return "C++";
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::ObjCXX:
|
2017-04-26 23:44:33 +00:00
|
|
|
return "Objective-C++";
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::OpenCL:
|
2017-02-14 22:44:20 +00:00
|
|
|
return "OpenCL";
|
2021-03-03 19:00:55 +00:00
|
|
|
case Language::OpenCLCXX:
|
|
|
|
return "C++ for OpenCL";
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::CUDA:
|
2017-02-14 22:44:20 +00:00
|
|
|
return "CUDA";
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::RenderScript:
|
2017-04-26 23:44:33 +00:00
|
|
|
return "RenderScript";
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::HIP:
|
2018-04-25 01:10:37 +00:00
|
|
|
return "HIP";
|
2017-04-26 23:44:33 +00:00
|
|
|
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::Asm:
|
2017-04-26 23:44:33 +00:00
|
|
|
return "Asm";
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::LLVM_IR:
|
2017-04-26 23:44:33 +00:00
|
|
|
return "LLVM IR";
|
|
|
|
|
2022-03-28 15:01:41 -05:00
|
|
|
case Language::HLSL:
|
|
|
|
return "HLSL";
|
|
|
|
|
2019-08-05 13:59:26 +00:00
|
|
|
case Language::Unknown:
|
2017-04-26 23:44:33 +00:00
|
|
|
break;
|
2017-02-14 22:44:20 +00:00
|
|
|
}
|
2017-04-26 23:44:33 +00:00
|
|
|
llvm_unreachable("unknown input language");
|
2017-02-14 22:44:20 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 10:17:04 +01:00
|
|
|
void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
|
|
|
|
SmallVectorImpl<const char *> &Args,
|
|
|
|
StringAllocator SA,
|
2021-04-16 17:20:04 +02:00
|
|
|
const llvm::Triple &T, InputKind IK) {
|
|
|
|
if (IK.getFormat() == InputKind::Precompiled ||
|
|
|
|
IK.getLanguage() == Language::LLVM_IR) {
|
|
|
|
if (Opts.ObjCAutoRefCount)
|
|
|
|
GenerateArg(Args, OPT_fobjc_arc, SA);
|
|
|
|
if (Opts.PICLevel != 0)
|
|
|
|
GenerateArg(Args, OPT_pic_level, Twine(Opts.PICLevel), SA);
|
|
|
|
if (Opts.PIE)
|
|
|
|
GenerateArg(Args, OPT_pic_is_pie, SA);
|
|
|
|
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
|
|
|
|
GenerateArg(Args, OPT_fsanitize_EQ, Sanitizer, SA);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-09 10:17:04 +01:00
|
|
|
OptSpecifier StdOpt;
|
|
|
|
switch (Opts.LangStd) {
|
|
|
|
case LangStandard::lang_opencl10:
|
|
|
|
case LangStandard::lang_opencl11:
|
|
|
|
case LangStandard::lang_opencl12:
|
|
|
|
case LangStandard::lang_opencl20:
|
|
|
|
case LangStandard::lang_opencl30:
|
2021-07-29 15:10:13 +01:00
|
|
|
case LangStandard::lang_openclcpp10:
|
2021-08-12 16:20:11 +01:00
|
|
|
case LangStandard::lang_openclcpp2021:
|
2021-02-09 10:17:04 +01:00
|
|
|
StdOpt = OPT_cl_std_EQ;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
StdOpt = OPT_std_EQ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto LangStandard = LangStandard::getLangStandardForKind(Opts.LangStd);
|
|
|
|
GenerateArg(Args, StdOpt, LangStandard.getName(), SA);
|
|
|
|
|
2021-01-15 14:47:55 +01:00
|
|
|
if (Opts.IncludeDefaultHeader)
|
2021-02-04 09:49:59 +01:00
|
|
|
GenerateArg(Args, OPT_finclude_default_header, SA);
|
2021-01-15 14:47:55 +01:00
|
|
|
if (Opts.DeclareOpenCLBuiltins)
|
2021-02-04 09:49:59 +01:00
|
|
|
GenerateArg(Args, OPT_fdeclare_opencl_builtins, SA);
|
2021-02-09 10:17:04 +01:00
|
|
|
|
|
|
|
const LangOptions *LangOpts = &Opts;
|
|
|
|
|
|
|
|
#define LANG_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef LANG_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
// The '-fcf-protection=' option is generated by CodeGenOpts generator.
|
|
|
|
|
|
|
|
if (Opts.ObjC) {
|
2021-03-02 13:02:04 +01:00
|
|
|
GenerateArg(Args, OPT_fobjc_runtime_EQ, Opts.ObjCRuntime.getAsString(), SA);
|
2021-02-09 10:17:04 +01:00
|
|
|
|
|
|
|
if (Opts.GC == LangOptions::GCOnly)
|
|
|
|
GenerateArg(Args, OPT_fobjc_gc_only, SA);
|
|
|
|
else if (Opts.GC == LangOptions::HybridGC)
|
|
|
|
GenerateArg(Args, OPT_fobjc_gc, SA);
|
|
|
|
else if (Opts.ObjCAutoRefCount == 1)
|
|
|
|
GenerateArg(Args, OPT_fobjc_arc, SA);
|
|
|
|
|
|
|
|
if (Opts.ObjCWeakRuntime)
|
|
|
|
GenerateArg(Args, OPT_fobjc_runtime_has_weak, SA);
|
|
|
|
|
|
|
|
if (Opts.ObjCWeak)
|
|
|
|
GenerateArg(Args, OPT_fobjc_weak, SA);
|
|
|
|
|
|
|
|
if (Opts.ObjCSubscriptingLegacyRuntime)
|
|
|
|
GenerateArg(Args, OPT_fobjc_subscripting_legacy_runtime, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.GNUCVersion != 0) {
|
|
|
|
unsigned Major = Opts.GNUCVersion / 100 / 100;
|
|
|
|
unsigned Minor = (Opts.GNUCVersion / 100) % 100;
|
|
|
|
unsigned Patch = Opts.GNUCVersion % 100;
|
|
|
|
GenerateArg(Args, OPT_fgnuc_version_EQ,
|
|
|
|
Twine(Major) + "." + Twine(Minor) + "." + Twine(Patch), SA);
|
|
|
|
}
|
|
|
|
|
2021-03-09 10:38:00 -05:00
|
|
|
if (Opts.IgnoreXCOFFVisibility)
|
|
|
|
GenerateArg(Args, OPT_mignore_xcoff_visibility, SA);
|
|
|
|
|
2021-02-09 10:17:04 +01:00
|
|
|
if (Opts.SignedOverflowBehavior == LangOptions::SOB_Trapping) {
|
|
|
|
GenerateArg(Args, OPT_ftrapv, SA);
|
|
|
|
GenerateArg(Args, OPT_ftrapv_handler, Opts.OverflowHandler, SA);
|
|
|
|
} else if (Opts.SignedOverflowBehavior == LangOptions::SOB_Defined) {
|
|
|
|
GenerateArg(Args, OPT_fwrapv, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.MSCompatibilityVersion != 0) {
|
|
|
|
unsigned Major = Opts.MSCompatibilityVersion / 10000000;
|
|
|
|
unsigned Minor = (Opts.MSCompatibilityVersion / 100000) % 100;
|
|
|
|
unsigned Subminor = Opts.MSCompatibilityVersion % 100000;
|
|
|
|
GenerateArg(Args, OPT_fms_compatibility_version,
|
|
|
|
Twine(Major) + "." + Twine(Minor) + "." + Twine(Subminor), SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((!Opts.GNUMode && !Opts.MSVCCompat && !Opts.CPlusPlus17) || T.isOSzOS()) {
|
|
|
|
if (!Opts.Trigraphs)
|
|
|
|
GenerateArg(Args, OPT_fno_trigraphs, SA);
|
|
|
|
} else {
|
|
|
|
if (Opts.Trigraphs)
|
|
|
|
GenerateArg(Args, OPT_ftrigraphs, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.Blocks && !(Opts.OpenCL && Opts.OpenCLVersion == 200))
|
|
|
|
GenerateArg(Args, OPT_fblocks, SA);
|
|
|
|
|
|
|
|
if (Opts.ConvergentFunctions &&
|
|
|
|
!(Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) || Opts.SYCLIsDevice))
|
|
|
|
GenerateArg(Args, OPT_fconvergent_functions, SA);
|
|
|
|
|
|
|
|
if (Opts.NoBuiltin && !Opts.Freestanding)
|
|
|
|
GenerateArg(Args, OPT_fno_builtin, SA);
|
|
|
|
|
2021-02-09 11:42:01 +01:00
|
|
|
if (!Opts.NoBuiltin)
|
|
|
|
for (const auto &Func : Opts.NoBuiltinFuncs)
|
|
|
|
GenerateArg(Args, OPT_fno_builtin_, Func, SA);
|
2021-02-09 10:17:04 +01:00
|
|
|
|
|
|
|
if (Opts.LongDoubleSize == 128)
|
|
|
|
GenerateArg(Args, OPT_mlong_double_128, SA);
|
|
|
|
else if (Opts.LongDoubleSize == 64)
|
|
|
|
GenerateArg(Args, OPT_mlong_double_64, SA);
|
2022-02-14 12:55:43 +08:00
|
|
|
else if (Opts.LongDoubleSize == 80)
|
|
|
|
GenerateArg(Args, OPT_mlong_double_80, SA);
|
2021-02-09 10:17:04 +01:00
|
|
|
|
|
|
|
// Not generating '-mrtd', it's just an alias for '-fdefault-calling-conv='.
|
|
|
|
|
|
|
|
// OpenMP was requested via '-fopenmp', not implied by '-fopenmp-simd' or
|
|
|
|
// '-fopenmp-targets='.
|
|
|
|
if (Opts.OpenMP && !Opts.OpenMPSimd) {
|
|
|
|
GenerateArg(Args, OPT_fopenmp, SA);
|
|
|
|
|
|
|
|
if (Opts.OpenMP != 50)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP), SA);
|
|
|
|
|
|
|
|
if (!Opts.OpenMPUseTLS)
|
|
|
|
GenerateArg(Args, OPT_fnoopenmp_use_tls, SA);
|
|
|
|
|
|
|
|
if (Opts.OpenMPIsDevice)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_is_device, SA);
|
|
|
|
|
|
|
|
if (Opts.OpenMPIRBuilder)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_enable_irbuilder, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Opts.OpenMPSimd) {
|
|
|
|
GenerateArg(Args, OPT_fopenmp_simd, SA);
|
|
|
|
|
|
|
|
if (Opts.OpenMP != 50)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP), SA);
|
|
|
|
}
|
|
|
|
|
2021-10-07 15:43:56 -04:00
|
|
|
if (Opts.OpenMPThreadSubscription)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_assume_threads_oversubscription, SA);
|
|
|
|
|
|
|
|
if (Opts.OpenMPTeamSubscription)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_assume_teams_oversubscription, SA);
|
|
|
|
|
2021-09-09 16:40:59 -04:00
|
|
|
if (Opts.OpenMPTargetDebug != 0)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_target_debug_EQ,
|
|
|
|
Twine(Opts.OpenMPTargetDebug), SA);
|
|
|
|
|
2021-02-09 10:17:04 +01:00
|
|
|
if (Opts.OpenMPCUDANumSMs != 0)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_cuda_number_of_sm_EQ,
|
|
|
|
Twine(Opts.OpenMPCUDANumSMs), SA);
|
|
|
|
|
|
|
|
if (Opts.OpenMPCUDABlocksPerSM != 0)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_cuda_blocks_per_sm_EQ,
|
|
|
|
Twine(Opts.OpenMPCUDABlocksPerSM), SA);
|
|
|
|
|
|
|
|
if (Opts.OpenMPCUDAReductionBufNum != 1024)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_cuda_teams_reduction_recs_num_EQ,
|
|
|
|
Twine(Opts.OpenMPCUDAReductionBufNum), SA);
|
|
|
|
|
|
|
|
if (!Opts.OMPTargetTriples.empty()) {
|
|
|
|
std::string Targets;
|
|
|
|
llvm::raw_string_ostream OS(Targets);
|
|
|
|
llvm::interleave(
|
|
|
|
Opts.OMPTargetTriples, OS,
|
|
|
|
[&OS](const llvm::Triple &T) { OS << T.str(); }, ",");
|
|
|
|
GenerateArg(Args, OPT_fopenmp_targets_EQ, OS.str(), SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Opts.OMPHostIRFile.empty())
|
|
|
|
GenerateArg(Args, OPT_fopenmp_host_ir_file_path, Opts.OMPHostIRFile, SA);
|
|
|
|
|
|
|
|
if (Opts.OpenMPCUDAMode)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_cuda_mode, SA);
|
|
|
|
|
|
|
|
if (Opts.OpenMPCUDAForceFullRuntime)
|
|
|
|
GenerateArg(Args, OPT_fopenmp_cuda_force_full_runtime, SA);
|
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
// The arguments used to set Optimize, OptimizeSize and NoInlineDefine are
|
|
|
|
// generated from CodeGenOptions.
|
2021-02-09 10:17:04 +01:00
|
|
|
|
|
|
|
if (Opts.DefaultFPContractMode == LangOptions::FPM_Fast)
|
|
|
|
GenerateArg(Args, OPT_ffp_contract, "fast", SA);
|
|
|
|
else if (Opts.DefaultFPContractMode == LangOptions::FPM_On)
|
|
|
|
GenerateArg(Args, OPT_ffp_contract, "on", SA);
|
|
|
|
else if (Opts.DefaultFPContractMode == LangOptions::FPM_Off)
|
|
|
|
GenerateArg(Args, OPT_ffp_contract, "off", SA);
|
|
|
|
else if (Opts.DefaultFPContractMode == LangOptions::FPM_FastHonorPragmas)
|
|
|
|
GenerateArg(Args, OPT_ffp_contract, "fast-honor-pragmas", SA);
|
|
|
|
|
|
|
|
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
|
|
|
|
GenerateArg(Args, OPT_fsanitize_EQ, Sanitizer, SA);
|
|
|
|
|
2021-05-04 09:50:43 -04:00
|
|
|
// Conflating '-fsanitize-system-ignorelist' and '-fsanitize-ignorelist'.
|
2021-02-22 14:47:29 -05:00
|
|
|
for (const std::string &F : Opts.NoSanitizeFiles)
|
2021-05-04 09:50:43 -04:00
|
|
|
GenerateArg(Args, OPT_fsanitize_ignorelist_EQ, F, SA);
|
2021-02-09 10:17:04 +01:00
|
|
|
|
|
|
|
if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver3_8)
|
|
|
|
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "3.8", SA);
|
|
|
|
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver4)
|
|
|
|
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "4.0", SA);
|
|
|
|
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver6)
|
|
|
|
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "6.0", SA);
|
|
|
|
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver7)
|
|
|
|
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "7.0", SA);
|
|
|
|
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver9)
|
|
|
|
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "9.0", SA);
|
|
|
|
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver11)
|
|
|
|
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "11.0", SA);
|
2021-05-05 18:56:58 -07:00
|
|
|
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver12)
|
|
|
|
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "12.0", SA);
|
2022-01-18 14:28:14 -08:00
|
|
|
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver13)
|
|
|
|
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "13.0", SA);
|
2022-05-02 18:07:47 +01:00
|
|
|
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver14)
|
|
|
|
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "14.0", SA);
|
2021-02-09 10:17:04 +01:00
|
|
|
|
|
|
|
if (Opts.getSignReturnAddressScope() ==
|
|
|
|
LangOptions::SignReturnAddressScopeKind::All)
|
|
|
|
GenerateArg(Args, OPT_msign_return_address_EQ, "all", SA);
|
|
|
|
else if (Opts.getSignReturnAddressScope() ==
|
|
|
|
LangOptions::SignReturnAddressScopeKind::NonLeaf)
|
|
|
|
GenerateArg(Args, OPT_msign_return_address_EQ, "non-leaf", SA);
|
|
|
|
|
|
|
|
if (Opts.getSignReturnAddressKey() ==
|
|
|
|
LangOptions::SignReturnAddressKeyKind::BKey)
|
|
|
|
GenerateArg(Args, OPT_msign_return_address_key_EQ, "b_key", SA);
|
2021-04-21 15:09:12 -07:00
|
|
|
|
|
|
|
if (Opts.CXXABI)
|
|
|
|
GenerateArg(Args, OPT_fcxx_abi_EQ, TargetCXXABI::getSpelling(*Opts.CXXABI),
|
|
|
|
SA);
|
2021-05-12 10:37:37 -07:00
|
|
|
|
|
|
|
if (Opts.RelativeCXXABIVTables)
|
|
|
|
GenerateArg(Args, OPT_fexperimental_relative_cxx_abi_vtables, SA);
|
|
|
|
else
|
|
|
|
GenerateArg(Args, OPT_fno_experimental_relative_cxx_abi_vtables, SA);
|
2021-08-04 16:42:14 -07:00
|
|
|
|
|
|
|
for (const auto &MP : Opts.MacroPrefixMap)
|
|
|
|
GenerateArg(Args, OPT_fmacro_prefix_map_EQ, MP.first + "=" + MP.second, SA);
|
2022-04-08 23:36:51 -07:00
|
|
|
|
|
|
|
if (!Opts.RandstructSeed.empty())
|
|
|
|
GenerateArg(Args, OPT_frandomize_layout_seed_EQ, Opts.RandstructSeed, SA);
|
2021-01-15 14:47:55 +01:00
|
|
|
}
|
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
|
|
|
InputKind IK, const llvm::Triple &T,
|
|
|
|
std::vector<std::string> &Includes,
|
|
|
|
DiagnosticsEngine &Diags) {
|
2021-02-08 10:38:01 +01:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
|
|
|
|
2021-04-16 17:20:04 +02:00
|
|
|
if (IK.getFormat() == InputKind::Precompiled ||
|
|
|
|
IK.getLanguage() == Language::LLVM_IR) {
|
|
|
|
// ObjCAAutoRefCount and Sanitize LangOpts are used to setup the
|
|
|
|
// PassManager in BackendUtil.cpp. They need to be initialized no matter
|
|
|
|
// what the input type is.
|
|
|
|
if (Args.hasArg(OPT_fobjc_arc))
|
|
|
|
Opts.ObjCAutoRefCount = 1;
|
|
|
|
// PICLevel and PIELevel are needed during code generation and this should
|
|
|
|
// be set regardless of the input type.
|
|
|
|
Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
|
|
|
|
Opts.PIE = Args.hasArg(OPT_pic_is_pie);
|
|
|
|
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
|
|
|
|
Diags, Opts.Sanitize);
|
|
|
|
|
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Other LangOpts are only initialized when the input is not AST or LLVM IR.
|
|
|
|
// FIXME: Should we really be parsing this for an Language::Asm input?
|
|
|
|
|
2010-12-04 01:50:27 +00:00
|
|
|
// FIXME: Cleanup per-file based stuff.
|
|
|
|
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
|
2019-08-05 13:59:26 +00:00
|
|
|
LangStd = LangStandard::getLangKind(A->getValue());
|
2017-02-14 22:44:20 +00:00
|
|
|
if (LangStd == LangStandard::lang_unspecified) {
|
2010-12-04 01:50:27 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
2012-11-01 04:30:05 +00:00
|
|
|
<< A->getAsString(Args) << A->getValue();
|
2017-02-14 22:44:20 +00:00
|
|
|
// Report supported standards with short description.
|
|
|
|
for (unsigned KindValue = 0;
|
|
|
|
KindValue != LangStandard::lang_unspecified;
|
|
|
|
++KindValue) {
|
|
|
|
const LangStandard &Std = LangStandard::getLangStandardForKind(
|
|
|
|
static_cast<LangStandard::Kind>(KindValue));
|
|
|
|
if (IsInputCompatibleWithStandard(IK, Std)) {
|
2017-04-27 01:17:05 +00:00
|
|
|
auto Diag = Diags.Report(diag::note_drv_use_standard);
|
|
|
|
Diag << Std.getName() << Std.getDescription();
|
|
|
|
unsigned NumAliases = 0;
|
|
|
|
#define LANGSTANDARD(id, name, lang, desc, features)
|
|
|
|
#define LANGSTANDARD_ALIAS(id, alias) \
|
|
|
|
if (KindValue == LangStandard::lang_##id) ++NumAliases;
|
|
|
|
#define LANGSTANDARD_ALIAS_DEPR(id, alias)
|
2019-08-05 13:59:26 +00:00
|
|
|
#include "clang/Basic/LangStandards.def"
|
2017-04-27 01:17:05 +00:00
|
|
|
Diag << NumAliases;
|
|
|
|
#define LANGSTANDARD(id, name, lang, desc, features)
|
|
|
|
#define LANGSTANDARD_ALIAS(id, alias) \
|
|
|
|
if (KindValue == LangStandard::lang_##id) Diag << alias;
|
|
|
|
#define LANGSTANDARD_ALIAS_DEPR(id, alias)
|
2019-08-05 13:59:26 +00:00
|
|
|
#include "clang/Basic/LangStandards.def"
|
2017-02-14 22:44:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2013-12-05 16:25:25 +00:00
|
|
|
// Valid standard, check to make sure language and standard are
|
|
|
|
// compatible.
|
2011-05-02 19:24:53 +00:00
|
|
|
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
|
2017-02-14 22:44:20 +00:00
|
|
|
if (!IsInputCompatibleWithStandard(IK, Std)) {
|
|
|
|
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< A->getAsString(Args) << GetInputKindName(IK);
|
2011-05-02 19:24:53 +00:00
|
|
|
}
|
|
|
|
}
|
2010-12-04 01:50:27 +00:00
|
|
|
}
|
|
|
|
|
2012-06-19 23:09:52 +00:00
|
|
|
// -cl-std only applies for OpenCL language standards.
|
|
|
|
// Override the -std option in this case.
|
2010-12-04 01:51:40 +00:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
|
2012-06-19 23:09:52 +00:00
|
|
|
LangStandard::Kind OpenCLLangStd
|
2017-02-14 22:44:20 +00:00
|
|
|
= llvm::StringSwitch<LangStandard::Kind>(A->getValue())
|
2017-04-27 01:17:05 +00:00
|
|
|
.Cases("cl", "CL", LangStandard::lang_opencl10)
|
2020-11-11 16:45:58 +03:00
|
|
|
.Cases("cl1.0", "CL1.0", LangStandard::lang_opencl10)
|
2017-02-14 22:44:20 +00:00
|
|
|
.Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11)
|
|
|
|
.Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12)
|
|
|
|
.Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20)
|
2020-10-09 15:13:39 +01:00
|
|
|
.Cases("cl3.0", "CL3.0", LangStandard::lang_opencl30)
|
2021-07-29 15:10:13 +01:00
|
|
|
.Cases("clc++", "CLC++", LangStandard::lang_openclcpp10)
|
|
|
|
.Cases("clc++1.0", "CLC++1.0", LangStandard::lang_openclcpp10)
|
2021-08-12 16:20:11 +01:00
|
|
|
.Cases("clc++2021", "CLC++2021", LangStandard::lang_openclcpp2021)
|
2017-02-14 22:44:20 +00:00
|
|
|
.Default(LangStandard::lang_unspecified);
|
2015-08-05 15:08:53 +00:00
|
|
|
|
2012-06-19 23:09:52 +00:00
|
|
|
if (OpenCLLangStd == LangStandard::lang_unspecified) {
|
2010-12-04 01:51:40 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
2017-02-14 22:44:20 +00:00
|
|
|
<< A->getAsString(Args) << A->getValue();
|
2010-12-04 01:51:40 +00:00
|
|
|
}
|
2012-06-19 23:09:52 +00:00
|
|
|
else
|
|
|
|
LangStd = OpenCLLangStd;
|
2010-12-04 01:51:40 +00:00
|
|
|
}
|
2015-08-05 15:08:53 +00:00
|
|
|
|
2021-01-15 14:47:55 +01:00
|
|
|
// These need to be parsed now. They are used to set OpenCL defaults.
|
|
|
|
Opts.IncludeDefaultHeader = Args.hasArg(OPT_finclude_default_header);
|
|
|
|
Opts.DeclareOpenCLBuiltins = Args.hasArg(OPT_fdeclare_opencl_builtins);
|
|
|
|
|
2022-04-08 13:23:12 +02:00
|
|
|
LangOptions::setLangDefaults(Opts, IK.getLanguage(), T, Includes, LangStd);
|
2010-12-04 01:50:27 +00:00
|
|
|
|
2021-01-15 17:55:03 +01:00
|
|
|
// The key paths of codegen options defined in Options.td start with
|
|
|
|
// "LangOpts->". Let's provide the expected variable name and type.
|
|
|
|
LangOptions *LangOpts = &Opts;
|
|
|
|
|
2021-01-28 10:48:26 +01:00
|
|
|
#define LANG_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-01-15 17:55:03 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef LANG_OPTION_WITH_MARSHALLING
|
|
|
|
|
2021-01-15 15:43:18 +01:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) {
|
|
|
|
StringRef Name = A->getValue();
|
|
|
|
if (Name == "full" || Name == "branch") {
|
|
|
|
Opts.CFProtectionBranch = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-18 10:32:22 -04:00
|
|
|
if ((Args.hasArg(OPT_fsycl_is_device) || Args.hasArg(OPT_fsycl_is_host)) &&
|
|
|
|
!Args.hasArg(OPT_sycl_std_EQ)) {
|
|
|
|
// If the user supplied -fsycl-is-device or -fsycl-is-host, but failed to
|
|
|
|
// provide -sycl-std=, we want to default it to whatever the default SYCL
|
|
|
|
// version is. I could not find a way to express this with the options
|
|
|
|
// tablegen because we still want this value to be SYCL_None when the user
|
|
|
|
// is not in device or host mode.
|
|
|
|
Opts.setSYCLVersion(LangOptions::SYCL_Default);
|
|
|
|
}
|
|
|
|
|
2018-10-30 20:31:30 +00:00
|
|
|
if (Opts.ObjC) {
|
2012-06-20 06:18:46 +00:00
|
|
|
if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) {
|
2012-11-01 04:30:05 +00:00
|
|
|
StringRef value = arg->getValue();
|
2012-06-20 06:18:46 +00:00
|
|
|
if (Opts.ObjCRuntime.tryParse(value))
|
|
|
|
Diags.Report(diag::err_drv_unknown_objc_runtime) << value;
|
|
|
|
}
|
|
|
|
|
2011-06-15 23:02:42 +00:00
|
|
|
if (Args.hasArg(OPT_fobjc_gc_only))
|
2011-09-13 17:21:33 +00:00
|
|
|
Opts.setGC(LangOptions::GCOnly);
|
2011-06-15 23:02:42 +00:00
|
|
|
else if (Args.hasArg(OPT_fobjc_gc))
|
2011-09-13 17:21:33 +00:00
|
|
|
Opts.setGC(LangOptions::HybridGC);
|
2011-06-15 23:02:42 +00:00
|
|
|
else if (Args.hasArg(OPT_fobjc_arc)) {
|
|
|
|
Opts.ObjCAutoRefCount = 1;
|
2012-08-21 02:47:43 +00:00
|
|
|
if (!Opts.ObjCRuntime.allowsARC())
|
|
|
|
Diags.Report(diag::err_arc_unsupported_on_runtime);
|
Define weak and __weak to mean ARC-style weak references, even in MRC.
Previously, __weak was silently accepted and ignored in MRC mode.
That makes this a potentially source-breaking change that we have to
roll out cautiously. Accordingly, for the time being, actual support
for __weak references in MRC is experimental, and the compiler will
reject attempts to actually form such references. The intent is to
eventually enable the feature by default in all non-GC modes.
(It is, of course, incompatible with ObjC GC's interpretation of
__weak.)
If you like, you can enable this feature with
-Xclang -fobjc-weak
but like any -Xclang option, this option may be removed at any point,
e.g. if/when it is eventually enabled by default.
This patch also enables the use of the ARC __unsafe_unretained qualifier
in MRC. Unlike __weak, this is being enabled immediately. Since
variables are essentially __unsafe_unretained by default in MRC,
the only practical uses are (1) communication and (2) changing the
default behavior of by-value block capture.
As an implementation matter, this means that the ObjC ownership
qualifiers may appear in any ObjC language mode, and so this patch
removes a number of checks for getLangOpts().ObjCAutoRefCount
that were guarding the processing of these qualifiers. I don't
expect this to be a significant drain on performance; it may even
be faster to just check for these qualifiers directly on a type
(since it's probably in a register anyway) than to do N dependent
loads to grab the LangOptions.
rdar://9674298
llvm-svn: 251041
2015-10-22 18:38:17 +00:00
|
|
|
}
|
2012-08-21 02:47:43 +00:00
|
|
|
|
Define weak and __weak to mean ARC-style weak references, even in MRC.
Previously, __weak was silently accepted and ignored in MRC mode.
That makes this a potentially source-breaking change that we have to
roll out cautiously. Accordingly, for the time being, actual support
for __weak references in MRC is experimental, and the compiler will
reject attempts to actually form such references. The intent is to
eventually enable the feature by default in all non-GC modes.
(It is, of course, incompatible with ObjC GC's interpretation of
__weak.)
If you like, you can enable this feature with
-Xclang -fobjc-weak
but like any -Xclang option, this option may be removed at any point,
e.g. if/when it is eventually enabled by default.
This patch also enables the use of the ARC __unsafe_unretained qualifier
in MRC. Unlike __weak, this is being enabled immediately. Since
variables are essentially __unsafe_unretained by default in MRC,
the only practical uses are (1) communication and (2) changing the
default behavior of by-value block capture.
As an implementation matter, this means that the ObjC ownership
qualifiers may appear in any ObjC language mode, and so this patch
removes a number of checks for getLangOpts().ObjCAutoRefCount
that were guarding the processing of these qualifiers. I don't
expect this to be a significant drain on performance; it may even
be faster to just check for these qualifiers directly on a type
(since it's probably in a register anyway) than to do N dependent
loads to grab the LangOptions.
rdar://9674298
llvm-svn: 251041
2015-10-22 18:38:17 +00:00
|
|
|
// ObjCWeakRuntime tracks whether the runtime supports __weak, not
|
|
|
|
// whether the feature is actually enabled. This is predominantly
|
|
|
|
// determined by -fobjc-runtime, but we allow it to be overridden
|
|
|
|
// from the command line for testing purposes.
|
|
|
|
if (Args.hasArg(OPT_fobjc_runtime_has_weak))
|
|
|
|
Opts.ObjCWeakRuntime = 1;
|
|
|
|
else
|
|
|
|
Opts.ObjCWeakRuntime = Opts.ObjCRuntime.allowsWeak();
|
|
|
|
|
|
|
|
// ObjCWeak determines whether __weak is actually enabled.
|
2015-11-05 19:19:56 +00:00
|
|
|
// Note that we allow -fno-objc-weak to disable this even in ARC mode.
|
|
|
|
if (auto weakArg = Args.getLastArg(OPT_fobjc_weak, OPT_fno_objc_weak)) {
|
|
|
|
if (!weakArg->getOption().matches(OPT_fobjc_weak)) {
|
|
|
|
assert(!Opts.ObjCWeak);
|
|
|
|
} else if (Opts.getGC() != LangOptions::NonGC) {
|
Define weak and __weak to mean ARC-style weak references, even in MRC.
Previously, __weak was silently accepted and ignored in MRC mode.
That makes this a potentially source-breaking change that we have to
roll out cautiously. Accordingly, for the time being, actual support
for __weak references in MRC is experimental, and the compiler will
reject attempts to actually form such references. The intent is to
eventually enable the feature by default in all non-GC modes.
(It is, of course, incompatible with ObjC GC's interpretation of
__weak.)
If you like, you can enable this feature with
-Xclang -fobjc-weak
but like any -Xclang option, this option may be removed at any point,
e.g. if/when it is eventually enabled by default.
This patch also enables the use of the ARC __unsafe_unretained qualifier
in MRC. Unlike __weak, this is being enabled immediately. Since
variables are essentially __unsafe_unretained by default in MRC,
the only practical uses are (1) communication and (2) changing the
default behavior of by-value block capture.
As an implementation matter, this means that the ObjC ownership
qualifiers may appear in any ObjC language mode, and so this patch
removes a number of checks for getLangOpts().ObjCAutoRefCount
that were guarding the processing of these qualifiers. I don't
expect this to be a significant drain on performance; it may even
be faster to just check for these qualifiers directly on a type
(since it's probably in a register anyway) than to do N dependent
loads to grab the LangOptions.
rdar://9674298
llvm-svn: 251041
2015-10-22 18:38:17 +00:00
|
|
|
Diags.Report(diag::err_objc_weak_with_gc);
|
2015-11-05 19:19:56 +00:00
|
|
|
} else if (!Opts.ObjCWeakRuntime) {
|
Define weak and __weak to mean ARC-style weak references, even in MRC.
Previously, __weak was silently accepted and ignored in MRC mode.
That makes this a potentially source-breaking change that we have to
roll out cautiously. Accordingly, for the time being, actual support
for __weak references in MRC is experimental, and the compiler will
reject attempts to actually form such references. The intent is to
eventually enable the feature by default in all non-GC modes.
(It is, of course, incompatible with ObjC GC's interpretation of
__weak.)
If you like, you can enable this feature with
-Xclang -fobjc-weak
but like any -Xclang option, this option may be removed at any point,
e.g. if/when it is eventually enabled by default.
This patch also enables the use of the ARC __unsafe_unretained qualifier
in MRC. Unlike __weak, this is being enabled immediately. Since
variables are essentially __unsafe_unretained by default in MRC,
the only practical uses are (1) communication and (2) changing the
default behavior of by-value block capture.
As an implementation matter, this means that the ObjC ownership
qualifiers may appear in any ObjC language mode, and so this patch
removes a number of checks for getLangOpts().ObjCAutoRefCount
that were guarding the processing of these qualifiers. I don't
expect this to be a significant drain on performance; it may even
be faster to just check for these qualifiers directly on a type
(since it's probably in a register anyway) than to do N dependent
loads to grab the LangOptions.
rdar://9674298
llvm-svn: 251041
2015-10-22 18:38:17 +00:00
|
|
|
Diags.Report(diag::err_objc_weak_unsupported);
|
2015-11-05 19:19:56 +00:00
|
|
|
} else {
|
|
|
|
Opts.ObjCWeak = 1;
|
Define weak and __weak to mean ARC-style weak references, even in MRC.
Previously, __weak was silently accepted and ignored in MRC mode.
That makes this a potentially source-breaking change that we have to
roll out cautiously. Accordingly, for the time being, actual support
for __weak references in MRC is experimental, and the compiler will
reject attempts to actually form such references. The intent is to
eventually enable the feature by default in all non-GC modes.
(It is, of course, incompatible with ObjC GC's interpretation of
__weak.)
If you like, you can enable this feature with
-Xclang -fobjc-weak
but like any -Xclang option, this option may be removed at any point,
e.g. if/when it is eventually enabled by default.
This patch also enables the use of the ARC __unsafe_unretained qualifier
in MRC. Unlike __weak, this is being enabled immediately. Since
variables are essentially __unsafe_unretained by default in MRC,
the only practical uses are (1) communication and (2) changing the
default behavior of by-value block capture.
As an implementation matter, this means that the ObjC ownership
qualifiers may appear in any ObjC language mode, and so this patch
removes a number of checks for getLangOpts().ObjCAutoRefCount
that were guarding the processing of these qualifiers. I don't
expect this to be a significant drain on performance; it may even
be faster to just check for these qualifiers directly on a type
(since it's probably in a register anyway) than to do N dependent
loads to grab the LangOptions.
rdar://9674298
llvm-svn: 251041
2015-10-22 18:38:17 +00:00
|
|
|
}
|
2015-11-05 19:19:56 +00:00
|
|
|
} else if (Opts.ObjCAutoRefCount) {
|
|
|
|
Opts.ObjCWeak = Opts.ObjCWeakRuntime;
|
2011-06-15 23:02:42 +00:00
|
|
|
}
|
|
|
|
|
2013-11-01 21:58:17 +00:00
|
|
|
if (Args.hasArg(OPT_fobjc_subscripting_legacy_runtime))
|
|
|
|
Opts.ObjCSubscriptingLegacyRuntime =
|
|
|
|
(Opts.ObjCRuntime.getKind() == ObjCRuntime::FragileMacOSX);
|
2011-06-15 23:02:42 +00:00
|
|
|
}
|
2015-08-05 15:08:53 +00:00
|
|
|
|
Add -fgnuc-version= to control __GNUC__ and other GCC macros
I noticed that compiling on Windows with -fno-ms-compatibility had the
side effect of defining __GNUC__, along with __GNUG__, __GXX_RTTI__, and
a number of other macros for GCC compatibility. This is undesirable and
causes Chromium to do things like mix __attribute__ and __declspec,
which doesn't work. We should have a positive language option to enable
GCC compatibility features so that we can experiment with
-fno-ms-compatibility on Windows. This change adds -fgnuc-version= to be
that option.
My issue aside, users have, for a long time, reported that __GNUC__
doesn't match their expectations in one way or another. We have
encouraged users to migrate code away from this macro, but new code
continues to be written assuming a GCC-only environment. There's really
nothing we can do to stop that. By adding this flag, we can allow them
to choose their own adventure with __GNUC__.
This overlaps a bit with the "GNUMode" language option from -std=gnu*.
The gnu language mode tends to enable non-conforming behaviors that we'd
rather not enable by default, but the we want to set things like
__GXX_RTTI__ by default, so I've kept these separate.
Helps address PR42817
Reviewed By: hans, nickdesaulniers, MaskRay
Differential Revision: https://reviews.llvm.org/D68055
llvm-svn: 374449
2019-10-10 21:04:25 +00:00
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) {
|
|
|
|
// Check that the version has 1 to 3 components and the minor and patch
|
|
|
|
// versions fit in two decimal digits.
|
|
|
|
VersionTuple GNUCVer;
|
|
|
|
bool Invalid = GNUCVer.tryParse(A->getValue());
|
|
|
|
unsigned Major = GNUCVer.getMajor();
|
|
|
|
unsigned Minor = GNUCVer.getMinor().getValueOr(0);
|
|
|
|
unsigned Patch = GNUCVer.getSubminor().getValueOr(0);
|
|
|
|
if (Invalid || GNUCVer.getBuild() || Minor >= 100 || Patch >= 100) {
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << A->getValue();
|
|
|
|
}
|
|
|
|
Opts.GNUCVersion = Major * 100 * 100 + Minor * 100 + Patch;
|
|
|
|
}
|
|
|
|
|
2021-03-09 10:38:00 -05:00
|
|
|
// In AIX OS, the -mignore-xcoff-visibility is enable by default if there is
|
|
|
|
// no -fvisibility=* option.
|
|
|
|
// This is the reason why '-fvisibility' needs to be always generated:
|
|
|
|
// its absence implies '-mignore-xcoff-visibility'.
|
|
|
|
//
|
|
|
|
// Suppose the original cc1 command line does contain '-fvisibility default':
|
|
|
|
// '-mignore-xcoff-visibility' should not be implied.
|
|
|
|
// * If '-fvisibility' is not generated (as most options with default values
|
|
|
|
// don't), its absence would imply '-mignore-xcoff-visibility'. This changes
|
|
|
|
// the command line semantics.
|
|
|
|
// * If '-fvisibility' is generated regardless of its presence and value,
|
|
|
|
// '-mignore-xcoff-visibility' won't be implied and the command line
|
|
|
|
// semantics are kept intact.
|
|
|
|
//
|
|
|
|
// When the original cc1 command line does **not** contain '-fvisibility',
|
|
|
|
// '-mignore-xcoff-visibility' is implied. The generated command line will
|
|
|
|
// contain both '-fvisibility default' and '-mignore-xcoff-visibility' and
|
|
|
|
// subsequent calls to `CreateFromArgs`/`generateCC1CommandLine` will always
|
2021-09-22 18:16:56 -04:00
|
|
|
// produce the same arguments.
|
|
|
|
|
2021-03-09 10:38:00 -05:00
|
|
|
if (T.isOSAIX() && (Args.hasArg(OPT_mignore_xcoff_visibility) ||
|
|
|
|
!Args.hasArg(OPT_fvisibility)))
|
|
|
|
Opts.IgnoreXCOFFVisibility = 1;
|
|
|
|
|
2010-09-17 18:29:54 +00:00
|
|
|
if (Args.hasArg(OPT_ftrapv)) {
|
2010-10-21 03:16:25 +00:00
|
|
|
Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping);
|
2010-09-17 18:29:54 +00:00
|
|
|
// Set the handler, if one is specified.
|
|
|
|
Opts.OverflowHandler =
|
2020-01-28 20:23:46 +01:00
|
|
|
std::string(Args.getLastArgValue(OPT_ftrapv_handler));
|
2010-09-17 18:29:54 +00:00
|
|
|
}
|
2010-06-26 21:25:03 +00:00
|
|
|
else if (Args.hasArg(OPT_fwrapv))
|
2010-10-21 03:16:25 +00:00
|
|
|
Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined);
|
2009-12-01 03:16:53 +00:00
|
|
|
|
2015-03-22 08:39:22 +00:00
|
|
|
Opts.MSCompatibilityVersion = 0;
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_fms_compatibility_version)) {
|
|
|
|
VersionTuple VT;
|
|
|
|
if (VT.tryParse(A->getValue()))
|
|
|
|
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
|
|
|
|
<< A->getValue();
|
|
|
|
Opts.MSCompatibilityVersion = VT.getMajor() * 10000000 +
|
|
|
|
VT.getMinor().getValueOr(0) * 100000 +
|
|
|
|
VT.getSubminor().getValueOr(0);
|
|
|
|
}
|
2014-12-22 18:35:03 +00:00
|
|
|
|
Misc typos fixes in ./lib folder
Summary: Found via `codespell -q 3 -I ../clang-whitelist.txt -L uint,importd,crasher,gonna,cant,ue,ons,orign,ned`
Reviewers: teemperor
Reviewed By: teemperor
Subscribers: teemperor, jholewinski, jvesely, nhaehnle, whisperity, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D55475
llvm-svn: 348755
2018-12-10 12:37:46 +00:00
|
|
|
// Mimicking gcc's behavior, trigraphs are only enabled if -trigraphs
|
2014-12-22 18:35:03 +00:00
|
|
|
// is specified, or -std is set to a conforming mode.
|
|
|
|
// Trigraphs are disabled by default in c++1z onwards.
|
2020-08-13 14:33:04 -04:00
|
|
|
// For z/OS, trigraphs are enabled by default (without regard to the above).
|
|
|
|
Opts.Trigraphs =
|
|
|
|
(!Opts.GNUMode && !Opts.MSVCCompat && !Opts.CPlusPlus17) || T.isOSzOS();
|
2014-12-23 22:32:37 +00:00
|
|
|
Opts.Trigraphs =
|
|
|
|
Args.hasFlag(OPT_ftrigraphs, OPT_fno_trigraphs, Opts.Trigraphs);
|
2009-12-01 03:16:53 +00:00
|
|
|
|
2016-06-14 21:43:01 +00:00
|
|
|
Opts.Blocks = Args.hasArg(OPT_fblocks) || (Opts.OpenCL
|
2018-04-12 14:17:04 +00:00
|
|
|
&& Opts.OpenCLVersion == 200);
|
2017-12-07 23:04:11 +00:00
|
|
|
|
2019-10-26 17:15:10 -07:00
|
|
|
Opts.ConvergentFunctions = Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) ||
|
2020-08-25 17:05:19 +03:00
|
|
|
Opts.SYCLIsDevice ||
|
|
|
|
Args.hasArg(OPT_fconvergent_functions);
|
2019-10-26 17:15:10 -07:00
|
|
|
|
2009-12-01 03:16:53 +00:00
|
|
|
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
|
2016-01-06 14:35:46 +00:00
|
|
|
if (!Opts.NoBuiltin)
|
|
|
|
getAllNoBuiltinFuncValues(Args, Opts.NoBuiltinFuncs);
|
2022-02-14 12:55:43 +08:00
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) {
|
|
|
|
if (A->getOption().matches(options::OPT_mlong_double_64))
|
|
|
|
Opts.LongDoubleSize = 64;
|
|
|
|
else if (A->getOption().matches(options::OPT_mlong_double_80))
|
|
|
|
Opts.LongDoubleSize = 80;
|
|
|
|
else if (A->getOption().matches(options::OPT_mlong_double_128))
|
|
|
|
Opts.LongDoubleSize = 128;
|
|
|
|
else
|
|
|
|
Opts.LongDoubleSize = 0;
|
|
|
|
}
|
2020-05-15 07:30:49 -07:00
|
|
|
if (Opts.FastRelaxedMath)
|
|
|
|
Opts.setDefaultFPContractMode(LangOptions::FPM_Fast);
|
2021-01-10 13:50:26 +00:00
|
|
|
|
2018-09-30 21:41:11 +00:00
|
|
|
llvm::sort(Opts.ModuleFeatures);
|
2014-07-23 15:30:23 +00:00
|
|
|
|
2016-05-18 09:06:38 +00:00
|
|
|
// -mrtd option
|
|
|
|
if (Arg *A = Args.getLastArg(OPT_mrtd)) {
|
|
|
|
if (Opts.getDefaultCallingConv() != LangOptions::DCC_None)
|
|
|
|
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< A->getSpelling() << "-fdefault-calling-conv";
|
|
|
|
else {
|
|
|
|
if (T.getArch() != llvm::Triple::x86)
|
|
|
|
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
|
|
|
<< A->getSpelling() << T.getTriple();
|
|
|
|
else
|
|
|
|
Opts.setDefaultCallingConv(LangOptions::DCC_StdCall);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-09 10:17:04 +01:00
|
|
|
// Check if -fopenmp is specified and set default version to 5.0.
|
|
|
|
Opts.OpenMP = Args.hasArg(OPT_fopenmp) ? 50 : 0;
|
2017-12-29 17:36:15 +00:00
|
|
|
// Check if -fopenmp-simd is specified.
|
2018-05-21 16:40:32 +00:00
|
|
|
bool IsSimdSpecified =
|
|
|
|
Args.hasFlag(options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd,
|
|
|
|
/*Default=*/false);
|
2021-02-01 12:36:43 +01:00
|
|
|
Opts.OpenMPSimd = !Opts.OpenMP && IsSimdSpecified;
|
|
|
|
Opts.OpenMPUseTLS =
|
|
|
|
Opts.OpenMP && !Args.hasArg(options::OPT_fnoopenmp_use_tls);
|
|
|
|
Opts.OpenMPIsDevice =
|
|
|
|
Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_is_device);
|
|
|
|
Opts.OpenMPIRBuilder =
|
|
|
|
Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_enable_irbuilder);
|
2018-07-26 15:17:38 +00:00
|
|
|
bool IsTargetSpecified =
|
|
|
|
Opts.OpenMPIsDevice || Args.hasArg(options::OPT_fopenmp_targets_EQ);
|
2016-01-06 13:42:12 +00:00
|
|
|
|
2021-02-03 20:57:59 -05:00
|
|
|
Opts.ConvergentFunctions = Opts.ConvergentFunctions || Opts.OpenMPIsDevice;
|
|
|
|
|
2017-12-29 17:36:15 +00:00
|
|
|
if (Opts.OpenMP || Opts.OpenMPSimd) {
|
2018-07-26 15:17:38 +00:00
|
|
|
if (int Version = getLastArgIntValue(
|
|
|
|
Args, OPT_fopenmp_version_EQ,
|
2020-06-25 07:01:15 +00:00
|
|
|
(IsSimdSpecified || IsTargetSpecified) ? 50 : Opts.OpenMP, Diags))
|
2016-05-26 11:10:11 +00:00
|
|
|
Opts.OpenMP = Version;
|
|
|
|
// Provide diagnostic when a given target is not expected to be an OpenMP
|
|
|
|
// device or host.
|
|
|
|
if (!Opts.OpenMPIsDevice) {
|
|
|
|
switch (T.getArch()) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
// Add unsupported host targets here:
|
|
|
|
case llvm::Triple::nvptx:
|
|
|
|
case llvm::Triple::nvptx64:
|
2021-01-14 08:26:12 +01:00
|
|
|
Diags.Report(diag::err_drv_omp_host_target_not_supported) << T.str();
|
2016-05-26 11:10:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-02-08 15:59:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[OpenMP] Prevent emission of exception handling code when using OpenMP to offload to NVIDIA devices.
Summary: For the OpenMP toolchain which offloads to NVIDIA GPUs make sure that no exception handling code is emitted.
Reviewers: arpith-jacob, sfantao, caomhin, carlo.bertolli, ABataev, Hahnfeld, hfinkel, tstellar
Reviewed By: ABataev, Hahnfeld
Subscribers: rengolin, Hahnfeld, cfe-commits
Differential Revision: https://reviews.llvm.org/D29904
llvm-svn: 310306
2017-08-07 20:57:59 +00:00
|
|
|
// Set the flag to prevent the implementation from emitting device exception
|
|
|
|
// handling code for those requiring so.
|
[OpenMP][AMDGCN] Support OpenMP offloading for AMDGCN architecture - Part 1
Summary:
Allow AMDGCN as a GPU offloading target for OpenMP during compiler
invocation and allow setting CUDAMode for it.
Originally authored by Greg Rodgers (@gregrodgers).
Reviewers: ronlieb, yaxunl, b-sumner, scchan, JonChesterfield, jdoerfert, sameerds, msearles, hliao, arsenm
Reviewed By: sameerds
Subscribers: sstefan1, jvesely, wdng, arsenm, guansong, dexonsmith, cfe-commits, llvm-commits, gregrodgers
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D79754
2020-05-14 06:09:04 +00:00
|
|
|
if ((Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN())) ||
|
|
|
|
Opts.OpenCLCPlusPlus) {
|
2021-09-09 16:40:59 -04:00
|
|
|
|
[OpenMP] Prevent emission of exception handling code when using OpenMP to offload to NVIDIA devices.
Summary: For the OpenMP toolchain which offloads to NVIDIA GPUs make sure that no exception handling code is emitted.
Reviewers: arpith-jacob, sfantao, caomhin, carlo.bertolli, ABataev, Hahnfeld, hfinkel, tstellar
Reviewed By: ABataev, Hahnfeld
Subscribers: rengolin, Hahnfeld, cfe-commits
Differential Revision: https://reviews.llvm.org/D29904
llvm-svn: 310306
2017-08-07 20:57:59 +00:00
|
|
|
Opts.Exceptions = 0;
|
|
|
|
Opts.CXXExceptions = 0;
|
|
|
|
}
|
2018-11-02 14:54:07 +00:00
|
|
|
if (Opts.OpenMPIsDevice && T.isNVPTX()) {
|
|
|
|
Opts.OpenMPCUDANumSMs =
|
|
|
|
getLastArgIntValue(Args, options::OPT_fopenmp_cuda_number_of_sm_EQ,
|
|
|
|
Opts.OpenMPCUDANumSMs, Diags);
|
|
|
|
Opts.OpenMPCUDABlocksPerSM =
|
|
|
|
getLastArgIntValue(Args, options::OPT_fopenmp_cuda_blocks_per_sm_EQ,
|
|
|
|
Opts.OpenMPCUDABlocksPerSM, Diags);
|
2019-02-20 16:36:22 +00:00
|
|
|
Opts.OpenMPCUDAReductionBufNum = getLastArgIntValue(
|
|
|
|
Args, options::OPT_fopenmp_cuda_teams_reduction_recs_num_EQ,
|
|
|
|
Opts.OpenMPCUDAReductionBufNum, Diags);
|
2018-11-02 14:54:07 +00:00
|
|
|
}
|
[OpenMP] Prevent emission of exception handling code when using OpenMP to offload to NVIDIA devices.
Summary: For the OpenMP toolchain which offloads to NVIDIA GPUs make sure that no exception handling code is emitted.
Reviewers: arpith-jacob, sfantao, caomhin, carlo.bertolli, ABataev, Hahnfeld, hfinkel, tstellar
Reviewed By: ABataev, Hahnfeld
Subscribers: rengolin, Hahnfeld, cfe-commits
Differential Revision: https://reviews.llvm.org/D29904
llvm-svn: 310306
2017-08-07 20:57:59 +00:00
|
|
|
|
2021-09-09 16:40:59 -04:00
|
|
|
// Set the value of the debugging flag used in the new offloading device RTL.
|
|
|
|
// Set either by a specific value or to a default if not specified.
|
|
|
|
if (Opts.OpenMPIsDevice && (Args.hasArg(OPT_fopenmp_target_debug) ||
|
|
|
|
Args.hasArg(OPT_fopenmp_target_debug_EQ))) {
|
2022-02-03 14:43:40 -05:00
|
|
|
Opts.OpenMPTargetDebug = getLastArgIntValue(
|
|
|
|
Args, OPT_fopenmp_target_debug_EQ, Opts.OpenMPTargetDebug, Diags);
|
|
|
|
if (!Opts.OpenMPTargetDebug && Args.hasArg(OPT_fopenmp_target_debug))
|
|
|
|
Opts.OpenMPTargetDebug = 1;
|
2021-09-09 16:40:59 -04:00
|
|
|
}
|
|
|
|
|
2022-02-03 14:43:40 -05:00
|
|
|
if (Opts.OpenMPIsDevice) {
|
2021-10-07 15:43:56 -04:00
|
|
|
if (Args.hasArg(OPT_fopenmp_assume_teams_oversubscription))
|
|
|
|
Opts.OpenMPTeamSubscription = true;
|
|
|
|
if (Args.hasArg(OPT_fopenmp_assume_threads_oversubscription))
|
|
|
|
Opts.OpenMPThreadSubscription = true;
|
|
|
|
}
|
|
|
|
|
2016-01-06 13:42:12 +00:00
|
|
|
// Get the OpenMP target triples if any.
|
2016-06-30 21:22:08 +00:00
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_fopenmp_targets_EQ)) {
|
2020-10-07 14:13:14 -04:00
|
|
|
enum ArchPtrSize { Arch16Bit, Arch32Bit, Arch64Bit };
|
|
|
|
auto getArchPtrSize = [](const llvm::Triple &T) {
|
|
|
|
if (T.isArch16Bit())
|
|
|
|
return Arch16Bit;
|
|
|
|
if (T.isArch32Bit())
|
|
|
|
return Arch32Bit;
|
|
|
|
assert(T.isArch64Bit() && "Expected 64-bit architecture");
|
|
|
|
return Arch64Bit;
|
|
|
|
};
|
2016-01-06 13:42:12 +00:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < A->getNumValues(); ++i) {
|
|
|
|
llvm::Triple TT(A->getValue(i));
|
|
|
|
|
2017-08-07 21:11:10 +00:00
|
|
|
if (TT.getArch() == llvm::Triple::UnknownArch ||
|
2021-01-02 12:17:58 -06:00
|
|
|
!(TT.getArch() == llvm::Triple::aarch64 || TT.isPPC() ||
|
2017-08-07 21:11:10 +00:00
|
|
|
TT.getArch() == llvm::Triple::nvptx ||
|
|
|
|
TT.getArch() == llvm::Triple::nvptx64 ||
|
[OpenMP][AMDGCN] Support OpenMP offloading for AMDGCN architecture - Part 1
Summary:
Allow AMDGCN as a GPU offloading target for OpenMP during compiler
invocation and allow setting CUDAMode for it.
Originally authored by Greg Rodgers (@gregrodgers).
Reviewers: ronlieb, yaxunl, b-sumner, scchan, JonChesterfield, jdoerfert, sameerds, msearles, hliao, arsenm
Reviewed By: sameerds
Subscribers: sstefan1, jvesely, wdng, arsenm, guansong, dexonsmith, cfe-commits, llvm-commits, gregrodgers
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D79754
2020-05-14 06:09:04 +00:00
|
|
|
TT.getArch() == llvm::Triple::amdgcn ||
|
2017-08-07 21:11:10 +00:00
|
|
|
TT.getArch() == llvm::Triple::x86 ||
|
|
|
|
TT.getArch() == llvm::Triple::x86_64))
|
2018-03-26 21:45:04 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_omp_target) << A->getValue(i);
|
2020-10-07 14:13:14 -04:00
|
|
|
else if (getArchPtrSize(T) != getArchPtrSize(TT))
|
|
|
|
Diags.Report(diag::err_drv_incompatible_omp_arch)
|
|
|
|
<< A->getValue(i) << T.str();
|
2016-01-06 13:42:12 +00:00
|
|
|
else
|
|
|
|
Opts.OMPTargetTriples.push_back(TT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-01 12:36:43 +01:00
|
|
|
// Get OpenMP host file path if any and report if a non existent file is
|
|
|
|
// found
|
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_fopenmp_host_ir_file_path)) {
|
|
|
|
Opts.OMPHostIRFile = A->getValue();
|
|
|
|
if (!llvm::sys::fs::exists(Opts.OMPHostIRFile))
|
|
|
|
Diags.Report(diag::err_drv_omp_host_ir_file_not_found)
|
|
|
|
<< Opts.OMPHostIRFile;
|
|
|
|
}
|
|
|
|
|
[OpenMP][AMDGCN] Support OpenMP offloading for AMDGCN architecture - Part 1
Summary:
Allow AMDGCN as a GPU offloading target for OpenMP during compiler
invocation and allow setting CUDAMode for it.
Originally authored by Greg Rodgers (@gregrodgers).
Reviewers: ronlieb, yaxunl, b-sumner, scchan, JonChesterfield, jdoerfert, sameerds, msearles, hliao, arsenm
Reviewed By: sameerds
Subscribers: sstefan1, jvesely, wdng, arsenm, guansong, dexonsmith, cfe-commits, llvm-commits, gregrodgers
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D79754
2020-05-14 06:09:04 +00:00
|
|
|
// Set CUDA mode for OpenMP target NVPTX/AMDGCN if specified in options
|
|
|
|
Opts.OpenMPCUDAMode = Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN()) &&
|
2018-02-28 20:48:35 +00:00
|
|
|
Args.hasArg(options::OPT_fopenmp_cuda_mode);
|
|
|
|
|
[OpenMP][AMDGCN] Support OpenMP offloading for AMDGCN architecture - Part 1
Summary:
Allow AMDGCN as a GPU offloading target for OpenMP during compiler
invocation and allow setting CUDAMode for it.
Originally authored by Greg Rodgers (@gregrodgers).
Reviewers: ronlieb, yaxunl, b-sumner, scchan, JonChesterfield, jdoerfert, sameerds, msearles, hliao, arsenm
Reviewed By: sameerds
Subscribers: sstefan1, jvesely, wdng, arsenm, guansong, dexonsmith, cfe-commits, llvm-commits, gregrodgers
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D79754
2020-05-14 06:09:04 +00:00
|
|
|
// Set CUDA mode for OpenMP target NVPTX/AMDGCN if specified in options
|
2018-08-30 14:45:24 +00:00
|
|
|
Opts.OpenMPCUDAForceFullRuntime =
|
[OpenMP][AMDGCN] Support OpenMP offloading for AMDGCN architecture - Part 1
Summary:
Allow AMDGCN as a GPU offloading target for OpenMP during compiler
invocation and allow setting CUDAMode for it.
Originally authored by Greg Rodgers (@gregrodgers).
Reviewers: ronlieb, yaxunl, b-sumner, scchan, JonChesterfield, jdoerfert, sameerds, msearles, hliao, arsenm
Reviewed By: sameerds
Subscribers: sstefan1, jvesely, wdng, arsenm, guansong, dexonsmith, cfe-commits, llvm-commits, gregrodgers
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D79754
2020-05-14 06:09:04 +00:00
|
|
|
Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN()) &&
|
2018-08-30 14:45:24 +00:00
|
|
|
Args.hasArg(options::OPT_fopenmp_cuda_force_full_runtime);
|
|
|
|
|
2009-12-01 03:16:53 +00:00
|
|
|
// FIXME: Eliminate this dependency.
|
2012-08-08 16:09:15 +00:00
|
|
|
unsigned Opt = getOptimizationLevel(Args, IK, Diags),
|
2013-04-10 21:30:03 +00:00
|
|
|
OptSize = getOptimizationLevelSize(Args);
|
2009-12-01 03:16:53 +00:00
|
|
|
Opts.Optimize = Opt != 0;
|
2012-08-08 16:09:15 +00:00
|
|
|
Opts.OptimizeSize = OptSize != 0;
|
2009-12-01 03:16:53 +00:00
|
|
|
|
|
|
|
// This is the __NO_INLINE__ define, which just depends on things like the
|
|
|
|
// optimization level and -fno-inline, not actually whether the backend has
|
|
|
|
// inlining enabled.
|
Cleanup the handling of noinline function attributes, -fno-inline,
-fno-inline-functions, -O0, and optnone.
These were really, really tangled together:
- We used the noinline LLVM attribute for -fno-inline
- But not for -fno-inline-functions (breaking LTO)
- But we did use it for -finline-hint-functions (yay, LTO is happy!)
- But we didn't for -O0 (LTO is sad yet again...)
- We had weird structuring of CodeGenOpts with both an inlining
enumeration and a boolean. They interacted in weird ways and
needlessly.
- A *lot* of set smashing went on with setting these, and then got worse
when we considered optnone and other inlining-effecting attributes.
- A bunch of inline affecting attributes were managed in a completely
different place from -fno-inline.
- Even with -fno-inline we failed to put the LLVM noinline attribute
onto many generated function definitions because they didn't show up
as AST-level functions.
- If you passed -O0 but -finline-functions we would run the normal
inliner pass in LLVM despite it being in the O0 pipeline, which really
doesn't make much sense.
- Lastly, we used things like '-fno-inline' to manipulate the pass
pipeline which forced the pass pipeline to be much more
parameterizable than it really needs to be. Instead we can *just* use
the optimization level to select a pipeline and control the rest via
attributes.
Sadly, this causes a bunch of churn in tests because we don't run the
optimizer in the tests and check the contents of attribute sets. It
would be awesome if attribute sets were a bit more FileCheck friendly,
but oh well.
I think this is a significant improvement and should remove the semantic
need to change what inliner pass we run in order to comply with the
requested inlining semantics by relying completely on attributes. It
also cleans up tho optnone and related handling a bit.
One unfortunate aspect of this is that for generating alwaysinline
routines like those in OpenMP we end up removing noinline and then
adding alwaysinline. I tried a bunch of other approaches, but because we
recompute function attributes from scratch and don't have a declaration
here I couldn't find anything substantially cleaner than this.
Differential Revision: https://reviews.llvm.org/D28053
llvm-svn: 290398
2016-12-23 01:24:49 +00:00
|
|
|
Opts.NoInlineDefine = !Opts.Optimize;
|
|
|
|
if (Arg *InlineArg = Args.getLastArg(
|
|
|
|
options::OPT_finline_functions, options::OPT_finline_hint_functions,
|
|
|
|
options::OPT_fno_inline_functions, options::OPT_fno_inline))
|
|
|
|
if (InlineArg->getOption().matches(options::OPT_fno_inline))
|
|
|
|
Opts.NoInlineDefine = true;
|
2009-12-01 03:16:53 +00:00
|
|
|
|
2017-03-29 21:54:24 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
|
|
|
|
StringRef Val = A->getValue();
|
|
|
|
if (Val == "fast")
|
2020-05-04 10:48:12 -07:00
|
|
|
Opts.setDefaultFPContractMode(LangOptions::FPM_Fast);
|
2017-03-29 21:54:24 +00:00
|
|
|
else if (Val == "on")
|
2020-05-04 10:48:12 -07:00
|
|
|
Opts.setDefaultFPContractMode(LangOptions::FPM_On);
|
2017-03-29 21:54:24 +00:00
|
|
|
else if (Val == "off")
|
2020-05-04 10:48:12 -07:00
|
|
|
Opts.setDefaultFPContractMode(LangOptions::FPM_Off);
|
[HIP] Fix regressions due to fp contract change
Recently HIP toolchain made a change to use clang instead of opt/llc to do compilation
(https://reviews.llvm.org/D81861). The intention is to make HIP toolchain canonical like
other toolchains.
However, this change introduced an unintentional change regarding backend fp fuse
option, which caused regressions in some HIP applications.
Basically before the change, HIP toolchain used clang to generate bitcode, then use
opt/llc to optimize bitcode and generate ISA. As such, the amdgpu backend takes
the default fp fuse mode which is 'Standard'. This mode respect contract flag of
fmul/fadd instructions and do not fuse fmul/fadd instructions without contract flag.
However, after the change, HIP toolchain now use clang to generate IR, do optimization,
and generate ISA as one process. Now amdgpu backend fp fuse option is determined
by -ffp-contract option, which is 'fast' by default. And this -ffp-contract=fast language option
is translated to 'Fast' fp fuse option in backend. Suddenly backend starts to fuse fmul/fadd
instructions without contract flag.
This causes wrong result for some device library functions, e.g. tan(-1e20), which should
return 0.8446, now returns -0.933. What is worse is that since backend with 'Fast' fp fuse
option does not respect contract flag, there is no way to use #pragma clang fp contract
directive to enforce fp contract requirements.
This patch fixes the regression by introducing a new value 'fast-honor-pragmas' for -ffp-contract
and use it for HIP by default. 'fast-honor-pragmas' is equivalent to 'fast' in frontend but
let the backend to use 'Standard' fp fuse option. 'fast-honor-pragmas' is useful since 'Fast'
fp fuse option in backend does not honor contract flag, it is of little use to HIP
applications since all code with #pragma STDC FP_CONTRACT or any IR from a
source compiled with -ffp-contract=on is broken.
Differential Revision: https://reviews.llvm.org/D90174
2020-10-23 16:24:48 -04:00
|
|
|
else if (Val == "fast-honor-pragmas")
|
|
|
|
Opts.setDefaultFPContractMode(LangOptions::FPM_FastHonorPragmas);
|
2017-03-29 21:54:24 +00:00
|
|
|
else
|
|
|
|
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
|
|
|
|
}
|
|
|
|
|
2012-11-05 22:04:41 +00:00
|
|
|
// Parse -fsanitize= arguments.
|
Reimplement -fsanitize-recover family of flags.
Introduce the following -fsanitize-recover flags:
- -fsanitize-recover=<list>: Enable recovery for selected checks or
group of checks. It is forbidden to explicitly list unrecoverable
sanitizers here (that is, "address", "unreachable", "return").
- -fno-sanitize-recover=<list>: Disable recovery for selected checks or
group of checks.
- -f(no-)?sanitize-recover is now a synonym for
-f(no-)?sanitize-recover=undefined,integer and will soon be deprecated.
These flags are parsed left to right, and mask of "recoverable"
sanitizer is updated accordingly, much like what we do for -fsanitize= flags.
-fsanitize= and -fsanitize-recover= flag families are independent.
CodeGen change: If there is a single UBSan handler function, responsible
for implementing multiple checks, which have different recoverable setting,
then we emit two handler calls instead of one:
the first one for the set of "unrecoverable" checks, another one - for
set of "recoverable" checks. If all checks implemented by a handler have the
same recoverability setting, then the generated code will be the same.
llvm-svn: 225719
2015-01-12 22:39:12 +00:00
|
|
|
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
|
|
|
|
Diags, Opts.Sanitize);
|
2021-05-04 09:50:43 -04:00
|
|
|
Opts.NoSanitizeFiles = Args.getAllArgValues(OPT_fsanitize_ignorelist_EQ);
|
|
|
|
std::vector<std::string> systemIgnorelists =
|
|
|
|
Args.getAllArgValues(OPT_fsanitize_system_ignorelist_EQ);
|
2021-02-22 14:47:29 -05:00
|
|
|
Opts.NoSanitizeFiles.insert(Opts.NoSanitizeFiles.end(),
|
2021-05-04 09:50:43 -04:00
|
|
|
systemIgnorelists.begin(),
|
|
|
|
systemIgnorelists.end());
|
2017-03-30 00:29:36 +00:00
|
|
|
|
2018-03-28 21:13:14 +00:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) {
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Latest);
|
|
|
|
|
|
|
|
StringRef Ver = A->getValue();
|
|
|
|
std::pair<StringRef, StringRef> VerParts = Ver.split('.');
|
|
|
|
unsigned Major, Minor = 0;
|
|
|
|
|
|
|
|
// Check the version number is valid: either 3.x (0 <= x <= 9) or
|
|
|
|
// y or y.0 (4 <= y <= current version).
|
|
|
|
if (!VerParts.first.startswith("0") &&
|
|
|
|
!VerParts.first.getAsInteger(10, Major) &&
|
|
|
|
3 <= Major && Major <= CLANG_VERSION_MAJOR &&
|
|
|
|
(Major == 3 ? VerParts.second.size() == 1 &&
|
|
|
|
!VerParts.second.getAsInteger(10, Minor)
|
|
|
|
: VerParts.first.size() == Ver.size() ||
|
|
|
|
VerParts.second == "0")) {
|
|
|
|
// Got a valid version number.
|
|
|
|
if (Major == 3 && Minor <= 8)
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8);
|
|
|
|
else if (Major <= 4)
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Ver4);
|
2018-04-02 18:29:44 +00:00
|
|
|
else if (Major <= 6)
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Ver6);
|
2018-10-26 19:26:45 +00:00
|
|
|
else if (Major <= 7)
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Ver7);
|
2019-09-06 06:02:13 +00:00
|
|
|
else if (Major <= 9)
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Ver9);
|
2020-10-19 18:17:34 -07:00
|
|
|
else if (Major <= 11)
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Ver11);
|
2021-05-05 18:56:58 -07:00
|
|
|
else if (Major <= 12)
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Ver12);
|
2022-01-18 14:28:14 -08:00
|
|
|
else if (Major <= 13)
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Ver13);
|
2022-05-02 18:07:47 +01:00
|
|
|
else if (Major <= 14)
|
|
|
|
Opts.setClangABICompat(LangOptions::ClangABI::Ver14);
|
2018-03-28 21:13:14 +00:00
|
|
|
} else if (Ver != "latest") {
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << A->getValue();
|
|
|
|
}
|
|
|
|
}
|
2018-05-30 03:40:04 +00:00
|
|
|
|
2020-04-02 10:11:01 +02:00
|
|
|
if (Arg *A = Args.getLastArg(OPT_msign_return_address_EQ)) {
|
|
|
|
StringRef SignScope = A->getValue();
|
|
|
|
|
2021-06-23 14:52:36 +03:00
|
|
|
if (SignScope.equals_insensitive("none"))
|
2020-04-02 10:11:01 +02:00
|
|
|
Opts.setSignReturnAddressScope(
|
|
|
|
LangOptions::SignReturnAddressScopeKind::None);
|
2021-06-23 14:52:36 +03:00
|
|
|
else if (SignScope.equals_insensitive("all"))
|
2020-04-02 10:11:01 +02:00
|
|
|
Opts.setSignReturnAddressScope(
|
|
|
|
LangOptions::SignReturnAddressScopeKind::All);
|
2021-06-23 14:52:36 +03:00
|
|
|
else if (SignScope.equals_insensitive("non-leaf"))
|
2020-04-02 10:11:01 +02:00
|
|
|
Opts.setSignReturnAddressScope(
|
|
|
|
LangOptions::SignReturnAddressScopeKind::NonLeaf);
|
|
|
|
else
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << SignScope;
|
|
|
|
|
|
|
|
if (Arg *A = Args.getLastArg(OPT_msign_return_address_key_EQ)) {
|
|
|
|
StringRef SignKey = A->getValue();
|
|
|
|
if (!SignScope.empty() && !SignKey.empty()) {
|
2021-06-23 14:52:36 +03:00
|
|
|
if (SignKey.equals_insensitive("a_key"))
|
2020-04-02 10:11:01 +02:00
|
|
|
Opts.setSignReturnAddressKey(
|
|
|
|
LangOptions::SignReturnAddressKeyKind::AKey);
|
2021-06-23 14:52:36 +03:00
|
|
|
else if (SignKey.equals_insensitive("b_key"))
|
2020-04-02 10:11:01 +02:00
|
|
|
Opts.setSignReturnAddressKey(
|
|
|
|
LangOptions::SignReturnAddressKeyKind::BKey);
|
|
|
|
else
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << SignKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-08 10:38:01 +01:00
|
|
|
|
2021-04-21 15:09:12 -07:00
|
|
|
// The value can be empty, which indicates the system default should be used.
|
|
|
|
StringRef CXXABI = Args.getLastArgValue(OPT_fcxx_abi_EQ);
|
|
|
|
if (!CXXABI.empty()) {
|
|
|
|
if (!TargetCXXABI::isABI(CXXABI)) {
|
|
|
|
Diags.Report(diag::err_invalid_cxx_abi) << CXXABI;
|
|
|
|
} else {
|
|
|
|
auto Kind = TargetCXXABI::getKind(CXXABI);
|
|
|
|
if (!TargetCXXABI::isSupportedCXXABI(T, Kind))
|
|
|
|
Diags.Report(diag::err_unsupported_cxx_abi) << CXXABI << T.str();
|
|
|
|
else
|
|
|
|
Opts.CXXABI = Kind;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-12 10:37:37 -07:00
|
|
|
Opts.RelativeCXXABIVTables =
|
|
|
|
Args.hasFlag(options::OPT_fexperimental_relative_cxx_abi_vtables,
|
|
|
|
options::OPT_fno_experimental_relative_cxx_abi_vtables,
|
|
|
|
TargetCXXABI::usesRelativeVTables(T));
|
|
|
|
|
2021-08-04 16:42:14 -07:00
|
|
|
for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) {
|
|
|
|
auto Split = StringRef(A).split('=');
|
|
|
|
Opts.MacroPrefixMap.insert(
|
|
|
|
{std::string(Split.first), std::string(Split.second)});
|
|
|
|
}
|
|
|
|
|
2021-12-07 09:20:42 +00:00
|
|
|
// Error if -mvscale-min is unbounded.
|
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_mvscale_min_EQ)) {
|
|
|
|
unsigned VScaleMin;
|
|
|
|
if (StringRef(A->getValue()).getAsInteger(10, VScaleMin) || VScaleMin == 0)
|
|
|
|
Diags.Report(diag::err_cc1_unbounded_vscale_min);
|
|
|
|
}
|
|
|
|
|
2022-04-08 23:36:51 -07:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_frandomize_layout_seed_file_EQ)) {
|
|
|
|
std::ifstream SeedFile(A->getValue(0));
|
|
|
|
|
|
|
|
if (!SeedFile.is_open())
|
|
|
|
Diags.Report(diag::err_drv_cannot_open_randomize_layout_seed_file)
|
|
|
|
<< A->getValue(0);
|
|
|
|
|
|
|
|
std::getline(SeedFile, Opts.RandstructSeed);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_frandomize_layout_seed_EQ))
|
|
|
|
Opts.RandstructSeed = A->getValue(0);
|
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
2017-06-16 20:13:39 +00:00
|
|
|
static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
|
|
|
|
switch (Action) {
|
|
|
|
case frontend::ASTDeclList:
|
|
|
|
case frontend::ASTDump:
|
|
|
|
case frontend::ASTPrint:
|
|
|
|
case frontend::ASTView:
|
|
|
|
case frontend::EmitAssembly:
|
|
|
|
case frontend::EmitBC:
|
|
|
|
case frontend::EmitHTML:
|
|
|
|
case frontend::EmitLLVM:
|
|
|
|
case frontend::EmitLLVMOnly:
|
|
|
|
case frontend::EmitCodeGenOnly:
|
|
|
|
case frontend::EmitObj:
|
2022-01-20 10:30:56 -08:00
|
|
|
case frontend::ExtractAPI:
|
2017-06-16 20:13:39 +00:00
|
|
|
case frontend::FixIt:
|
|
|
|
case frontend::GenerateModule:
|
|
|
|
case frontend::GenerateModuleInterface:
|
2018-09-15 01:21:15 +00:00
|
|
|
case frontend::GenerateHeaderModule:
|
2020-09-20 09:29:14 +01:00
|
|
|
case frontend::GenerateHeaderUnit:
|
2017-06-16 20:13:39 +00:00
|
|
|
case frontend::GeneratePCH:
|
2020-03-28 04:08:27 -04:00
|
|
|
case frontend::GenerateInterfaceStubs:
|
2017-06-16 20:13:39 +00:00
|
|
|
case frontend::ParseSyntaxOnly:
|
|
|
|
case frontend::ModuleFileInfo:
|
|
|
|
case frontend::VerifyPCH:
|
|
|
|
case frontend::PluginAction:
|
|
|
|
case frontend::RewriteObjC:
|
|
|
|
case frontend::RewriteTest:
|
|
|
|
case frontend::RunAnalysis:
|
2018-02-10 14:04:45 +00:00
|
|
|
case frontend::TemplightDump:
|
2017-06-16 20:13:39 +00:00
|
|
|
case frontend::MigrateSource:
|
|
|
|
return false;
|
|
|
|
|
2018-05-31 13:57:09 +00:00
|
|
|
case frontend::DumpCompilerOptions:
|
2017-06-16 20:13:39 +00:00
|
|
|
case frontend::DumpRawTokens:
|
|
|
|
case frontend::DumpTokens:
|
|
|
|
case frontend::InitOnly:
|
|
|
|
case frontend::PrintPreamble:
|
|
|
|
case frontend::PrintPreprocessedInput:
|
|
|
|
case frontend::RewriteMacros:
|
|
|
|
case frontend::RunPreprocessorOnly:
|
2019-06-03 22:59:17 +00:00
|
|
|
case frontend::PrintDependencyDirectivesSourceMinimizerOutput:
|
2017-06-16 20:13:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
llvm_unreachable("invalid frontend action");
|
|
|
|
}
|
|
|
|
|
2021-02-08 09:27:17 +01:00
|
|
|
static void GeneratePreprocessorArgs(PreprocessorOptions &Opts,
|
|
|
|
SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA,
|
|
|
|
const LangOptions &LangOpts,
|
|
|
|
const FrontendOptions &FrontendOpts,
|
|
|
|
const CodeGenOptions &CodeGenOpts) {
|
|
|
|
PreprocessorOptions *PreprocessorOpts = &Opts;
|
|
|
|
|
|
|
|
#define PREPROCESSOR_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef PREPROCESSOR_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
if (Opts.PCHWithHdrStop && !Opts.PCHWithHdrStopCreate)
|
|
|
|
GenerateArg(Args, OPT_pch_through_hdrstop_use, SA);
|
|
|
|
|
|
|
|
for (const auto &D : Opts.DeserializedPCHDeclsToErrorOn)
|
|
|
|
GenerateArg(Args, OPT_error_on_deserialized_pch_decl, D, SA);
|
|
|
|
|
|
|
|
if (Opts.PrecompiledPreambleBytes != std::make_pair(0u, false))
|
|
|
|
GenerateArg(Args, OPT_preamble_bytes_EQ,
|
|
|
|
Twine(Opts.PrecompiledPreambleBytes.first) + "," +
|
|
|
|
(Opts.PrecompiledPreambleBytes.second ? "1" : "0"),
|
|
|
|
SA);
|
|
|
|
|
|
|
|
for (const auto &M : Opts.Macros) {
|
|
|
|
// Don't generate __CET__ macro definitions. They are implied by the
|
|
|
|
// -fcf-protection option that is generated elsewhere.
|
|
|
|
if (M.first == "__CET__=1" && !M.second &&
|
|
|
|
!CodeGenOpts.CFProtectionReturn && CodeGenOpts.CFProtectionBranch)
|
|
|
|
continue;
|
|
|
|
if (M.first == "__CET__=2" && !M.second && CodeGenOpts.CFProtectionReturn &&
|
|
|
|
!CodeGenOpts.CFProtectionBranch)
|
|
|
|
continue;
|
|
|
|
if (M.first == "__CET__=3" && !M.second && CodeGenOpts.CFProtectionReturn &&
|
|
|
|
CodeGenOpts.CFProtectionBranch)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
GenerateArg(Args, M.second ? OPT_U : OPT_D, M.first, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &I : Opts.Includes) {
|
|
|
|
// Don't generate OpenCL includes. They are implied by other flags that are
|
|
|
|
// generated elsewhere.
|
|
|
|
if (LangOpts.OpenCL && LangOpts.IncludeDefaultHeader &&
|
|
|
|
((LangOpts.DeclareOpenCLBuiltins && I == "opencl-c-base.h") ||
|
|
|
|
I == "opencl-c.h"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
GenerateArg(Args, OPT_include, I, SA);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &CI : Opts.ChainedIncludes)
|
|
|
|
GenerateArg(Args, OPT_chain_include, CI, SA);
|
|
|
|
|
|
|
|
for (const auto &RF : Opts.RemappedFiles)
|
|
|
|
GenerateArg(Args, OPT_remap_file, RF.first + ";" + RF.second, SA);
|
|
|
|
|
|
|
|
// Don't handle LexEditorPlaceholders. It is implied by the action that is
|
|
|
|
// generated elsewhere.
|
|
|
|
}
|
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
static bool ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
|
|
|
|
DiagnosticsEngine &Diags,
|
|
|
|
frontend::ActionKind Action,
|
|
|
|
const FrontendOptions &FrontendOpts) {
|
2021-04-16 15:30:28 +02:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
|
|
|
|
2021-02-08 09:27:17 +01:00
|
|
|
PreprocessorOptions *PreprocessorOpts = &Opts;
|
|
|
|
|
|
|
|
#define PREPROCESSOR_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-02-08 09:27:17 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef PREPROCESSOR_OPTION_WITH_MARSHALLING
|
|
|
|
|
2018-09-11 17:10:44 +00:00
|
|
|
Opts.PCHWithHdrStop = Args.hasArg(OPT_pch_through_hdrstop_create) ||
|
|
|
|
Args.hasArg(OPT_pch_through_hdrstop_use);
|
2010-10-14 20:14:25 +00:00
|
|
|
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl))
|
2012-11-01 04:30:05 +00:00
|
|
|
Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue());
|
2010-07-27 00:27:13 +00:00
|
|
|
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-26 21:36:20 +00:00
|
|
|
if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) {
|
2012-11-01 04:30:05 +00:00
|
|
|
StringRef Value(A->getValue());
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-26 21:36:20 +00:00
|
|
|
size_t Comma = Value.find(',');
|
|
|
|
unsigned Bytes = 0;
|
|
|
|
unsigned EndOfLine = 0;
|
2010-10-21 03:16:25 +00:00
|
|
|
|
2011-07-23 10:55:15 +00:00
|
|
|
if (Comma == StringRef::npos ||
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-26 21:36:20 +00:00
|
|
|
Value.substr(0, Comma).getAsInteger(10, Bytes) ||
|
|
|
|
Value.substr(Comma + 1).getAsInteger(10, EndOfLine))
|
|
|
|
Diags.Report(diag::err_drv_preamble_format);
|
|
|
|
else {
|
|
|
|
Opts.PrecompiledPreambleBytes.first = Bytes;
|
|
|
|
Opts.PrecompiledPreambleBytes.second = (EndOfLine != 0);
|
|
|
|
}
|
|
|
|
}
|
2010-10-21 03:16:25 +00:00
|
|
|
|
2018-05-18 11:56:21 +00:00
|
|
|
// Add the __CET__ macro if a CFProtection option is set.
|
|
|
|
if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) {
|
|
|
|
StringRef Name = A->getValue();
|
|
|
|
if (Name == "branch")
|
|
|
|
Opts.addMacroDef("__CET__=1");
|
|
|
|
else if (Name == "return")
|
|
|
|
Opts.addMacroDef("__CET__=2");
|
|
|
|
else if (Name == "full")
|
|
|
|
Opts.addMacroDef("__CET__=3");
|
|
|
|
}
|
|
|
|
|
2009-12-01 03:16:53 +00:00
|
|
|
// Add macros from the command line.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_D, OPT_U)) {
|
2015-06-09 01:57:17 +00:00
|
|
|
if (A->getOption().matches(OPT_D))
|
|
|
|
Opts.addMacroDef(A->getValue());
|
2009-12-01 03:16:53 +00:00
|
|
|
else
|
2015-06-09 01:57:17 +00:00
|
|
|
Opts.addMacroUndef(A->getValue());
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add the ordered list of -includes.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_include))
|
2015-05-29 19:42:19 +00:00
|
|
|
Opts.Includes.emplace_back(A->getValue());
|
2009-12-03 05:11:16 +00:00
|
|
|
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_chain_include))
|
2015-05-29 19:42:19 +00:00
|
|
|
Opts.ChainedIncludes.emplace_back(A->getValue());
|
2011-03-09 17:21:42 +00:00
|
|
|
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_remap_file)) {
|
2015-06-09 01:57:17 +00:00
|
|
|
std::pair<StringRef, StringRef> Split = StringRef(A->getValue()).split(';');
|
2009-12-03 05:11:16 +00:00
|
|
|
|
|
|
|
if (Split.second.empty()) {
|
2010-06-11 22:00:13 +00:00
|
|
|
Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args);
|
2009-12-03 05:11:16 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Opts.addRemappedFile(Split.first, Split.second);
|
|
|
|
}
|
2015-06-09 01:57:17 +00:00
|
|
|
|
2017-06-16 20:13:39 +00:00
|
|
|
// Always avoid lexing editor placeholders when we're just running the
|
|
|
|
// preprocessor as we never want to emit the
|
|
|
|
// "editor placeholder in source file" error in PP only mode.
|
2021-09-01 04:48:50 -07:00
|
|
|
if (isStrictlyPreprocessorAction(Action))
|
2017-06-16 20:13:39 +00:00
|
|
|
Opts.LexEditorPlaceholders = false;
|
2021-02-08 09:27:17 +01:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2021-02-08 09:27:17 +01:00
|
|
|
}
|
|
|
|
|
2021-02-10 11:16:10 +01:00
|
|
|
static void GeneratePreprocessorOutputArgs(
|
|
|
|
const PreprocessorOutputOptions &Opts, SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA, frontend::ActionKind Action) {
|
|
|
|
const PreprocessorOutputOptions &PreprocessorOutputOpts = Opts;
|
|
|
|
|
|
|
|
#define PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
bool Generate_dM = isStrictlyPreprocessorAction(Action) && !Opts.ShowCPP;
|
|
|
|
if (Generate_dM)
|
|
|
|
GenerateArg(Args, OPT_dM, SA);
|
|
|
|
if (!Generate_dM && Opts.ShowMacros)
|
|
|
|
GenerateArg(Args, OPT_dD, SA);
|
2020-07-31 10:44:12 +01:00
|
|
|
if (Opts.DirectivesOnly)
|
|
|
|
GenerateArg(Args, OPT_fdirectives_only, SA);
|
2021-02-10 11:16:10 +01:00
|
|
|
}
|
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
static bool ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
|
|
|
|
ArgList &Args, DiagnosticsEngine &Diags,
|
|
|
|
frontend::ActionKind Action) {
|
2021-02-10 11:16:10 +01:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
2021-04-16 15:30:28 +02:00
|
|
|
|
|
|
|
PreprocessorOutputOptions &PreprocessorOutputOpts = Opts;
|
2021-02-10 11:16:10 +01:00
|
|
|
|
|
|
|
#define PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-02-10 11:16:10 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef PREPROCESSOR_OUTPUT_OPTION_WITH_MARSHALLING
|
2013-01-30 01:52:57 +00:00
|
|
|
|
2021-02-10 11:16:10 +01:00
|
|
|
Opts.ShowCPP = isStrictlyPreprocessorAction(Action) && !Args.hasArg(OPT_dM);
|
2010-08-24 22:44:13 +00:00
|
|
|
Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
|
2020-07-31 10:44:12 +01:00
|
|
|
Opts.DirectivesOnly = Args.hasArg(OPT_fdirectives_only);
|
2021-02-10 11:16:10 +01:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2021-02-10 11:16:10 +01:00
|
|
|
}
|
|
|
|
|
2021-02-10 11:33:24 +01:00
|
|
|
static void GenerateTargetArgs(const TargetOptions &Opts,
|
|
|
|
SmallVectorImpl<const char *> &Args,
|
|
|
|
CompilerInvocation::StringAllocator SA) {
|
|
|
|
const TargetOptions *TargetOpts = &Opts;
|
|
|
|
#define TARGET_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
|
|
|
GENERATE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
|
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef TARGET_OPTION_WITH_MARSHALLING
|
|
|
|
|
|
|
|
if (!Opts.SDKVersion.empty())
|
|
|
|
GenerateArg(Args, OPT_target_sdk_version_EQ, Opts.SDKVersion.getAsString(),
|
|
|
|
SA);
|
2022-02-02 00:19:49 -08:00
|
|
|
if (!Opts.DarwinTargetVariantSDKVersion.empty())
|
|
|
|
GenerateArg(Args, OPT_darwin_target_variant_sdk_version_EQ,
|
|
|
|
Opts.DarwinTargetVariantSDKVersion.getAsString(), SA);
|
2021-02-10 11:33:24 +01:00
|
|
|
}
|
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
static bool ParseTargetArgs(TargetOptions &Opts, ArgList &Args,
|
|
|
|
DiagnosticsEngine &Diags) {
|
2021-02-10 11:33:24 +01:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
2021-04-16 15:30:28 +02:00
|
|
|
|
|
|
|
TargetOptions *TargetOpts = &Opts;
|
2021-02-10 11:33:24 +01:00
|
|
|
|
|
|
|
#define TARGET_OPTION_WITH_MARSHALLING( \
|
|
|
|
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
|
|
|
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
|
|
|
|
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
|
|
|
|
MERGER, EXTRACTOR, TABLE_INDEX) \
|
2021-04-16 15:30:28 +02:00
|
|
|
PARSE_OPTION_WITH_MARSHALLING( \
|
|
|
|
Args, Diags, ID, FLAGS, PARAM, SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
|
|
|
|
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, MERGER, TABLE_INDEX)
|
2021-02-10 11:33:24 +01:00
|
|
|
#include "clang/Driver/Options.inc"
|
|
|
|
#undef TARGET_OPTION_WITH_MARSHALLING
|
|
|
|
|
2018-12-17 19:19:15 +00:00
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_target_sdk_version_EQ)) {
|
|
|
|
llvm::VersionTuple Version;
|
|
|
|
if (Version.tryParse(A->getValue()))
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << A->getValue();
|
|
|
|
else
|
|
|
|
Opts.SDKVersion = Version;
|
|
|
|
}
|
2022-02-02 00:19:49 -08:00
|
|
|
if (Arg *A =
|
|
|
|
Args.getLastArg(options::OPT_darwin_target_variant_sdk_version_EQ)) {
|
|
|
|
llvm::VersionTuple Version;
|
|
|
|
if (Version.tryParse(A->getValue()))
|
|
|
|
Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
<< A->getAsString(Args) << A->getValue();
|
|
|
|
else
|
|
|
|
Opts.DarwinTargetVariantSDKVersion = Version;
|
|
|
|
}
|
2021-02-10 11:33:24 +01:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2021-02-10 11:33:24 +01:00
|
|
|
}
|
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
bool CompilerInvocation::CreateFromArgsImpl(
|
|
|
|
CompilerInvocation &Res, ArrayRef<const char *> CommandLineArgs,
|
|
|
|
DiagnosticsEngine &Diags, const char *Argv0) {
|
2021-04-16 15:30:28 +02:00
|
|
|
unsigned NumErrorsBefore = Diags.getNumErrors();
|
2011-12-23 03:05:38 +00:00
|
|
|
|
2009-12-01 03:16:53 +00:00
|
|
|
// Parse the arguments.
|
2019-09-04 14:26:28 +00:00
|
|
|
const OptTable &Opts = getDriverOptTable();
|
2013-08-02 20:16:22 +00:00
|
|
|
const unsigned IncludedFlagsBitmask = options::CC1Option;
|
2009-12-01 03:16:53 +00:00
|
|
|
unsigned MissingArgIndex, MissingArgCount;
|
2019-09-04 14:26:28 +00:00
|
|
|
InputArgList Args = Opts.ParseArgs(CommandLineArgs, MissingArgIndex,
|
|
|
|
MissingArgCount, IncludedFlagsBitmask);
|
2016-04-08 17:42:32 +00:00
|
|
|
LangOptions &LangOpts = *Res.getLangOpts();
|
2009-12-01 03:16:53 +00:00
|
|
|
|
|
|
|
// Check for missing argument error.
|
2021-04-16 15:30:28 +02:00
|
|
|
if (MissingArgCount)
|
2009-12-01 03:16:53 +00:00
|
|
|
Diags.Report(diag::err_drv_missing_argument)
|
2015-06-22 22:07:27 +00:00
|
|
|
<< Args.getArgString(MissingArgIndex) << MissingArgCount;
|
2009-12-01 03:16:53 +00:00
|
|
|
|
|
|
|
// Issue errors on unknown arguments.
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto *A : Args.filtered(OPT_UNKNOWN)) {
|
[Driver] Suggest correctly spelled driver options
Summary:
Depends on https://reviews.llvm.org/D41732.
Utilities such as `opt`, when invoked with arguments that are very
nearly spelled correctly, suggest the correctly spelled options:
```
bin/opt -hel
opt: Unknown command line argument '-hel'. Try: 'bin/opt -help'
opt: Did you mean '-help'?
```
Clang, on the other hand, prior to this commit, does not:
```
bin/clang -hel
clang-6.0: error: unknown argument: '-hel'
```
This commit makes use of the new libLLVMOption API from
https://reviews.llvm.org/D41732 in order to provide correct suggestions:
```
bin/clang -hel
clang-6.0: error: unknown argument: '-hel', did you mean '-help'?
```
Test Plan: `check-clang`
Reviewers: yamaguchi, v.g.vassilev, teemperor, ruiu, bruno
Reviewed By: bruno
Subscribers: bruno, jroelofs, cfe-commits
Differential Revision: https://reviews.llvm.org/D41733
llvm-svn: 321917
2018-01-06 00:25:40 +00:00
|
|
|
auto ArgString = A->getAsString(Args);
|
|
|
|
std::string Nearest;
|
2019-09-04 14:26:28 +00:00
|
|
|
if (Opts.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
|
[Driver] Suggest correctly spelled driver options
Summary:
Depends on https://reviews.llvm.org/D41732.
Utilities such as `opt`, when invoked with arguments that are very
nearly spelled correctly, suggest the correctly spelled options:
```
bin/opt -hel
opt: Unknown command line argument '-hel'. Try: 'bin/opt -help'
opt: Did you mean '-help'?
```
Clang, on the other hand, prior to this commit, does not:
```
bin/clang -hel
clang-6.0: error: unknown argument: '-hel'
```
This commit makes use of the new libLLVMOption API from
https://reviews.llvm.org/D41732 in order to provide correct suggestions:
```
bin/clang -hel
clang-6.0: error: unknown argument: '-hel', did you mean '-help'?
```
Test Plan: `check-clang`
Reviewers: yamaguchi, v.g.vassilev, teemperor, ruiu, bruno
Reviewed By: bruno
Subscribers: bruno, jroelofs, cfe-commits
Differential Revision: https://reviews.llvm.org/D41733
llvm-svn: 321917
2018-01-06 00:25:40 +00:00
|
|
|
Diags.Report(diag::err_drv_unknown_argument) << ArgString;
|
|
|
|
else
|
|
|
|
Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
|
|
|
|
<< ArgString << Nearest;
|
2011-12-23 03:05:38 +00:00
|
|
|
}
|
2009-12-01 03:16:53 +00:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
ParseFileSystemArgs(Res.getFileSystemOpts(), Args, Diags);
|
|
|
|
ParseMigratorArgs(Res.getMigratorOpts(), Args, Diags);
|
|
|
|
ParseAnalyzerArgs(*Res.getAnalyzerOpts(), Args, Diags);
|
|
|
|
ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags,
|
|
|
|
/*DefaultDiagColor=*/false);
|
|
|
|
ParseFrontendArgs(Res.getFrontendOpts(), Args, Diags, LangOpts.IsHeaderFile);
|
2010-12-04 01:50:36 +00:00
|
|
|
// FIXME: We shouldn't have to pass the DashX option around here
|
2021-02-09 15:08:31 +01:00
|
|
|
InputKind DashX = Res.getFrontendOpts().DashX;
|
2021-04-16 15:30:28 +02:00
|
|
|
ParseTargetArgs(Res.getTargetOpts(), Args, Diags);
|
2021-01-14 08:34:17 +01:00
|
|
|
llvm::Triple T(Res.getTargetOpts().Triple);
|
2021-02-25 13:30:21 +01:00
|
|
|
ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags,
|
2017-03-14 23:07:49 +00:00
|
|
|
Res.getFileSystemOpts().WorkingDir);
|
2021-04-16 17:20:04 +02:00
|
|
|
|
|
|
|
ParseLangArgs(LangOpts, Args, DashX, T, Res.getPreprocessorOpts().Includes,
|
|
|
|
Diags);
|
|
|
|
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
|
|
|
|
LangOpts.ObjCExceptions = 1;
|
2016-03-14 13:23:58 +00:00
|
|
|
|
2022-04-01 22:03:48 +00:00
|
|
|
for (auto Warning : Res.getDiagnosticOpts().Warnings) {
|
|
|
|
if (Warning == "misexpect" &&
|
|
|
|
!Diags.isIgnored(diag::warn_profile_data_misexpect, SourceLocation())) {
|
|
|
|
Res.getCodeGenOpts().MisExpect = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-19 18:44:45 +00:00
|
|
|
if (LangOpts.CUDA) {
|
|
|
|
// During CUDA device-side compilation, the aux triple is the
|
|
|
|
// triple used for host compilation.
|
|
|
|
if (LangOpts.CUDAIsDevice)
|
|
|
|
Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
|
2016-04-29 23:05:19 +00:00
|
|
|
}
|
|
|
|
|
[OpenMP] Add support for auxiliary triple specification
Summary: Device offloading requires the specification of an additional flag containing the triple of the //other// architecture the code is being compiled on if such an architecture exists. If compiling for the host, the auxiliary triple flag will contain the triple describing the device and vice versa.
Reviewers: arpith-jacob, sfantao, caomhin, carlo.bertolli, ABataev, Hahnfeld, jlebar, hfinkel, tstellar
Reviewed By: Hahnfeld
Subscribers: rengolin, cfe-commits
Differential Revision: https://reviews.llvm.org/D29339
llvm-svn: 306689
2017-06-29 15:49:03 +00:00
|
|
|
// Set the triple of the host for OpenMP device compile.
|
|
|
|
if (LangOpts.OpenMPIsDevice)
|
|
|
|
Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
|
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags, T,
|
|
|
|
Res.getFrontendOpts().OutputFile, LangOpts);
|
2021-01-15 17:55:03 +01:00
|
|
|
|
2016-03-15 09:41:39 +00:00
|
|
|
// FIXME: Override value name discarding when asan or msan is used because the
|
2016-03-14 13:23:58 +00:00
|
|
|
// backend passes depend on the name of the alloca in order to print out
|
|
|
|
// names.
|
2016-03-15 09:41:39 +00:00
|
|
|
Res.getCodeGenOpts().DiscardValueNames &=
|
2016-04-08 17:42:32 +00:00
|
|
|
!LangOpts.Sanitize.has(SanitizerKind::Address) &&
|
2018-09-07 09:21:09 +00:00
|
|
|
!LangOpts.Sanitize.has(SanitizerKind::KernelAddress) &&
|
|
|
|
!LangOpts.Sanitize.has(SanitizerKind::Memory) &&
|
|
|
|
!LangOpts.Sanitize.has(SanitizerKind::KernelMemory);
|
2016-03-14 13:23:58 +00:00
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, Diags,
|
2021-02-08 09:27:17 +01:00
|
|
|
Res.getFrontendOpts().ProgramAction,
|
|
|
|
Res.getFrontendOpts());
|
2021-02-25 13:30:21 +01:00
|
|
|
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args, Diags,
|
2013-01-30 01:52:57 +00:00
|
|
|
Res.getFrontendOpts().ProgramAction);
|
2016-07-28 19:26:30 +00:00
|
|
|
|
2021-02-25 13:30:21 +01:00
|
|
|
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), Args, Diags,
|
2021-02-10 11:47:33 +01:00
|
|
|
Res.getFrontendOpts().ProgramAction,
|
|
|
|
Res.getPreprocessorOutputOpts().ShowLineMarkers);
|
|
|
|
if (!Res.getDependencyOutputOpts().OutputFile.empty() &&
|
2021-04-16 15:30:28 +02:00
|
|
|
Res.getDependencyOutputOpts().Targets.empty())
|
2021-02-10 11:47:33 +01:00
|
|
|
Diags.Report(diag::err_fe_dependency_file_requires_MT);
|
|
|
|
|
2017-10-16 16:50:27 +00:00
|
|
|
// If sanitizer is enabled, disable OPT_ffine_grained_bitfield_accesses.
|
|
|
|
if (Res.getCodeGenOpts().FineGrainedBitfieldAccesses &&
|
|
|
|
!Res.getLangOpts()->Sanitize.empty()) {
|
|
|
|
Res.getCodeGenOpts().FineGrainedBitfieldAccesses = false;
|
|
|
|
Diags.Report(diag::warn_drv_fine_grained_bitfield_accesses_ignored);
|
|
|
|
}
|
2020-06-18 08:57:50 -04:00
|
|
|
|
|
|
|
// Store the command-line for using in the CodeView backend.
|
|
|
|
Res.getCodeGenOpts().Argv0 = Argv0;
|
2021-12-21 17:41:26 -05:00
|
|
|
append_range(Res.getCodeGenOpts().CommandLineArgs, CommandLineArgs);
|
2020-06-18 08:57:50 -04:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
FixupInvocation(Res, Diags, Args, DashX);
|
2020-12-15 09:59:19 +01:00
|
|
|
|
2021-04-16 15:30:28 +02:00
|
|
|
return Diags.getNumErrors() == NumErrorsBefore;
|
2009-12-01 03:16:53 +00:00
|
|
|
}
|
2011-09-13 23:15:45 +00:00
|
|
|
|
2021-02-25 10:10:40 +01:00
|
|
|
bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Invocation,
|
|
|
|
ArrayRef<const char *> CommandLineArgs,
|
|
|
|
DiagnosticsEngine &Diags,
|
|
|
|
const char *Argv0) {
|
|
|
|
CompilerInvocation DummyInvocation;
|
|
|
|
|
|
|
|
return RoundTrip(
|
|
|
|
[](CompilerInvocation &Invocation, ArrayRef<const char *> CommandLineArgs,
|
|
|
|
DiagnosticsEngine &Diags, const char *Argv0) {
|
|
|
|
return CreateFromArgsImpl(Invocation, CommandLineArgs, Diags, Argv0);
|
|
|
|
},
|
|
|
|
[](CompilerInvocation &Invocation, SmallVectorImpl<const char *> &Args,
|
|
|
|
StringAllocator SA) { Invocation.generateCC1CommandLine(Args, SA); },
|
|
|
|
Invocation, DummyInvocation, CommandLineArgs, Diags, Argv0);
|
|
|
|
}
|
|
|
|
|
2011-09-13 23:15:45 +00:00
|
|
|
std::string CompilerInvocation::getModuleHash() const {
|
2021-09-03 11:12:27 -07:00
|
|
|
// FIXME: Consider using SHA1 instead of MD5.
|
|
|
|
llvm::HashBuilder<llvm::MD5, llvm::support::endianness::native> HBuilder;
|
|
|
|
|
2013-03-27 16:47:18 +00:00
|
|
|
// Note: For QoI reasons, the things we use as a hash here should all be
|
|
|
|
// dumped via the -module-info flag.
|
2012-11-05 19:45:09 +00:00
|
|
|
|
2011-09-13 23:15:45 +00:00
|
|
|
// Start the signature with the compiler version.
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.add(getClangFullRepositoryVersion());
|
2012-11-05 19:45:09 +00:00
|
|
|
|
Make AST reading work better with LLVM_APPEND_VC_REV=NO
With LLVM_APPEND_VC_REV=NO, Modules/merge-lifetime-extended-temporary.cpp
would fail if it ran before a0f50d731639350c7a7 (which changed
the serialization format) and then after, for these reasons:
1. With LLVM_APPEND_VC_REV=NO, the module hash before and after the
change was the same.
2. Modules/merge-lifetime-extended-temporary.cpp is the only test
we have that uses -fmodule-cache-path=%t that
a) actually writes to the cache path
b) doesn't do `rm -rf %t` at the top of the test
So the old run would write a module file, and then the new run would
try to load it, but the serialized format changed.
Do several things to fix this:
1. Include clang::serialization::VERSION_MAJOR/VERSION_MINOR in
the module hash, so that when the AST format changes (...and
we remember to bump these), we use a different module cache dir.
2. Bump VERSION_MAJOR, since a0f50d731639350c7a7 changed the
on-disk format in a way that a gch file written before that change
can't be read after that change.
3. Add `rm -rf %t` to all tests that pass -fmodule-cache-path=%t.
This is unnecessary from a correctness PoV after 1 and 2,
but makes it so that we don't amass many cache dirs over time.
(Arguably, it also makes it so that the test suite doesn't catch
when we change the serialization format but don't bump
clang::serialization::VERSION_MAJOR/VERSION_MINOR; oh well.)
Differential Revision: https://reviews.llvm.org/D73202
2020-01-22 10:34:34 -05:00
|
|
|
// Also include the serialization version, in case LLVM_APPEND_VC_REV is off
|
|
|
|
// and getClangFullRepositoryVersion() doesn't include git revision.
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
|
Make AST reading work better with LLVM_APPEND_VC_REV=NO
With LLVM_APPEND_VC_REV=NO, Modules/merge-lifetime-extended-temporary.cpp
would fail if it ran before a0f50d731639350c7a7 (which changed
the serialization format) and then after, for these reasons:
1. With LLVM_APPEND_VC_REV=NO, the module hash before and after the
change was the same.
2. Modules/merge-lifetime-extended-temporary.cpp is the only test
we have that uses -fmodule-cache-path=%t that
a) actually writes to the cache path
b) doesn't do `rm -rf %t` at the top of the test
So the old run would write a module file, and then the new run would
try to load it, but the serialized format changed.
Do several things to fix this:
1. Include clang::serialization::VERSION_MAJOR/VERSION_MINOR in
the module hash, so that when the AST format changes (...and
we remember to bump these), we use a different module cache dir.
2. Bump VERSION_MAJOR, since a0f50d731639350c7a7 changed the
on-disk format in a way that a gch file written before that change
can't be read after that change.
3. Add `rm -rf %t` to all tests that pass -fmodule-cache-path=%t.
This is unnecessary from a correctness PoV after 1 and 2,
but makes it so that we don't amass many cache dirs over time.
(Arguably, it also makes it so that the test suite doesn't catch
when we change the serialization format but don't bump
clang::serialization::VERSION_MAJOR/VERSION_MINOR; oh well.)
Differential Revision: https://reviews.llvm.org/D73202
2020-01-22 10:34:34 -05:00
|
|
|
|
2011-09-13 23:15:45 +00:00
|
|
|
// Extend the signature with the language options
|
2021-09-03 11:12:27 -07:00
|
|
|
#define LANGOPT(Name, Bits, Default, Description) HBuilder.add(LangOpts->Name);
|
|
|
|
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
|
|
|
|
HBuilder.add(static_cast<unsigned>(LangOpts->get##Name()));
|
2011-09-13 23:15:45 +00:00
|
|
|
#define BENIGN_LANGOPT(Name, Bits, Default, Description)
|
|
|
|
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
|
|
|
|
#include "clang/Basic/LangOptions.def"
|
2015-06-23 18:20:18 +00:00
|
|
|
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.addRange(LangOpts->ModuleFeatures);
|
2015-08-05 15:08:53 +00:00
|
|
|
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.add(LangOpts->ObjCRuntime);
|
|
|
|
HBuilder.addRange(LangOpts->CommentOpts.BlockCommandNames);
|
2020-07-07 17:13:02 -06:00
|
|
|
|
2012-11-05 19:45:09 +00:00
|
|
|
// Extend the signature with the target options.
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.add(TargetOpts->Triple, TargetOpts->CPU, TargetOpts->TuneCPU,
|
|
|
|
TargetOpts->ABI);
|
|
|
|
HBuilder.addRange(TargetOpts->FeaturesAsWritten);
|
2011-09-13 23:15:45 +00:00
|
|
|
|
2011-09-14 15:55:12 +00:00
|
|
|
// Extend the signature with preprocessor options.
|
2012-11-05 19:45:09 +00:00
|
|
|
const PreprocessorOptions &ppOpts = getPreprocessorOpts();
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.add(ppOpts.UsePredefines, ppOpts.DetailedRecord);
|
2012-11-05 19:45:09 +00:00
|
|
|
|
2021-09-03 11:12:27 -07:00
|
|
|
const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
|
|
|
|
for (const auto &Macro : getPreprocessorOpts().Macros) {
|
2013-02-07 00:21:12 +00:00
|
|
|
// If we're supposed to ignore this macro for the purposes of modules,
|
|
|
|
// don't put it into the hash.
|
|
|
|
if (!hsOpts.ModulesIgnoreMacros.empty()) {
|
|
|
|
// Check whether we're ignoring this macro.
|
2021-09-03 11:12:27 -07:00
|
|
|
StringRef MacroDef = Macro.first;
|
2016-10-21 21:45:01 +00:00
|
|
|
if (hsOpts.ModulesIgnoreMacros.count(
|
|
|
|
llvm::CachedHashString(MacroDef.split('=').first)))
|
2013-02-07 00:21:12 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.add(Macro);
|
2011-10-17 14:55:37 +00:00
|
|
|
}
|
2012-11-05 19:45:09 +00:00
|
|
|
|
2016-01-12 21:01:56 +00:00
|
|
|
// Extend the signature with the sysroot and other header search options.
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.add(hsOpts.Sysroot, hsOpts.ModuleFormat, hsOpts.UseDebugInfo,
|
|
|
|
hsOpts.UseBuiltinIncludes, hsOpts.UseStandardSystemIncludes,
|
|
|
|
hsOpts.UseStandardCXXIncludes, hsOpts.UseLibcxx,
|
|
|
|
hsOpts.ModulesValidateDiagnosticOptions);
|
|
|
|
HBuilder.add(hsOpts.ResourceDir);
|
2012-11-05 19:45:09 +00:00
|
|
|
|
2019-10-21 22:51:13 +00:00
|
|
|
if (hsOpts.ModulesStrictContextHash) {
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.addRange(hsOpts.SystemHeaderPrefixes);
|
|
|
|
HBuilder.addRange(hsOpts.UserEntries);
|
2019-10-21 22:51:13 +00:00
|
|
|
|
|
|
|
const DiagnosticOptions &diagOpts = getDiagnosticOpts();
|
2021-09-03 11:12:27 -07:00
|
|
|
#define DIAGOPT(Name, Bits, Default) HBuilder.add(diagOpts.Name);
|
|
|
|
#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
|
|
|
|
HBuilder.add(diagOpts.get##Name());
|
|
|
|
#include "clang/Basic/DiagnosticOptions.def"
|
|
|
|
#undef DIAGOPT
|
|
|
|
#undef ENUM_DIAGOPT
|
2019-10-21 22:51:13 +00:00
|
|
|
}
|
|
|
|
|
2014-03-03 08:12:05 +00:00
|
|
|
// Extend the signature with the user build path.
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.add(hsOpts.ModuleUserBuildPath);
|
2014-03-03 08:12:05 +00:00
|
|
|
|
2015-11-03 18:33:07 +00:00
|
|
|
// Extend the signature with the module file extensions.
|
2021-09-03 11:12:27 -07:00
|
|
|
for (const auto &ext : getFrontendOpts().ModuleFileExtensions)
|
|
|
|
ext->hashExtension(HBuilder);
|
2015-11-03 18:33:07 +00:00
|
|
|
|
2018-11-29 22:33:09 +00:00
|
|
|
// When compiling with -gmodules, also hash -fdebug-prefix-map as it
|
|
|
|
// affects the debug info in the PCM.
|
|
|
|
if (getCodeGenOpts().DebugTypeExtRefs)
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.addRange(getCodeGenOpts().DebugPrefixMap);
|
2018-11-29 22:33:09 +00:00
|
|
|
|
2017-06-01 20:01:01 +00:00
|
|
|
// Extend the signature with the enabled sanitizers, if at least one is
|
|
|
|
// enabled. Sanitizers which cannot affect AST generation aren't hashed.
|
|
|
|
SanitizerSet SanHash = LangOpts->Sanitize;
|
|
|
|
SanHash.clear(getPPTransparentSanitizers());
|
|
|
|
if (!SanHash.empty())
|
2021-09-03 11:12:27 -07:00
|
|
|
HBuilder.add(SanHash.Mask);
|
2017-06-01 20:01:01 +00:00
|
|
|
|
2021-09-03 11:12:27 -07:00
|
|
|
llvm::MD5::MD5Result Result;
|
|
|
|
HBuilder.getHasher().final(Result);
|
|
|
|
uint64_t Hash = Result.high() ^ Result.low();
|
|
|
|
return toString(llvm::APInt(64, Hash), 36, /*Signed=*/false);
|
2011-09-13 23:15:45 +00:00
|
|
|
}
|
2013-06-14 17:17:23 +00:00
|
|
|
|
2020-05-11 11:42:38 +01:00
|
|
|
void CompilerInvocation::generateCC1CommandLine(
|
|
|
|
SmallVectorImpl<const char *> &Args, StringAllocator SA) const {
|
2021-02-09 10:17:04 +01:00
|
|
|
llvm::Triple T(TargetOpts->Triple);
|
|
|
|
|
2021-02-10 12:47:06 +01:00
|
|
|
GenerateFileSystemArgs(FileSystemOpts, Args, SA);
|
|
|
|
GenerateMigratorArgs(MigratorOpts, Args, SA);
|
2021-02-08 09:04:21 +01:00
|
|
|
GenerateAnalyzerArgs(*AnalyzerOpts, Args, SA);
|
2021-02-10 12:24:19 +01:00
|
|
|
GenerateDiagnosticArgs(*DiagnosticOpts, Args, SA, false);
|
2021-02-09 16:30:14 +01:00
|
|
|
GenerateFrontendArgs(FrontendOpts, Args, SA, LangOpts->IsHeaderFile);
|
2021-02-10 11:33:24 +01:00
|
|
|
GenerateTargetArgs(*TargetOpts, Args, SA);
|
2021-01-27 14:50:09 +01:00
|
|
|
GenerateHeaderSearchArgs(*HeaderSearchOpts, Args, SA);
|
2021-04-16 17:20:04 +02:00
|
|
|
GenerateLangArgs(*LangOpts, Args, SA, T, FrontendOpts.DashX);
|
2021-02-09 11:42:01 +01:00
|
|
|
GenerateCodeGenArgs(CodeGenOpts, Args, SA, T, FrontendOpts.OutputFile,
|
|
|
|
&*LangOpts);
|
2021-02-10 11:16:10 +01:00
|
|
|
GeneratePreprocessorArgs(*PreprocessorOpts, Args, SA, *LangOpts, FrontendOpts,
|
|
|
|
CodeGenOpts);
|
|
|
|
GeneratePreprocessorOutputArgs(PreprocessorOutputOpts, Args, SA,
|
|
|
|
FrontendOpts.ProgramAction);
|
2021-02-10 11:47:33 +01:00
|
|
|
GenerateDependencyOutputArgs(DependencyOutputOpts, Args, SA);
|
2020-05-11 11:42:38 +01:00
|
|
|
}
|
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
2020-11-06 12:40:43 -05:00
|
|
|
clang::createVFSFromCompilerInvocation(const CompilerInvocation &CI,
|
|
|
|
DiagnosticsEngine &Diags) {
|
2018-10-10 13:27:25 +00:00
|
|
|
return createVFSFromCompilerInvocation(CI, Diags,
|
|
|
|
llvm::vfs::getRealFileSystem());
|
2017-05-23 11:37:52 +00:00
|
|
|
}
|
|
|
|
|
2020-11-06 12:40:43 -05:00
|
|
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
|
|
|
clang::createVFSFromCompilerInvocation(
|
2018-10-10 13:27:25 +00:00
|
|
|
const CompilerInvocation &CI, DiagnosticsEngine &Diags,
|
|
|
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
|
2014-04-15 18:16:25 +00:00
|
|
|
if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
|
2017-05-23 11:37:52 +00:00
|
|
|
return BaseFS;
|
2014-04-15 18:16:25 +00:00
|
|
|
|
2018-10-26 22:16:24 +00:00
|
|
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem> Result = BaseFS;
|
2014-04-15 18:16:25 +00:00
|
|
|
// earlier vfs files are on the bottom
|
2018-03-26 21:45:04 +00:00
|
|
|
for (const auto &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
|
2014-07-06 17:43:24 +00:00
|
|
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
|
2018-10-26 22:16:24 +00:00
|
|
|
Result->getBufferForFile(File);
|
2014-07-06 17:43:24 +00:00
|
|
|
if (!Buffer) {
|
2014-04-15 18:16:25 +00:00
|
|
|
Diags.Report(diag::err_missing_vfs_overlay_file) << File;
|
2018-03-23 17:37:27 +00:00
|
|
|
continue;
|
2014-04-15 18:16:25 +00:00
|
|
|
}
|
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = llvm::vfs::getVFSFromYAML(
|
2018-10-26 22:16:24 +00:00
|
|
|
std::move(Buffer.get()), /*DiagHandler*/ nullptr, File,
|
|
|
|
/*DiagContext*/ nullptr, Result);
|
|
|
|
if (!FS) {
|
2014-04-15 18:16:25 +00:00
|
|
|
Diags.Report(diag::err_invalid_vfs_overlay) << File;
|
2018-10-26 22:16:24 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result = FS;
|
2014-04-15 18:16:25 +00:00
|
|
|
}
|
2018-10-26 22:16:24 +00:00
|
|
|
return Result;
|
2013-06-14 17:17:23 +00:00
|
|
|
}
|