Merge ^/vendor/llvm-project/release-10.x up to its last change (upstream
commit llvmorg-10.0.0-rc2-0-g90c78073f73), bump versions, and update build glue.
This commit is contained in:
commit
e08186f819
@ -29,14 +29,14 @@ class ConceptSpecializationExpr;
|
||||
class ConstraintSatisfaction : public llvm::FoldingSetNode {
|
||||
// The template-like entity that 'owns' the constraint checked here (can be a
|
||||
// constrained entity or a concept).
|
||||
NamedDecl *ConstraintOwner = nullptr;
|
||||
const NamedDecl *ConstraintOwner = nullptr;
|
||||
llvm::SmallVector<TemplateArgument, 4> TemplateArgs;
|
||||
|
||||
public:
|
||||
|
||||
ConstraintSatisfaction() = default;
|
||||
|
||||
ConstraintSatisfaction(NamedDecl *ConstraintOwner,
|
||||
ConstraintSatisfaction(const NamedDecl *ConstraintOwner,
|
||||
ArrayRef<TemplateArgument> TemplateArgs) :
|
||||
ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(),
|
||||
TemplateArgs.end()) { }
|
||||
@ -57,7 +57,7 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C,
|
||||
NamedDecl *ConstraintOwner,
|
||||
const NamedDecl *ConstraintOwner,
|
||||
ArrayRef<TemplateArgument> TemplateArgs);
|
||||
};
|
||||
|
||||
|
@ -63,6 +63,12 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference,
|
||||
ArrayRef<TemplateArgument> ConvertedArgs,
|
||||
const ConstraintSatisfaction *Satisfaction);
|
||||
|
||||
ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
|
||||
ArrayRef<TemplateArgument> ConvertedArgs,
|
||||
const ConstraintSatisfaction *Satisfaction,
|
||||
bool Dependent,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
|
||||
|
||||
public:
|
||||
@ -75,6 +81,13 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference,
|
||||
ArrayRef<TemplateArgument> ConvertedArgs,
|
||||
const ConstraintSatisfaction *Satisfaction);
|
||||
|
||||
static ConceptSpecializationExpr *
|
||||
Create(const ASTContext &C, ConceptDecl *NamedConcept,
|
||||
ArrayRef<TemplateArgument> ConvertedArgs,
|
||||
const ConstraintSatisfaction *Satisfaction,
|
||||
bool Dependent,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
static ConceptSpecializationExpr *
|
||||
Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
class Twine;
|
||||
class VersionTuple;
|
||||
} // namespace llvm
|
||||
|
||||
@ -30,7 +31,7 @@ enum class CudaVersion {
|
||||
};
|
||||
const char *CudaVersionToString(CudaVersion V);
|
||||
// Input is "Major.Minor"
|
||||
CudaVersion CudaStringToVersion(llvm::StringRef S);
|
||||
CudaVersion CudaStringToVersion(const llvm::Twine &S);
|
||||
|
||||
enum class CudaArch {
|
||||
UNKNOWN,
|
||||
|
@ -60,6 +60,9 @@ def err_drv_cuda_version_unsupported : Error<
|
||||
"but installation at %3 is %4. Use --cuda-path to specify a different CUDA "
|
||||
"install, pass a different GPU arch with --cuda-gpu-arch, or pass "
|
||||
"--no-cuda-version-check.">;
|
||||
def warn_drv_unknown_cuda_version: Warning<
|
||||
"Unknown CUDA version %0. Assuming the latest supported version %1">,
|
||||
InGroup<CudaUnknownVersion>;
|
||||
def err_drv_cuda_host_arch : Error<"unsupported architecture '%0' for host compilation.">;
|
||||
def err_drv_mix_cuda_hip : Error<"Mixed Cuda and HIP compilation is not supported.">;
|
||||
def err_drv_invalid_thread_model_for_target : Error<
|
||||
|
@ -384,7 +384,10 @@ def GNULabelsAsValue : DiagGroup<"gnu-label-as-value">;
|
||||
def LiteralRange : DiagGroup<"literal-range">;
|
||||
def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args",
|
||||
[CXX98CompatLocalTypeTemplateArgs]>;
|
||||
def RangeLoopAnalysis : DiagGroup<"range-loop-analysis">;
|
||||
def RangeLoopConstruct : DiagGroup<"range-loop-construct">;
|
||||
def RangeLoopBindReference : DiagGroup<"range-loop-bind-reference">;
|
||||
def RangeLoopAnalysis : DiagGroup<"range-loop-analysis",
|
||||
[RangeLoopConstruct, RangeLoopBindReference]>;
|
||||
def ForLoopAnalysis : DiagGroup<"for-loop-analysis">;
|
||||
def LoopAnalysis : DiagGroup<"loop-analysis", [ForLoopAnalysis,
|
||||
RangeLoopAnalysis]>;
|
||||
@ -858,14 +861,15 @@ def Most : DiagGroup<"most", [
|
||||
Comment,
|
||||
DeleteNonVirtualDtor,
|
||||
Format,
|
||||
ForLoopAnalysis,
|
||||
Implicit,
|
||||
InfiniteRecursion,
|
||||
IntInBoolContext,
|
||||
LoopAnalysis,
|
||||
MismatchedTags,
|
||||
MissingBraces,
|
||||
Move,
|
||||
MultiChar,
|
||||
RangeLoopConstruct,
|
||||
Reorder,
|
||||
ReturnType,
|
||||
SelfAssignment,
|
||||
@ -1113,6 +1117,9 @@ def SerializedDiagnostics : DiagGroup<"serialized-diagnostics">;
|
||||
// compiling CUDA C/C++ but which is not compatible with the CUDA spec.
|
||||
def CudaCompat : DiagGroup<"cuda-compat">;
|
||||
|
||||
// Warning about unknown CUDA SDK version.
|
||||
def CudaUnknownVersion: DiagGroup<"unknown-cuda-version">;
|
||||
|
||||
// A warning group for warnings about features supported by HIP but
|
||||
// ignored by CUDA.
|
||||
def HIPOnly : DiagGroup<"hip-only">;
|
||||
|
@ -2378,17 +2378,17 @@ def warn_for_range_const_reference_copy : Warning<
|
||||
"loop variable %0 "
|
||||
"%diff{has type $ but is initialized with type $"
|
||||
"| is initialized with a value of a different type}1,2 resulting in a copy">,
|
||||
InGroup<RangeLoopAnalysis>, DefaultIgnore;
|
||||
InGroup<RangeLoopConstruct>, DefaultIgnore;
|
||||
def note_use_type_or_non_reference : Note<
|
||||
"use non-reference type %0 to keep the copy or type %1 to prevent copying">;
|
||||
def warn_for_range_variable_always_copy : Warning<
|
||||
"loop variable %0 is always a copy because the range of type %1 does not "
|
||||
"return a reference">,
|
||||
InGroup<RangeLoopAnalysis>, DefaultIgnore;
|
||||
InGroup<RangeLoopBindReference>, DefaultIgnore;
|
||||
def note_use_non_reference_type : Note<"use non-reference type %0">;
|
||||
def warn_for_range_copy : Warning<
|
||||
"loop variable %0 of type %1 creates a copy from type %2">,
|
||||
InGroup<RangeLoopAnalysis>, DefaultIgnore;
|
||||
InGroup<RangeLoopConstruct>, DefaultIgnore;
|
||||
def note_use_reference_type : Note<"use reference type %0 to prevent copying">;
|
||||
def err_objc_for_range_init_stmt : Error<
|
||||
"initialization statement is not supported when iterating over Objective-C "
|
||||
@ -4683,6 +4683,8 @@ def note_checking_constraints_for_var_spec_id_here : Note<
|
||||
def note_checking_constraints_for_class_spec_id_here : Note<
|
||||
"while checking constraint satisfaction for class template partial "
|
||||
"specialization '%0' required here">;
|
||||
def note_checking_constraints_for_function_here : Note<
|
||||
"while checking constraint satisfaction for function '%0' required here">;
|
||||
def note_constraint_substitution_here : Note<
|
||||
"while substituting template arguments into constraint expression here">;
|
||||
def note_constraint_normalization_here : Note<
|
||||
@ -6746,6 +6748,10 @@ def err_bad_cxx_cast_scalar_to_vector_different_size : Error<
|
||||
def err_bad_cxx_cast_vector_to_vector_different_size : Error<
|
||||
"%select{||reinterpret_cast||C-style cast|}0 from vector %1 "
|
||||
"to vector %2 of different size">;
|
||||
def warn_bad_cxx_cast_nested_pointer_addr_space : Warning<
|
||||
"%select{reinterpret_cast|C-style cast}0 from %1 to %2 "
|
||||
"changes address space of nested pointers">,
|
||||
InGroup<IncompatiblePointerTypesDiscardsQualifiers>;
|
||||
def err_bad_lvalue_to_rvalue_cast : Error<
|
||||
"cannot cast from lvalue of type %1 to rvalue reference type %2; types are "
|
||||
"not compatible">;
|
||||
@ -8390,6 +8396,12 @@ def note_defaulted_comparison_cannot_deduce : Note<
|
||||
"return type of defaulted 'operator<=>' cannot be deduced because "
|
||||
"return type %2 of three-way comparison for %select{|member|base class}0 %1 "
|
||||
"is not a standard comparison category type">;
|
||||
def err_defaulted_comparison_cannot_deduce_undeduced_auto : Error<
|
||||
"return type of defaulted 'operator<=>' cannot be deduced because "
|
||||
"three-way comparison for %select{|member|base class}0 %1 "
|
||||
"has a deduced return type and is not yet defined">;
|
||||
def note_defaulted_comparison_cannot_deduce_undeduced_auto : Note<
|
||||
"%select{|member|base class}0 %1 declared here">;
|
||||
def note_defaulted_comparison_cannot_deduce_callee : Note<
|
||||
"selected 'operator<=>' for %select{|member|base class}0 %1 declared here">;
|
||||
def err_incorrect_defaulted_comparison_constexpr : Error<
|
||||
|
@ -859,6 +859,8 @@ def detailed_preprocessing_record : Flag<["-"], "detailed-preprocessing-record">
|
||||
HelpText<"include a detailed record of preprocessing actions">;
|
||||
def setup_static_analyzer : Flag<["-"], "setup-static-analyzer">,
|
||||
HelpText<"Set up preprocessor for static analyzer (done automatically when static analyzer is run).">;
|
||||
def disable_pragma_debug_crash : Flag<["-"], "disable-pragma-debug-crash">,
|
||||
HelpText<"Disable any #pragma clang __debug that can lead to crashing behavior. This is meant for testing.">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OpenCL Options
|
||||
|
@ -55,9 +55,6 @@ class Command {
|
||||
/// The list of program arguments which are inputs.
|
||||
llvm::opt::ArgStringList InputFilenames;
|
||||
|
||||
/// Whether to print the input filenames when executing.
|
||||
bool PrintInputFilenames = false;
|
||||
|
||||
/// Response file name, if this command is set to use one, or nullptr
|
||||
/// otherwise
|
||||
const char *ResponseFile = nullptr;
|
||||
@ -86,6 +83,12 @@ class Command {
|
||||
void writeResponseFile(raw_ostream &OS) const;
|
||||
|
||||
public:
|
||||
/// Whether to print the input filenames when executing.
|
||||
bool PrintInputFilenames = false;
|
||||
|
||||
/// Whether the command will be executed in this process or not.
|
||||
bool InProcess = false;
|
||||
|
||||
Command(const Action &Source, const Tool &Creator, const char *Executable,
|
||||
const llvm::opt::ArgStringList &Arguments,
|
||||
ArrayRef<InputInfo> Inputs);
|
||||
@ -128,9 +131,6 @@ class Command {
|
||||
/// Print a command argument, and optionally quote it.
|
||||
static void printArg(llvm::raw_ostream &OS, StringRef Arg, bool Quote);
|
||||
|
||||
/// Set whether to print the input filenames when executing.
|
||||
void setPrintInputFilenames(bool P) { PrintInputFilenames = P; }
|
||||
|
||||
protected:
|
||||
/// Optionally print the filenames to be compiled
|
||||
void PrintFileNames() const;
|
||||
@ -139,7 +139,9 @@ class Command {
|
||||
/// Use the CC1 tool callback when available, to avoid creating a new process
|
||||
class CC1Command : public Command {
|
||||
public:
|
||||
using Command::Command;
|
||||
CC1Command(const Action &Source, const Tool &Creator, const char *Executable,
|
||||
const llvm::opt::ArgStringList &Arguments,
|
||||
ArrayRef<InputInfo> Inputs);
|
||||
|
||||
void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
|
||||
CrashReportInfo *CrashInfo = nullptr) const override;
|
||||
|
@ -189,6 +189,9 @@ class PreprocessorOptions {
|
||||
/// Set up preprocessor for RunAnalysis action.
|
||||
bool SetUpStaticAnalyzer = false;
|
||||
|
||||
/// Prevents intended crashes when using #pragma clang __debug. For testing.
|
||||
bool DisablePragmaDebugCrash = false;
|
||||
|
||||
public:
|
||||
PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {}
|
||||
|
||||
|
@ -6275,7 +6275,7 @@ class Sema final {
|
||||
/// \returns true if an error occurred and satisfaction could not be checked,
|
||||
/// false otherwise.
|
||||
bool CheckConstraintSatisfaction(
|
||||
NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
|
||||
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
|
||||
ArrayRef<TemplateArgument> TemplateArgs,
|
||||
SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
|
||||
|
||||
@ -6288,6 +6288,17 @@ class Sema final {
|
||||
bool CheckConstraintSatisfaction(const Expr *ConstraintExpr,
|
||||
ConstraintSatisfaction &Satisfaction);
|
||||
|
||||
/// Check whether the given function decl's trailing requires clause is
|
||||
/// satisfied, if any. Returns false and updates Satisfaction with the
|
||||
/// satisfaction verdict if successful, emits a diagnostic and returns true if
|
||||
/// an error occured and satisfaction could not be determined.
|
||||
///
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
bool CheckFunctionConstraints(const FunctionDecl *FD,
|
||||
ConstraintSatisfaction &Satisfaction,
|
||||
SourceLocation UsageLoc = SourceLocation());
|
||||
|
||||
|
||||
/// \brief Ensure that the given template arguments satisfy the constraints
|
||||
/// associated with the given template, emitting a diagnostic if they do not.
|
||||
///
|
||||
@ -6986,7 +6997,7 @@ class Sema final {
|
||||
/// Get a template argument mapping the given template parameter to itself,
|
||||
/// e.g. for X in \c template<int X>, this would return an expression template
|
||||
/// argument referencing X.
|
||||
TemplateArgumentLoc getIdentityTemplateArgumentLoc(Decl *Param,
|
||||
TemplateArgumentLoc getIdentityTemplateArgumentLoc(NamedDecl *Param,
|
||||
SourceLocation Location);
|
||||
|
||||
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
|
||||
|
@ -43,11 +43,15 @@ struct AtomicConstraint {
|
||||
if (ParameterMapping->size() != Other.ParameterMapping->size())
|
||||
return false;
|
||||
|
||||
for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I)
|
||||
if (!C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
|
||||
.structurallyEquals(C.getCanonicalTemplateArgument(
|
||||
(*Other.ParameterMapping)[I].getArgument())))
|
||||
for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) {
|
||||
llvm::FoldingSetNodeID IDA, IDB;
|
||||
C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
|
||||
.Profile(IDA, C);
|
||||
C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument())
|
||||
.Profile(IDB, C);
|
||||
if (IDA != IDB)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,8 @@ ASTConstraintSatisfaction::Create(const ASTContext &C,
|
||||
}
|
||||
|
||||
void ConstraintSatisfaction::Profile(
|
||||
llvm::FoldingSetNodeID &ID, const ASTContext &C, NamedDecl *ConstraintOwner,
|
||||
ArrayRef<TemplateArgument> TemplateArgs) {
|
||||
llvm::FoldingSetNodeID &ID, const ASTContext &C,
|
||||
const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) {
|
||||
ID.AddPointer(ConstraintOwner);
|
||||
ID.AddInteger(TemplateArgs.size());
|
||||
for (auto &Arg : TemplateArgs)
|
||||
|
@ -756,12 +756,8 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
|
||||
NewConverted.push_back(Arg);
|
||||
}
|
||||
Expr *NewIDC = ConceptSpecializationExpr::Create(
|
||||
C, NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
|
||||
CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
|
||||
CSE->getNamedConcept(),
|
||||
// Actually canonicalizing a TemplateArgumentLoc is difficult so we
|
||||
// simply omit the ArgsAsWritten
|
||||
/*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
|
||||
C, CSE->getNamedConcept(), NewConverted, nullptr,
|
||||
CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack());
|
||||
|
||||
if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
|
||||
NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC,
|
||||
|
@ -758,6 +758,8 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
|
||||
return false;
|
||||
};
|
||||
|
||||
// FIXME: IsHidden reads from Overriding from the middle of a remove_if
|
||||
// over the same sequence! Is this guaranteed to work?
|
||||
Overriding.erase(
|
||||
std::remove_if(Overriding.begin(), Overriding.end(), IsHidden),
|
||||
Overriding.end());
|
||||
|
@ -2038,17 +2038,36 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
|
||||
if (auto *MD = getCorrespondingMethodDeclaredInClass(RD, MayBeBase))
|
||||
return MD;
|
||||
|
||||
llvm::SmallVector<CXXMethodDecl*, 4> FinalOverriders;
|
||||
auto AddFinalOverrider = [&](CXXMethodDecl *D) {
|
||||
// If this function is overridden by a candidate final overrider, it is not
|
||||
// a final overrider.
|
||||
for (CXXMethodDecl *OtherD : FinalOverriders) {
|
||||
if (declaresSameEntity(D, OtherD) || recursivelyOverrides(OtherD, D))
|
||||
return;
|
||||
}
|
||||
|
||||
// Other candidate final overriders might be overridden by this function.
|
||||
FinalOverriders.erase(
|
||||
std::remove_if(FinalOverriders.begin(), FinalOverriders.end(),
|
||||
[&](CXXMethodDecl *OtherD) {
|
||||
return recursivelyOverrides(D, OtherD);
|
||||
}),
|
||||
FinalOverriders.end());
|
||||
|
||||
FinalOverriders.push_back(D);
|
||||
};
|
||||
|
||||
for (const auto &I : RD->bases()) {
|
||||
const RecordType *RT = I.getType()->getAs<RecordType>();
|
||||
if (!RT)
|
||||
continue;
|
||||
const auto *Base = cast<CXXRecordDecl>(RT->getDecl());
|
||||
CXXMethodDecl *T = this->getCorrespondingMethodInClass(Base);
|
||||
if (T)
|
||||
return T;
|
||||
if (CXXMethodDecl *D = this->getCorrespondingMethodInClass(Base))
|
||||
AddFinalOverrider(D);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return FinalOverriders.size() == 1 ? FinalOverriders.front() : nullptr;
|
||||
}
|
||||
|
||||
CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
@ -2105,6 +2124,11 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
|
||||
CXXMethodDecl *DevirtualizedMethod =
|
||||
getCorrespondingMethodInClass(BestDynamicDecl);
|
||||
|
||||
// If there final overrider in the dynamic type is ambiguous, we can't
|
||||
// devirtualize this call.
|
||||
if (!DevirtualizedMethod)
|
||||
return nullptr;
|
||||
|
||||
// If that method is pure virtual, we can't devirtualize. If this code is
|
||||
// reached, the result would be UB, not a direct call to the derived class
|
||||
// function, and we can't assume the derived class function is defined.
|
||||
|
@ -1685,6 +1685,11 @@ MemberExpr *MemberExpr::Create(
|
||||
CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC);
|
||||
if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC))
|
||||
E->setTypeDependent(T->isDependentType());
|
||||
|
||||
// Bitfield with value-dependent width is type-dependent.
|
||||
FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl);
|
||||
if (FD && FD->isBitField() && FD->getBitWidth()->isValueDependent())
|
||||
E->setTypeDependent(true);
|
||||
}
|
||||
|
||||
if (HasQualOrFound) {
|
||||
|
@ -46,24 +46,12 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C,
|
||||
ASTConstraintSatisfaction::Create(C, *Satisfaction) :
|
||||
nullptr) {
|
||||
setTemplateArguments(ConvertedArgs);
|
||||
}
|
||||
|
||||
ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
|
||||
unsigned NumTemplateArgs)
|
||||
: Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
|
||||
NumTemplateArgs(NumTemplateArgs) { }
|
||||
|
||||
void ConceptSpecializationExpr::setTemplateArguments(
|
||||
ArrayRef<TemplateArgument> Converted) {
|
||||
assert(Converted.size() == NumTemplateArgs);
|
||||
std::uninitialized_copy(Converted.begin(), Converted.end(),
|
||||
getTrailingObjects<TemplateArgument>());
|
||||
bool IsInstantiationDependent = false;
|
||||
bool ContainsUnexpandedParameterPack = false;
|
||||
for (const TemplateArgument& Arg : Converted) {
|
||||
if (Arg.isInstantiationDependent())
|
||||
for (const TemplateArgumentLoc& ArgLoc : ArgsAsWritten->arguments()) {
|
||||
if (ArgLoc.getArgument().isInstantiationDependent())
|
||||
IsInstantiationDependent = true;
|
||||
if (Arg.containsUnexpandedParameterPack())
|
||||
if (ArgLoc.getArgument().containsUnexpandedParameterPack())
|
||||
ContainsUnexpandedParameterPack = true;
|
||||
if (ContainsUnexpandedParameterPack && IsInstantiationDependent)
|
||||
break;
|
||||
@ -80,6 +68,18 @@ void ConceptSpecializationExpr::setTemplateArguments(
|
||||
"should not be value-dependent");
|
||||
}
|
||||
|
||||
ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
|
||||
unsigned NumTemplateArgs)
|
||||
: Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
|
||||
NumTemplateArgs(NumTemplateArgs) { }
|
||||
|
||||
void ConceptSpecializationExpr::setTemplateArguments(
|
||||
ArrayRef<TemplateArgument> Converted) {
|
||||
assert(Converted.size() == NumTemplateArgs);
|
||||
std::uninitialized_copy(Converted.begin(), Converted.end(),
|
||||
getTrailingObjects<TemplateArgument>());
|
||||
}
|
||||
|
||||
ConceptSpecializationExpr *
|
||||
ConceptSpecializationExpr::Create(const ASTContext &C,
|
||||
NestedNameSpecifierLoc NNS,
|
||||
@ -98,6 +98,39 @@ ConceptSpecializationExpr::Create(const ASTContext &C,
|
||||
ConvertedArgs, Satisfaction);
|
||||
}
|
||||
|
||||
ConceptSpecializationExpr::ConceptSpecializationExpr(
|
||||
const ASTContext &C, ConceptDecl *NamedConcept,
|
||||
ArrayRef<TemplateArgument> ConvertedArgs,
|
||||
const ConstraintSatisfaction *Satisfaction, bool Dependent,
|
||||
bool ContainsUnexpandedParameterPack)
|
||||
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
|
||||
/*TypeDependent=*/false,
|
||||
/*ValueDependent=*/!Satisfaction, Dependent,
|
||||
ContainsUnexpandedParameterPack),
|
||||
ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
|
||||
DeclarationNameInfo(), NamedConcept,
|
||||
NamedConcept, nullptr),
|
||||
NumTemplateArgs(ConvertedArgs.size()),
|
||||
Satisfaction(Satisfaction ?
|
||||
ASTConstraintSatisfaction::Create(C, *Satisfaction) :
|
||||
nullptr) {
|
||||
setTemplateArguments(ConvertedArgs);
|
||||
}
|
||||
|
||||
ConceptSpecializationExpr *
|
||||
ConceptSpecializationExpr::Create(const ASTContext &C,
|
||||
ConceptDecl *NamedConcept,
|
||||
ArrayRef<TemplateArgument> ConvertedArgs,
|
||||
const ConstraintSatisfaction *Satisfaction,
|
||||
bool Dependent,
|
||||
bool ContainsUnexpandedParameterPack) {
|
||||
void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
|
||||
ConvertedArgs.size()));
|
||||
return new (Buffer) ConceptSpecializationExpr(
|
||||
C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
|
||||
ContainsUnexpandedParameterPack);
|
||||
}
|
||||
|
||||
ConceptSpecializationExpr *
|
||||
ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
|
||||
unsigned NumTemplateArgs) {
|
||||
|
@ -1535,8 +1535,8 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
|
||||
return Stmt::BinaryOperatorClass;
|
||||
|
||||
case OO_Spaceship:
|
||||
// FIXME: Update this once we support <=> expressions.
|
||||
llvm_unreachable("<=> expressions not supported yet");
|
||||
BinaryOp = BO_Cmp;
|
||||
return Stmt::BinaryOperatorClass;
|
||||
|
||||
case OO_AmpAmp:
|
||||
BinaryOp = BO_LAnd;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/VersionTuple.h"
|
||||
|
||||
@ -31,8 +32,8 @@ const char *CudaVersionToString(CudaVersion V) {
|
||||
llvm_unreachable("invalid enum");
|
||||
}
|
||||
|
||||
CudaVersion CudaStringToVersion(llvm::StringRef S) {
|
||||
return llvm::StringSwitch<CudaVersion>(S)
|
||||
CudaVersion CudaStringToVersion(const llvm::Twine &S) {
|
||||
return llvm::StringSwitch<CudaVersion>(S.str())
|
||||
.Case("7.0", CudaVersion::CUDA_70)
|
||||
.Case("7.5", CudaVersion::CUDA_75)
|
||||
.Case("8.0", CudaVersion::CUDA_80)
|
||||
@ -40,7 +41,8 @@ CudaVersion CudaStringToVersion(llvm::StringRef S) {
|
||||
.Case("9.1", CudaVersion::CUDA_91)
|
||||
.Case("9.2", CudaVersion::CUDA_92)
|
||||
.Case("10.0", CudaVersion::CUDA_100)
|
||||
.Case("10.1", CudaVersion::CUDA_101);
|
||||
.Case("10.1", CudaVersion::CUDA_101)
|
||||
.Default(CudaVersion::UNKNOWN);
|
||||
}
|
||||
|
||||
const char *CudaArchToString(CudaArch A) {
|
||||
|
@ -537,6 +537,13 @@ void CodeGenModule::Release() {
|
||||
getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth);
|
||||
}
|
||||
|
||||
if (Arch == llvm::Triple::riscv32 || Arch == llvm::Triple::riscv64) {
|
||||
StringRef ABIStr = Target.getABI();
|
||||
llvm::LLVMContext &Ctx = TheModule.getContext();
|
||||
getModule().addModuleFlag(llvm::Module::Error, "target-abi",
|
||||
llvm::MDString::get(Ctx, ABIStr));
|
||||
}
|
||||
|
||||
if (CodeGenOpts.SanitizeCfiCrossDso) {
|
||||
// Indicate that we want cross-DSO control flow integrity checks.
|
||||
getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1);
|
||||
|
@ -258,14 +258,23 @@ void Compilation::initCompilationForDiagnostics() {
|
||||
|
||||
// Remove any user specified output. Claim any unclaimed arguments, so as
|
||||
// to avoid emitting warnings about unused args.
|
||||
OptSpecifier OutputOpts[] = { options::OPT_o, options::OPT_MD,
|
||||
options::OPT_MMD };
|
||||
OptSpecifier OutputOpts[] = {
|
||||
options::OPT_o, options::OPT_MD, options::OPT_MMD, options::OPT_M,
|
||||
options::OPT_MM, options::OPT_MF, options::OPT_MG, options::OPT_MJ,
|
||||
options::OPT_MQ, options::OPT_MT, options::OPT_MV};
|
||||
for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
|
||||
if (TranslatedArgs->hasArg(OutputOpts[i]))
|
||||
TranslatedArgs->eraseArg(OutputOpts[i]);
|
||||
}
|
||||
TranslatedArgs->ClaimAllArgs();
|
||||
|
||||
// Force re-creation of the toolchain Args, otherwise our modifications just
|
||||
// above will have no effect.
|
||||
for (auto Arg : TCArgs)
|
||||
if (Arg.second != TranslatedArgs)
|
||||
delete Arg.second;
|
||||
TCArgs.clear();
|
||||
|
||||
// Redirect stdout/stderr to /dev/null.
|
||||
Redirects = {None, {""}, {""}};
|
||||
|
||||
|
@ -3757,6 +3757,11 @@ void Driver::BuildJobs(Compilation &C) const {
|
||||
/*TargetDeviceOffloadKind*/ Action::OFK_None);
|
||||
}
|
||||
|
||||
// If we have more than one job, then disable integrated-cc1 for now.
|
||||
if (C.getJobs().size() > 1)
|
||||
for (auto &J : C.getJobs())
|
||||
J.InProcess = false;
|
||||
|
||||
// If the user passed -Qunused-arguments or there were errors, don't warn
|
||||
// about any unused arguments.
|
||||
if (Diags.hasErrorOccurred() ||
|
||||
|
@ -371,14 +371,29 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
|
||||
/*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
|
||||
}
|
||||
|
||||
CC1Command::CC1Command(const Action &Source, const Tool &Creator,
|
||||
const char *Executable,
|
||||
const llvm::opt::ArgStringList &Arguments,
|
||||
ArrayRef<InputInfo> Inputs)
|
||||
: Command(Source, Creator, Executable, Arguments, Inputs) {
|
||||
InProcess = true;
|
||||
}
|
||||
|
||||
void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
|
||||
CrashReportInfo *CrashInfo) const {
|
||||
OS << " (in-process)\n";
|
||||
if (InProcess)
|
||||
OS << " (in-process)\n";
|
||||
Command::Print(OS, Terminator, Quote, CrashInfo);
|
||||
}
|
||||
|
||||
int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> /*Redirects*/,
|
||||
int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
|
||||
std::string *ErrMsg, bool *ExecutionFailed) const {
|
||||
// FIXME: Currently, if there're more than one job, we disable
|
||||
// -fintegrate-cc1. If we're no longer a integrated-cc1 job, fallback to
|
||||
// out-of-process execution. See discussion in https://reviews.llvm.org/D74447
|
||||
if (!InProcess)
|
||||
return Command::Execute(Redirects, ErrMsg, ExecutionFailed);
|
||||
|
||||
PrintFileNames();
|
||||
|
||||
SmallVector<const char *, 128> Argv;
|
||||
|
@ -4679,6 +4679,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
: "-");
|
||||
}
|
||||
|
||||
// Give the gen diagnostics more chances to succeed, by avoiding intentional
|
||||
// crashes.
|
||||
if (D.CCGenDiagnostics)
|
||||
CmdArgs.push_back("-disable-pragma-debug-crash");
|
||||
|
||||
bool UseSeparateSections = isUseSeparateSections(Triple);
|
||||
|
||||
if (Args.hasFlag(options::OPT_ffunction_sections,
|
||||
@ -6048,7 +6053,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
if (Output.getType() == types::TY_Object &&
|
||||
Args.hasFlag(options::OPT__SLASH_showFilenames,
|
||||
options::OPT__SLASH_showFilenames_, false)) {
|
||||
C.getJobs().getJobs().back()->setPrintInputFilenames(true);
|
||||
C.getJobs().getJobs().back()->PrintInputFilenames = true;
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_pg))
|
||||
|
@ -32,37 +32,24 @@ using namespace llvm::opt;
|
||||
|
||||
// Parses the contents of version.txt in an CUDA installation. It should
|
||||
// contain one line of the from e.g. "CUDA Version 7.5.2".
|
||||
static CudaVersion ParseCudaVersionFile(llvm::StringRef V) {
|
||||
static CudaVersion ParseCudaVersionFile(const Driver &D, llvm::StringRef V) {
|
||||
if (!V.startswith("CUDA Version "))
|
||||
return CudaVersion::UNKNOWN;
|
||||
V = V.substr(strlen("CUDA Version "));
|
||||
int Major = -1, Minor = -1;
|
||||
auto First = V.split('.');
|
||||
auto Second = First.second.split('.');
|
||||
if (First.first.getAsInteger(10, Major) ||
|
||||
Second.first.getAsInteger(10, Minor))
|
||||
SmallVector<StringRef,4> VersionParts;
|
||||
V.split(VersionParts, '.');
|
||||
if (VersionParts.size() < 2)
|
||||
return CudaVersion::UNKNOWN;
|
||||
std::string MajorMinor = join_items(".", VersionParts[0], VersionParts[1]);
|
||||
CudaVersion Version = CudaStringToVersion(MajorMinor);
|
||||
if (Version != CudaVersion::UNKNOWN)
|
||||
return Version;
|
||||
|
||||
if (Major == 7 && Minor == 0) {
|
||||
// This doesn't appear to ever happen -- version.txt doesn't exist in the
|
||||
// CUDA 7 installs I've seen. But no harm in checking.
|
||||
return CudaVersion::CUDA_70;
|
||||
}
|
||||
if (Major == 7 && Minor == 5)
|
||||
return CudaVersion::CUDA_75;
|
||||
if (Major == 8 && Minor == 0)
|
||||
return CudaVersion::CUDA_80;
|
||||
if (Major == 9 && Minor == 0)
|
||||
return CudaVersion::CUDA_90;
|
||||
if (Major == 9 && Minor == 1)
|
||||
return CudaVersion::CUDA_91;
|
||||
if (Major == 9 && Minor == 2)
|
||||
return CudaVersion::CUDA_92;
|
||||
if (Major == 10 && Minor == 0)
|
||||
return CudaVersion::CUDA_100;
|
||||
if (Major == 10 && Minor == 1)
|
||||
return CudaVersion::CUDA_101;
|
||||
return CudaVersion::UNKNOWN;
|
||||
// Issue a warning and assume that the version we've found is compatible with
|
||||
// the latest version we support.
|
||||
D.Diag(diag::warn_drv_unknown_cuda_version)
|
||||
<< MajorMinor << CudaVersionToString(CudaVersion::LATEST);
|
||||
return CudaVersion::LATEST;
|
||||
}
|
||||
|
||||
CudaInstallationDetector::CudaInstallationDetector(
|
||||
@ -160,7 +147,7 @@ CudaInstallationDetector::CudaInstallationDetector(
|
||||
// version.txt isn't present.
|
||||
Version = CudaVersion::CUDA_70;
|
||||
} else {
|
||||
Version = ParseCudaVersionFile((*VersionFile)->getBuffer());
|
||||
Version = ParseCudaVersionFile(D, (*VersionFile)->getBuffer());
|
||||
}
|
||||
|
||||
if (Version >= CudaVersion::CUDA_90) {
|
||||
|
@ -3440,6 +3440,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
|
||||
Opts.LexEditorPlaceholders = false;
|
||||
|
||||
Opts.SetUpStaticAnalyzer = Args.hasArg(OPT_setup_static_analyzer);
|
||||
Opts.DisablePragmaDebugCrash = Args.hasArg(OPT_disable_pragma_debug_crash);
|
||||
}
|
||||
|
||||
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
|
||||
|
@ -45,7 +45,7 @@
|
||||
_Static_assert(sizeof(__val) == sizeof(__Bits)); \
|
||||
_Static_assert(sizeof(__Bits) == 2 * sizeof(int)); \
|
||||
__Bits __tmp; \
|
||||
memcpy(&__val, &__tmp, sizeof(__val)); \
|
||||
memcpy(&__tmp, &__val, sizeof(__val)); \
|
||||
__tmp.__a = ::__FnName(__tmp.__a, __offset, __width); \
|
||||
__tmp.__b = ::__FnName(__tmp.__b, __offset, __width); \
|
||||
long long __ret; \
|
||||
@ -129,7 +129,7 @@ __MAKE_SHUFFLES(__shfl_xor, __nvvm_shfl_bfly_i32, __nvvm_shfl_bfly_f32, 0x1f,
|
||||
_Static_assert(sizeof(__val) == sizeof(__Bits)); \
|
||||
_Static_assert(sizeof(__Bits) == 2 * sizeof(int)); \
|
||||
__Bits __tmp; \
|
||||
memcpy(&__val, &__tmp, sizeof(__val)); \
|
||||
memcpy(&__tmp, &__val, sizeof(__val)); \
|
||||
__tmp.__a = ::__FnName(__mask, __tmp.__a, __offset, __width); \
|
||||
__tmp.__b = ::__FnName(__mask, __tmp.__b, __offset, __width); \
|
||||
long long __ret; \
|
||||
|
@ -48,7 +48,7 @@
|
||||
#include "cuda.h"
|
||||
#if !defined(CUDA_VERSION)
|
||||
#error "cuda.h did not define CUDA_VERSION"
|
||||
#elif CUDA_VERSION < 7000 || CUDA_VERSION > 10010
|
||||
#elif CUDA_VERSION < 7000
|
||||
#error "Unsupported CUDA version!"
|
||||
#endif
|
||||
|
||||
|
@ -2181,7 +2181,7 @@ void _mm_sfence(void);
|
||||
/// 3: Bits [63:48] are copied to the destination.
|
||||
/// \returns A 16-bit integer containing the extracted 16 bits of packed data.
|
||||
#define _mm_extract_pi16(a, n) \
|
||||
(int)__builtin_ia32_vec_ext_v4hi((__m64)a, (int)n)
|
||||
(int)__builtin_ia32_vec_ext_v4hi((__v4hi)a, (int)n)
|
||||
|
||||
/// Copies data from the 64-bit vector of [4 x i16] to the destination,
|
||||
/// and inserts the lower 16-bits of an integer operand at the 16-bit offset
|
||||
@ -2212,7 +2212,7 @@ void _mm_sfence(void);
|
||||
/// \returns A 64-bit integer vector containing the copied packed data from the
|
||||
/// operands.
|
||||
#define _mm_insert_pi16(a, d, n) \
|
||||
(__m64)__builtin_ia32_vec_set_v4hi((__m64)a, (int)d, (int)n)
|
||||
(__m64)__builtin_ia32_vec_set_v4hi((__v4hi)a, (int)d, (int)n)
|
||||
|
||||
/// Compares each of the corresponding packed 16-bit integer values of
|
||||
/// the 64-bit integer vectors, and writes the greater value to the
|
||||
|
@ -2552,8 +2552,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
|
||||
'/', '/', '/', '/', '/', '/', '/', '/',
|
||||
'/', '/', '/', '/', '/', '/', '/', '/'
|
||||
};
|
||||
while (CurPtr+16 <= BufferEnd &&
|
||||
!vec_any_eq(*(const vector unsigned char*)CurPtr, Slashes))
|
||||
while (CurPtr + 16 <= BufferEnd &&
|
||||
!vec_any_eq(*(const __vector unsigned char *)CurPtr, Slashes))
|
||||
CurPtr += 16;
|
||||
#else
|
||||
// Scan for '/' quickly. Many block comments are very large.
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/PreprocessorLexer.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
#include "clang/Lex/Token.h"
|
||||
#include "clang/Lex/TokenLexer.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
@ -39,7 +40,6 @@
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/CrashRecoveryContext.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <algorithm>
|
||||
@ -1035,15 +1035,19 @@ struct PragmaDebugHandler : public PragmaHandler {
|
||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
|
||||
if (II->isStr("assert")) {
|
||||
llvm_unreachable("This is an assertion!");
|
||||
if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
|
||||
llvm_unreachable("This is an assertion!");
|
||||
} else if (II->isStr("crash")) {
|
||||
LLVM_BUILTIN_TRAP;
|
||||
if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
|
||||
LLVM_BUILTIN_TRAP;
|
||||
} else if (II->isStr("parser_crash")) {
|
||||
Token Crasher;
|
||||
Crasher.startToken();
|
||||
Crasher.setKind(tok::annot_pragma_parser_crash);
|
||||
Crasher.setAnnotationRange(SourceRange(Tok.getLocation()));
|
||||
PP.EnterToken(Crasher, /*IsReinject*/false);
|
||||
if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) {
|
||||
Token Crasher;
|
||||
Crasher.startToken();
|
||||
Crasher.setKind(tok::annot_pragma_parser_crash);
|
||||
Crasher.setAnnotationRange(SourceRange(Tok.getLocation()));
|
||||
PP.EnterToken(Crasher, /*IsReinject*/ false);
|
||||
}
|
||||
} else if (II->isStr("dump")) {
|
||||
Token Identifier;
|
||||
PP.LexUnexpandedToken(Identifier);
|
||||
@ -1075,9 +1079,11 @@ struct PragmaDebugHandler : public PragmaHandler {
|
||||
<< II->getName();
|
||||
}
|
||||
} else if (II->isStr("llvm_fatal_error")) {
|
||||
llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error");
|
||||
if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
|
||||
llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error");
|
||||
} else if (II->isStr("llvm_unreachable")) {
|
||||
llvm_unreachable("#pragma clang __debug llvm_unreachable");
|
||||
if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
|
||||
llvm_unreachable("#pragma clang __debug llvm_unreachable");
|
||||
} else if (II->isStr("macro")) {
|
||||
Token MacroName;
|
||||
PP.LexUnexpandedToken(MacroName);
|
||||
@ -1104,11 +1110,8 @@ struct PragmaDebugHandler : public PragmaHandler {
|
||||
}
|
||||
M->dump();
|
||||
} else if (II->isStr("overflow_stack")) {
|
||||
DebugOverflowStack();
|
||||
} else if (II->isStr("handle_crash")) {
|
||||
llvm::CrashRecoveryContext *CRC =llvm::CrashRecoveryContext::GetCurrent();
|
||||
if (CRC)
|
||||
CRC->HandleCrash();
|
||||
if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash)
|
||||
DebugOverflowStack();
|
||||
} else if (II->isStr("captured")) {
|
||||
HandleCaptured(PP);
|
||||
} else {
|
||||
|
@ -5060,6 +5060,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
||||
// recurse to handle whatever we get.
|
||||
if (TryAnnotateTypeOrScopeToken())
|
||||
return true;
|
||||
if (TryAnnotateTypeConstraint())
|
||||
return true;
|
||||
if (Tok.is(tok::identifier))
|
||||
return false;
|
||||
|
||||
@ -5192,11 +5194,14 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
||||
|
||||
// placeholder-type-specifier
|
||||
case tok::annot_template_id: {
|
||||
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
|
||||
return TemplateId->Kind == TNK_Concept_template &&
|
||||
return isTypeConstraintAnnotation() &&
|
||||
(NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype));
|
||||
}
|
||||
|
||||
case tok::annot_cxxscope:
|
||||
if (NextToken().is(tok::identifier) && TryAnnotateTypeConstraint())
|
||||
return true;
|
||||
return isTypeConstraintAnnotation() &&
|
||||
GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype);
|
||||
case tok::kw___declspec:
|
||||
case tok::kw___cdecl:
|
||||
case tok::kw___stdcall:
|
||||
|
@ -2716,7 +2716,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||
// C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains
|
||||
// to a friend declaration, that declaration shall be a definition.
|
||||
if (DeclaratorInfo.isFunctionDeclarator() &&
|
||||
DefinitionKind != FDK_Definition && DS.isFriendSpecified()) {
|
||||
DefinitionKind == FDK_Declaration && DS.isFriendSpecified()) {
|
||||
// Diagnose attributes that appear before decl specifier:
|
||||
// [[]] friend int foo();
|
||||
ProhibitAttributes(FnAttrs);
|
||||
|
@ -3374,25 +3374,6 @@ ExprResult Parser::ParseRequiresExpression() {
|
||||
Diag(Tok, diag::err_requires_expr_missing_arrow)
|
||||
<< FixItHint::CreateInsertion(Tok.getLocation(), "->");
|
||||
// Try to parse a 'type-constraint'
|
||||
CXXScopeSpec SS;
|
||||
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
|
||||
/*EnteringContext=*/false,
|
||||
/*MayBePseudoDestructor=*/nullptr,
|
||||
// If this is not a type-constraint,
|
||||
// then this scope-spec is part of
|
||||
// the typename of a non-type
|
||||
// template parameter
|
||||
/*IsTypename=*/true,
|
||||
/*LastII=*/nullptr,
|
||||
// We won't find concepts in
|
||||
// non-namespaces anyway, so might as
|
||||
// well parse this correctly for
|
||||
// possible type names.
|
||||
/*OnlyNamespace=*/false,
|
||||
/*SuppressDiagnostic=*/true)) {
|
||||
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
|
||||
break;
|
||||
}
|
||||
if (TryAnnotateTypeConstraint()) {
|
||||
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
|
||||
break;
|
||||
@ -3402,8 +3383,13 @@ ExprResult Parser::ParseRequiresExpression() {
|
||||
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
|
||||
break;
|
||||
}
|
||||
if (Tok.is(tok::annot_cxxscope))
|
||||
CXXScopeSpec SS;
|
||||
if (Tok.is(tok::annot_cxxscope)) {
|
||||
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
|
||||
Tok.getAnnotationRange(),
|
||||
SS);
|
||||
ConsumeAnnotationToken();
|
||||
}
|
||||
|
||||
Req = Actions.ActOnCompoundRequirement(
|
||||
Expression.get(), NoexceptLoc, SS, takeTemplateIdAnnotation(Tok),
|
||||
@ -3490,6 +3476,7 @@ ExprResult Parser::ParseRequiresExpression() {
|
||||
// We need to consume the typename to allow 'requires { typename a; }'
|
||||
SourceLocation TypenameKWLoc = ConsumeToken();
|
||||
if (TryAnnotateCXXScopeToken()) {
|
||||
TPA.Commit();
|
||||
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
|
||||
break;
|
||||
}
|
||||
|
@ -2311,6 +2311,24 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
|
||||
return SuccessResult;
|
||||
}
|
||||
|
||||
// Diagnose address space conversion in nested pointers.
|
||||
QualType DestPtee = DestType->getPointeeType().isNull()
|
||||
? DestType->getPointeeType()
|
||||
: DestType->getPointeeType()->getPointeeType();
|
||||
QualType SrcPtee = SrcType->getPointeeType().isNull()
|
||||
? SrcType->getPointeeType()
|
||||
: SrcType->getPointeeType()->getPointeeType();
|
||||
while (!DestPtee.isNull() && !SrcPtee.isNull()) {
|
||||
if (DestPtee.getAddressSpace() != SrcPtee.getAddressSpace()) {
|
||||
Self.Diag(OpRange.getBegin(),
|
||||
diag::warn_bad_cxx_cast_nested_pointer_addr_space)
|
||||
<< CStyle << SrcType << DestType << SrcExpr.get()->getSourceRange();
|
||||
break;
|
||||
}
|
||||
DestPtee = DestPtee->getPointeeType();
|
||||
SrcPtee = SrcPtee->getPointeeType();
|
||||
}
|
||||
|
||||
// C++ 5.2.10p7: A pointer to an object can be explicitly converted to
|
||||
// a pointer to an object of different type.
|
||||
// Void pointers are not specified, but supported by every compiler out there.
|
||||
|
@ -167,9 +167,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename TemplateDeclT>
|
||||
static bool calculateConstraintSatisfaction(
|
||||
Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs,
|
||||
Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
|
||||
SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
|
||||
const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
|
||||
return calculateConstraintSatisfaction(
|
||||
@ -182,8 +181,9 @@ static bool calculateConstraintSatisfaction(
|
||||
{
|
||||
TemplateDeductionInfo Info(TemplateNameLoc);
|
||||
Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(),
|
||||
Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template,
|
||||
Info, AtomicExpr->getSourceRange());
|
||||
Sema::InstantiatingTemplate::ConstraintSubstitution{},
|
||||
const_cast<NamedDecl *>(Template), Info,
|
||||
AtomicExpr->getSourceRange());
|
||||
if (Inst.isInvalid())
|
||||
return ExprError();
|
||||
// We do not want error diagnostics escaping here.
|
||||
@ -230,8 +230,7 @@ static bool calculateConstraintSatisfaction(
|
||||
});
|
||||
}
|
||||
|
||||
template<typename TemplateDeclT>
|
||||
static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
|
||||
static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template,
|
||||
ArrayRef<const Expr *> ConstraintExprs,
|
||||
ArrayRef<TemplateArgument> TemplateArgs,
|
||||
SourceRange TemplateIDRange,
|
||||
@ -249,8 +248,8 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
|
||||
}
|
||||
|
||||
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
|
||||
Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
|
||||
TemplateIDRange);
|
||||
Sema::InstantiatingTemplate::ConstraintsCheck{},
|
||||
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
|
||||
if (Inst.isInvalid())
|
||||
return true;
|
||||
|
||||
@ -273,7 +272,7 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
|
||||
}
|
||||
|
||||
bool Sema::CheckConstraintSatisfaction(
|
||||
NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
|
||||
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
|
||||
ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange,
|
||||
ConstraintSatisfaction &OutSatisfaction) {
|
||||
if (ConstraintExprs.empty()) {
|
||||
@ -284,7 +283,8 @@ bool Sema::CheckConstraintSatisfaction(
|
||||
llvm::FoldingSetNodeID ID;
|
||||
void *InsertPos;
|
||||
ConstraintSatisfaction *Satisfaction = nullptr;
|
||||
if (LangOpts.ConceptSatisfactionCaching) {
|
||||
bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template;
|
||||
if (ShouldCache) {
|
||||
ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
|
||||
Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos);
|
||||
if (Satisfaction) {
|
||||
@ -295,27 +295,15 @@ bool Sema::CheckConstraintSatisfaction(
|
||||
} else {
|
||||
Satisfaction = &OutSatisfaction;
|
||||
}
|
||||
bool Failed;
|
||||
if (auto *T = dyn_cast<TemplateDecl>(Template))
|
||||
Failed = ::CheckConstraintSatisfaction(*this, T, ConstraintExprs,
|
||||
TemplateArgs, TemplateIDRange,
|
||||
*Satisfaction);
|
||||
else if (auto *P =
|
||||
dyn_cast<ClassTemplatePartialSpecializationDecl>(Template))
|
||||
Failed = ::CheckConstraintSatisfaction(*this, P, ConstraintExprs,
|
||||
TemplateArgs, TemplateIDRange,
|
||||
*Satisfaction);
|
||||
else
|
||||
Failed = ::CheckConstraintSatisfaction(
|
||||
*this, cast<VarTemplatePartialSpecializationDecl>(Template),
|
||||
ConstraintExprs, TemplateArgs, TemplateIDRange, *Satisfaction);
|
||||
if (Failed) {
|
||||
if (LangOpts.ConceptSatisfactionCaching)
|
||||
if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
|
||||
TemplateArgs, TemplateIDRange,
|
||||
*Satisfaction)) {
|
||||
if (ShouldCache)
|
||||
delete Satisfaction;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (LangOpts.ConceptSatisfactionCaching) {
|
||||
if (ShouldCache) {
|
||||
// We cannot use InsertNode here because CheckConstraintSatisfaction might
|
||||
// have invalidated it.
|
||||
SatisfactionCache.InsertNode(Satisfaction);
|
||||
@ -333,6 +321,30 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
|
||||
});
|
||||
}
|
||||
|
||||
bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
|
||||
ConstraintSatisfaction &Satisfaction,
|
||||
SourceLocation UsageLoc) {
|
||||
const Expr *RC = FD->getTrailingRequiresClause();
|
||||
if (RC->isInstantiationDependent()) {
|
||||
Satisfaction.IsSatisfied = true;
|
||||
return false;
|
||||
}
|
||||
Qualifiers ThisQuals;
|
||||
CXXRecordDecl *Record = nullptr;
|
||||
if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
|
||||
ThisQuals = Method->getMethodQualifiers();
|
||||
Record = const_cast<CXXRecordDecl *>(Method->getParent());
|
||||
}
|
||||
CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
|
||||
// We substitute with empty arguments in order to rebuild the atomic
|
||||
// constraint in a constant-evaluated context.
|
||||
// FIXME: Should this be a dedicated TreeTransform?
|
||||
return CheckConstraintSatisfaction(
|
||||
FD, {RC}, /*TemplateArgs=*/{},
|
||||
SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
|
||||
Satisfaction);
|
||||
}
|
||||
|
||||
bool Sema::EnsureTemplateArgumentListConstraints(
|
||||
TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
|
||||
SourceRange TemplateIDRange) {
|
||||
@ -671,6 +683,10 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
|
||||
ArgsAsWritten->arguments().back().getSourceRange().getEnd()));
|
||||
if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
|
||||
return true;
|
||||
Atomic.ParameterMapping.emplace(
|
||||
MutableArrayRef<TemplateArgumentLoc>(
|
||||
new (S.Context) TemplateArgumentLoc[SubstArgs.size()],
|
||||
SubstArgs.size()));
|
||||
std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
|
||||
N.getAtomicConstraint()->ParameterMapping->begin());
|
||||
return false;
|
||||
|
@ -12526,6 +12526,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
|
||||
var->getDeclContext()->getRedeclContext()->isFileContext() &&
|
||||
var->isExternallyVisible() && var->hasLinkage() &&
|
||||
!var->isInline() && !var->getDescribedVarTemplate() &&
|
||||
!isa<VarTemplatePartialSpecializationDecl>(var) &&
|
||||
!isTemplateInstantiation(var->getTemplateSpecializationKind()) &&
|
||||
!getDiagnostics().isIgnored(diag::warn_missing_variable_declarations,
|
||||
var->getLocation())) {
|
||||
|
@ -7373,7 +7373,14 @@ class DefaultedComparisonAnalyzer
|
||||
/// resolution [...]
|
||||
CandidateSet.exclude(FD);
|
||||
|
||||
S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args);
|
||||
if (Args[0]->getType()->isOverloadableType())
|
||||
S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args);
|
||||
else {
|
||||
// FIXME: We determine whether this is a valid expression by checking to
|
||||
// see if there's a viable builtin operator candidate for it. That isn't
|
||||
// really what the rules ask us to do, but should give the right results.
|
||||
S.AddBuiltinOperatorCandidates(OO, FD->getLocation(), Args, CandidateSet);
|
||||
}
|
||||
|
||||
Result R;
|
||||
|
||||
@ -7438,6 +7445,31 @@ class DefaultedComparisonAnalyzer
|
||||
|
||||
if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) {
|
||||
if (auto *BestFD = Best->Function) {
|
||||
// If any callee has an undeduced return type, deduce it now.
|
||||
// FIXME: It's not clear how a failure here should be handled. For
|
||||
// now, we produce an eager diagnostic, because that is forward
|
||||
// compatible with most (all?) other reasonable options.
|
||||
if (BestFD->getReturnType()->isUndeducedType() &&
|
||||
S.DeduceReturnType(BestFD, FD->getLocation(),
|
||||
/*Diagnose=*/false)) {
|
||||
// Don't produce a duplicate error when asked to explain why the
|
||||
// comparison is deleted: we diagnosed that when initially checking
|
||||
// the defaulted operator.
|
||||
if (Diagnose == NoDiagnostics) {
|
||||
S.Diag(
|
||||
FD->getLocation(),
|
||||
diag::err_defaulted_comparison_cannot_deduce_undeduced_auto)
|
||||
<< Subobj.Kind << Subobj.Decl;
|
||||
S.Diag(
|
||||
Subobj.Loc,
|
||||
diag::note_defaulted_comparison_cannot_deduce_undeduced_auto)
|
||||
<< Subobj.Kind << Subobj.Decl;
|
||||
S.Diag(BestFD->getLocation(),
|
||||
diag::note_defaulted_comparison_cannot_deduce_callee)
|
||||
<< Subobj.Kind << Subobj.Decl;
|
||||
}
|
||||
return Result::deleted();
|
||||
}
|
||||
if (auto *Info = S.Context.CompCategories.lookupInfoForType(
|
||||
BestFD->getCallResultType())) {
|
||||
R.Category = Info->Kind;
|
||||
@ -7826,10 +7858,14 @@ class DefaultedComparisonSynthesizer
|
||||
return StmtError();
|
||||
|
||||
OverloadedOperatorKind OO = FD->getOverloadedOperator();
|
||||
ExprResult Op = S.CreateOverloadedBinOp(
|
||||
Loc, BinaryOperator::getOverloadedOpcode(OO), Fns,
|
||||
Obj.first.get(), Obj.second.get(), /*PerformADL=*/true,
|
||||
/*AllowRewrittenCandidates=*/true, FD);
|
||||
BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(OO);
|
||||
ExprResult Op;
|
||||
if (Type->isOverloadableType())
|
||||
Op = S.CreateOverloadedBinOp(Loc, Opc, Fns, Obj.first.get(),
|
||||
Obj.second.get(), /*PerformADL=*/true,
|
||||
/*AllowRewrittenCandidates=*/true, FD);
|
||||
else
|
||||
Op = S.CreateBuiltinBinOp(Loc, Opc, Obj.first.get(), Obj.second.get());
|
||||
if (Op.isInvalid())
|
||||
return StmtError();
|
||||
|
||||
@ -7869,8 +7905,12 @@ class DefaultedComparisonSynthesizer
|
||||
llvm::APInt ZeroVal(S.Context.getIntWidth(S.Context.IntTy), 0);
|
||||
Expr *Zero =
|
||||
IntegerLiteral::Create(S.Context, ZeroVal, S.Context.IntTy, Loc);
|
||||
ExprResult Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(),
|
||||
Zero, true, true, FD);
|
||||
ExprResult Comp;
|
||||
if (VDRef.get()->getType()->isOverloadableType())
|
||||
Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(), Zero, true,
|
||||
true, FD);
|
||||
else
|
||||
Comp = S.CreateBuiltinBinOp(Loc, BO_NE, VDRef.get(), Zero);
|
||||
if (Comp.isInvalid())
|
||||
return StmtError();
|
||||
Sema::ConditionResult Cond = S.ActOnCondition(
|
||||
|
@ -245,8 +245,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
||||
return true;
|
||||
}
|
||||
|
||||
// See if this is a deleted function.
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
// See if this is a deleted function.
|
||||
if (FD->isDeleted()) {
|
||||
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
|
||||
if (Ctor && Ctor->isInheritingConstructor())
|
||||
@ -259,6 +259,29 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
||||
return true;
|
||||
}
|
||||
|
||||
// [expr.prim.id]p4
|
||||
// A program that refers explicitly or implicitly to a function with a
|
||||
// trailing requires-clause whose constraint-expression is not satisfied,
|
||||
// other than to declare it, is ill-formed. [...]
|
||||
//
|
||||
// See if this is a function with constraints that need to be satisfied.
|
||||
// Check this before deducing the return type, as it might instantiate the
|
||||
// definition.
|
||||
if (FD->getTrailingRequiresClause()) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
if (CheckFunctionConstraints(FD, Satisfaction, Loc))
|
||||
// A diagnostic will have already been generated (non-constant
|
||||
// constraint expression, for example)
|
||||
return true;
|
||||
if (!Satisfaction.IsSatisfied) {
|
||||
Diag(Loc,
|
||||
diag::err_reference_to_function_with_unsatisfied_constraints)
|
||||
<< D;
|
||||
DiagnoseUnsatisfiedConstraint(Satisfaction);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the function has a deduced return type, and we can't deduce it,
|
||||
// then we can't use it either.
|
||||
if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() &&
|
||||
@ -326,30 +349,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
||||
|
||||
diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
|
||||
|
||||
// [expr.prim.id]p4
|
||||
// A program that refers explicitly or implicitly to a function with a
|
||||
// trailing requires-clause whose constraint-expression is not satisfied,
|
||||
// other than to declare it, is ill-formed. [...]
|
||||
//
|
||||
// See if this is a function with constraints that need to be satisfied.
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
if (Expr *RC = FD->getTrailingRequiresClause()) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
bool Failed = CheckConstraintSatisfaction(RC, Satisfaction);
|
||||
if (Failed)
|
||||
// A diagnostic will have already been generated (non-constant
|
||||
// constraint expression, for example)
|
||||
return true;
|
||||
if (!Satisfaction.IsSatisfied) {
|
||||
Diag(Loc,
|
||||
diag::err_reference_to_function_with_unsatisfied_constraints)
|
||||
<< D;
|
||||
DiagnoseUnsatisfiedConstraint(Satisfaction);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isa<ParmVarDecl>(D) && isa<RequiresExprBodyDecl>(D->getDeclContext()) &&
|
||||
!isUnevaluatedContext()) {
|
||||
// C++ [expr.prim.req.nested] p3
|
||||
|
@ -8487,7 +8487,8 @@ concepts::NestedRequirement *
|
||||
Sema::BuildNestedRequirement(Expr *Constraint) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
if (!Constraint->isInstantiationDependent() &&
|
||||
CheckConstraintSatisfaction(Constraint, Satisfaction))
|
||||
CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{},
|
||||
Constraint->getSourceRange(), Satisfaction))
|
||||
return nullptr;
|
||||
return new (Context) concepts::NestedRequirement(Context, Constraint,
|
||||
Satisfaction);
|
||||
|
@ -3176,7 +3176,7 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
|
||||
/// FromType and \p ToType is permissible, given knowledge about whether every
|
||||
/// outer layer is const-qualified.
|
||||
static bool isQualificationConversionStep(QualType FromType, QualType ToType,
|
||||
bool CStyle,
|
||||
bool CStyle, bool IsTopLevel,
|
||||
bool &PreviousToQualsIncludeConst,
|
||||
bool &ObjCLifetimeConversion) {
|
||||
Qualifiers FromQuals = FromType.getQualifiers();
|
||||
@ -3213,11 +3213,15 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType,
|
||||
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
|
||||
return false;
|
||||
|
||||
// For a C-style cast, just require the address spaces to overlap.
|
||||
// FIXME: Does "superset" also imply the representation of a pointer is the
|
||||
// same? We're assuming that it does here and in compatiblyIncludes.
|
||||
if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
|
||||
!FromQuals.isAddressSpaceSupersetOf(ToQuals))
|
||||
// If address spaces mismatch:
|
||||
// - in top level it is only valid to convert to addr space that is a
|
||||
// superset in all cases apart from C-style casts where we allow
|
||||
// conversions between overlapping address spaces.
|
||||
// - in non-top levels it is not a valid conversion.
|
||||
if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() &&
|
||||
(!IsTopLevel ||
|
||||
!(ToQuals.isAddressSpaceSupersetOf(FromQuals) ||
|
||||
(CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals)))))
|
||||
return false;
|
||||
|
||||
// -- if the cv 1,j and cv 2,j are different, then const is in
|
||||
@ -3258,9 +3262,9 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
|
||||
bool PreviousToQualsIncludeConst = true;
|
||||
bool UnwrappedAnyPointer = false;
|
||||
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
|
||||
if (!isQualificationConversionStep(FromType, ToType, CStyle,
|
||||
PreviousToQualsIncludeConst,
|
||||
ObjCLifetimeConversion))
|
||||
if (!isQualificationConversionStep(
|
||||
FromType, ToType, CStyle, !UnwrappedAnyPointer,
|
||||
PreviousToQualsIncludeConst, ObjCLifetimeConversion))
|
||||
return false;
|
||||
UnwrappedAnyPointer = true;
|
||||
}
|
||||
@ -4499,7 +4503,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
|
||||
// If we find a qualifier mismatch, the types are not reference-compatible,
|
||||
// but are still be reference-related if they're similar.
|
||||
bool ObjCLifetimeConversion = false;
|
||||
if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false,
|
||||
if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel,
|
||||
PreviousToQualsIncludeConst,
|
||||
ObjCLifetimeConversion))
|
||||
return (ConvertedReferent || Context.hasSimilarType(T1, T2))
|
||||
@ -6291,9 +6295,9 @@ void Sema::AddOverloadCandidate(
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expr *RequiresClause = Function->getTrailingRequiresClause()) {
|
||||
if (Function->getTrailingRequiresClause()) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
|
||||
if (CheckFunctionConstraints(Function, Satisfaction) ||
|
||||
!Satisfaction.IsSatisfied) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
|
||||
@ -6808,9 +6812,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
|
||||
return;
|
||||
}
|
||||
|
||||
if (Expr *RequiresClause = Method->getTrailingRequiresClause()) {
|
||||
if (Method->getTrailingRequiresClause()) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
|
||||
if (CheckFunctionConstraints(Method, Satisfaction) ||
|
||||
!Satisfaction.IsSatisfied) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
|
||||
@ -7204,10 +7208,9 @@ void Sema::AddConversionCandidate(
|
||||
return;
|
||||
}
|
||||
|
||||
Expr *RequiresClause = Conversion->getTrailingRequiresClause();
|
||||
if (RequiresClause) {
|
||||
if (Conversion->getTrailingRequiresClause()) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
|
||||
if (CheckFunctionConstraints(Conversion, Satisfaction) ||
|
||||
!Satisfaction.IsSatisfied) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
|
||||
@ -9270,17 +9273,31 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
|
||||
if (ExplicitTemplateArgs)
|
||||
continue;
|
||||
|
||||
AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet,
|
||||
/*SuppressUserConversions=*/false, PartialOverloading,
|
||||
/*AllowExplicit*/ true,
|
||||
/*AllowExplicitConversions*/ false,
|
||||
ADLCallKind::UsesADL);
|
||||
AddOverloadCandidate(
|
||||
FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false,
|
||||
PartialOverloading, /*AllowExplicit=*/true,
|
||||
/*AllowExplicitConversions=*/false, ADLCallKind::UsesADL);
|
||||
if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) {
|
||||
AddOverloadCandidate(
|
||||
FD, FoundDecl, {Args[1], Args[0]}, CandidateSet,
|
||||
/*SuppressUserConversions=*/false, PartialOverloading,
|
||||
/*AllowExplicit=*/true, /*AllowExplicitConversions=*/false,
|
||||
ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed);
|
||||
}
|
||||
} else {
|
||||
auto *FTD = cast<FunctionTemplateDecl>(*I);
|
||||
AddTemplateOverloadCandidate(
|
||||
cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args,
|
||||
CandidateSet,
|
||||
FTD, FoundDecl, ExplicitTemplateArgs, Args, CandidateSet,
|
||||
/*SuppressUserConversions=*/false, PartialOverloading,
|
||||
/*AllowExplicit*/true, ADLCallKind::UsesADL);
|
||||
/*AllowExplicit=*/true, ADLCallKind::UsesADL);
|
||||
if (CandidateSet.getRewriteInfo().shouldAddReversed(
|
||||
Context, FTD->getTemplatedDecl())) {
|
||||
AddTemplateOverloadCandidate(
|
||||
FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]},
|
||||
CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading,
|
||||
/*AllowExplicit=*/true, ADLCallKind::UsesADL,
|
||||
OverloadCandidateParamOrder::Reversed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9566,17 +9583,15 @@ bool clang::isBetterOverloadCandidate(
|
||||
if (RC1 && RC2) {
|
||||
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
|
||||
if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function,
|
||||
{RC2}, AtLeastAsConstrained1))
|
||||
return false;
|
||||
if (!AtLeastAsConstrained1)
|
||||
return false;
|
||||
if (S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function,
|
||||
{RC2}, AtLeastAsConstrained1) ||
|
||||
S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function,
|
||||
{RC1}, AtLeastAsConstrained2))
|
||||
return false;
|
||||
if (!AtLeastAsConstrained2)
|
||||
return true;
|
||||
} else if (RC1 || RC2)
|
||||
if (AtLeastAsConstrained1 != AtLeastAsConstrained2)
|
||||
return AtLeastAsConstrained1;
|
||||
} else if (RC1 || RC2) {
|
||||
return RC1 != nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9947,9 +9962,9 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const Expr *RC = FD->getTrailingRequiresClause()) {
|
||||
if (FD->getTrailingRequiresClause()) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
if (S.CheckConstraintSatisfaction(RC, Satisfaction))
|
||||
if (S.CheckFunctionConstraints(FD, Satisfaction, Loc))
|
||||
return false;
|
||||
if (!Satisfaction.IsSatisfied) {
|
||||
if (Complain) {
|
||||
@ -10974,8 +10989,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
||||
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
|
||||
<< FnDesc /* Ignored */;
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(),
|
||||
Satisfaction))
|
||||
if (S.CheckFunctionConstraints(Fn, Satisfaction))
|
||||
break;
|
||||
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
|
||||
}
|
||||
|
@ -2047,12 +2047,14 @@ struct ConvertConstructorToDeductionGuideTransform {
|
||||
if (const auto *TC = TTP->getTypeConstraint()) {
|
||||
TemplateArgumentListInfo TransformedArgs;
|
||||
const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten();
|
||||
if (SemaRef.Subst(ArgsAsWritten->getTemplateArgs(),
|
||||
if (!ArgsAsWritten ||
|
||||
SemaRef.Subst(ArgsAsWritten->getTemplateArgs(),
|
||||
ArgsAsWritten->NumTemplateArgs, TransformedArgs,
|
||||
Args))
|
||||
SemaRef.AttachTypeConstraint(
|
||||
TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
|
||||
TC->getNamedConcept(), &TransformedArgs, NewTTP,
|
||||
TC->getNamedConcept(), ArgsAsWritten ? &TransformedArgs : nullptr,
|
||||
NewTTP,
|
||||
NewTTP->isParameterPack()
|
||||
? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
|
||||
->getEllipsisLoc()
|
||||
|
@ -2488,7 +2488,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
|
||||
case TemplateArgument::Template:
|
||||
case TemplateArgument::TemplateExpansion: {
|
||||
NestedNameSpecifierLocBuilder Builder;
|
||||
TemplateName Template = Arg.getAsTemplate();
|
||||
TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
|
||||
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
|
||||
Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
|
||||
else if (QualifiedTemplateName *QTN =
|
||||
@ -2514,27 +2514,10 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
|
||||
}
|
||||
|
||||
TemplateArgumentLoc
|
||||
Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm,
|
||||
Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm,
|
||||
SourceLocation Location) {
|
||||
if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParm))
|
||||
return getTrivialTemplateArgumentLoc(
|
||||
TemplateArgument(
|
||||
Context.getTemplateTypeParmType(TTP->getDepth(), TTP->getIndex(),
|
||||
TTP->isParameterPack(), TTP)),
|
||||
QualType(), Location.isValid() ? Location : TTP->getLocation());
|
||||
else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParm))
|
||||
return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)),
|
||||
QualType(),
|
||||
Location.isValid() ? Location :
|
||||
TTP->getLocation());
|
||||
auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParm);
|
||||
CXXScopeSpec SS;
|
||||
DeclarationNameInfo Info(NTTP->getDeclName(),
|
||||
Location.isValid() ? Location : NTTP->getLocation());
|
||||
Expr *E = BuildDeclarationNameExpr(SS, Info, NTTP).get();
|
||||
return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(),
|
||||
Location.isValid() ? Location :
|
||||
NTTP->getLocation());
|
||||
return getTrivialTemplateArgumentLoc(
|
||||
Context.getInjectedTemplateArg(TemplateParm), QualType(), Location);
|
||||
}
|
||||
|
||||
/// Convert the given deduced template argument and add it to the set of
|
||||
@ -3456,13 +3439,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
|
||||
// ([temp.constr.decl]), those constraints are checked for satisfaction
|
||||
// ([temp.constr.constr]). If the constraints are not satisfied, type
|
||||
// deduction fails.
|
||||
if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
|
||||
Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
|
||||
return TDK_MiscellaneousDeductionFailure;
|
||||
if (!PartialOverloading ||
|
||||
(Builder.size() == FunctionTemplate->getTemplateParameters()->size())) {
|
||||
if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
|
||||
Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
|
||||
return TDK_MiscellaneousDeductionFailure;
|
||||
|
||||
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
|
||||
Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
|
||||
return TDK_ConstraintsNotSatisfied;
|
||||
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
|
||||
Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
|
||||
return TDK_ConstraintsNotSatisfied;
|
||||
}
|
||||
}
|
||||
|
||||
if (OriginalCallArgs) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/PrettyDeclStackTrace.h"
|
||||
#include "clang/AST/TypeVisitor.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/Stack.h"
|
||||
#include "clang/Sema/DeclSpec.h"
|
||||
@ -763,21 +764,30 @@ void Sema::PrintInstantiationStack() {
|
||||
|
||||
case CodeSynthesisContext::ConstraintsCheck: {
|
||||
unsigned DiagID = 0;
|
||||
if (!Active->Entity) {
|
||||
Diags.Report(Active->PointOfInstantiation,
|
||||
diag::note_nested_requirement_here)
|
||||
<< Active->InstantiationRange;
|
||||
break;
|
||||
}
|
||||
if (isa<ConceptDecl>(Active->Entity))
|
||||
DiagID = diag::note_concept_specialization_here;
|
||||
else if (isa<TemplateDecl>(Active->Entity))
|
||||
DiagID = diag::note_checking_constraints_for_template_id_here;
|
||||
else if (isa<VarTemplatePartialSpecializationDecl>(Active->Entity))
|
||||
DiagID = diag::note_checking_constraints_for_var_spec_id_here;
|
||||
else {
|
||||
assert(isa<ClassTemplatePartialSpecializationDecl>(Active->Entity));
|
||||
else if (isa<ClassTemplatePartialSpecializationDecl>(Active->Entity))
|
||||
DiagID = diag::note_checking_constraints_for_class_spec_id_here;
|
||||
else {
|
||||
assert(isa<FunctionDecl>(Active->Entity));
|
||||
DiagID = diag::note_checking_constraints_for_function_here;
|
||||
}
|
||||
SmallVector<char, 128> TemplateArgsStr;
|
||||
llvm::raw_svector_ostream OS(TemplateArgsStr);
|
||||
cast<NamedDecl>(Active->Entity)->printName(OS);
|
||||
printTemplateArgumentList(OS, Active->template_arguments(),
|
||||
getPrintingPolicy());
|
||||
if (!isa<FunctionDecl>(Active->Entity))
|
||||
printTemplateArgumentList(OS, Active->template_arguments(),
|
||||
getPrintingPolicy());
|
||||
Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str()
|
||||
<< Active->InstantiationRange;
|
||||
break;
|
||||
@ -1048,6 +1058,8 @@ namespace {
|
||||
NonTypeTemplateParmDecl *D);
|
||||
ExprResult TransformSubstNonTypeTemplateParmPackExpr(
|
||||
SubstNonTypeTemplateParmPackExpr *E);
|
||||
ExprResult TransformSubstNonTypeTemplateParmExpr(
|
||||
SubstNonTypeTemplateParmExpr *E);
|
||||
|
||||
/// Rebuild a DeclRefExpr for a VarDecl reference.
|
||||
ExprResult RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc);
|
||||
@ -1526,6 +1538,44 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
|
||||
Arg);
|
||||
}
|
||||
|
||||
ExprResult
|
||||
TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
|
||||
SubstNonTypeTemplateParmExpr *E) {
|
||||
ExprResult SubstReplacement = TransformExpr(E->getReplacement());
|
||||
if (SubstReplacement.isInvalid())
|
||||
return true;
|
||||
QualType SubstType = TransformType(E->getType());
|
||||
if (SubstType.isNull())
|
||||
return true;
|
||||
// The type may have been previously dependent and not now, which means we
|
||||
// might have to implicit cast the argument to the new type, for example:
|
||||
// template<auto T, decltype(T) U>
|
||||
// concept C = sizeof(U) == 4;
|
||||
// void foo() requires C<2, 'a'> { }
|
||||
// When normalizing foo(), we first form the normalized constraints of C:
|
||||
// AtomicExpr(sizeof(U) == 4,
|
||||
// U=SubstNonTypeTemplateParmExpr(Param=U,
|
||||
// Expr=DeclRef(U),
|
||||
// Type=decltype(T)))
|
||||
// Then we substitute T = 2, U = 'a' into the parameter mapping, and need to
|
||||
// produce:
|
||||
// AtomicExpr(sizeof(U) == 4,
|
||||
// U=SubstNonTypeTemplateParmExpr(Param=U,
|
||||
// Expr=ImpCast(
|
||||
// decltype(2),
|
||||
// SubstNTTPE(Param=U, Expr='a',
|
||||
// Type=char)),
|
||||
// Type=decltype(2)))
|
||||
// The call to CheckTemplateArgument here produces the ImpCast.
|
||||
TemplateArgument Converted;
|
||||
if (SemaRef.CheckTemplateArgument(E->getParameter(), SubstType,
|
||||
SubstReplacement.get(),
|
||||
Converted).isInvalid())
|
||||
return true;
|
||||
return transformNonTypeTemplateParmRef(E->getParameter(),
|
||||
E->getExprLoc(), Converted);
|
||||
}
|
||||
|
||||
ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD,
|
||||
SourceLocation Loc) {
|
||||
DeclarationNameInfo NameInfo(PD->getDeclName(), Loc);
|
||||
@ -2096,6 +2146,94 @@ void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
|
||||
UpdateExceptionSpec(New, ESI);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct GetContainedInventedTypeParmVisitor :
|
||||
public TypeVisitor<GetContainedInventedTypeParmVisitor,
|
||||
TemplateTypeParmDecl *> {
|
||||
using TypeVisitor<GetContainedInventedTypeParmVisitor,
|
||||
TemplateTypeParmDecl *>::Visit;
|
||||
|
||||
TemplateTypeParmDecl *Visit(QualType T) {
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
return Visit(T.getTypePtr());
|
||||
}
|
||||
// The deduced type itself.
|
||||
TemplateTypeParmDecl *VisitTemplateTypeParmType(
|
||||
const TemplateTypeParmType *T) {
|
||||
if (!T->getDecl()->isImplicit())
|
||||
return nullptr;
|
||||
return T->getDecl();
|
||||
}
|
||||
|
||||
// Only these types can contain 'auto' types, and subsequently be replaced
|
||||
// by references to invented parameters.
|
||||
|
||||
TemplateTypeParmDecl *VisitElaboratedType(const ElaboratedType *T) {
|
||||
return Visit(T->getNamedType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitPointerType(const PointerType *T) {
|
||||
return Visit(T->getPointeeType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitBlockPointerType(const BlockPointerType *T) {
|
||||
return Visit(T->getPointeeType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitReferenceType(const ReferenceType *T) {
|
||||
return Visit(T->getPointeeTypeAsWritten());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitMemberPointerType(const MemberPointerType *T) {
|
||||
return Visit(T->getPointeeType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitArrayType(const ArrayType *T) {
|
||||
return Visit(T->getElementType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitDependentSizedExtVectorType(
|
||||
const DependentSizedExtVectorType *T) {
|
||||
return Visit(T->getElementType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitVectorType(const VectorType *T) {
|
||||
return Visit(T->getElementType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitFunctionProtoType(const FunctionProtoType *T) {
|
||||
return VisitFunctionType(T);
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitFunctionType(const FunctionType *T) {
|
||||
return Visit(T->getReturnType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitParenType(const ParenType *T) {
|
||||
return Visit(T->getInnerType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitAttributedType(const AttributedType *T) {
|
||||
return Visit(T->getModifiedType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitMacroQualifiedType(const MacroQualifiedType *T) {
|
||||
return Visit(T->getUnderlyingType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitAdjustedType(const AdjustedType *T) {
|
||||
return Visit(T->getOriginalType());
|
||||
}
|
||||
|
||||
TemplateTypeParmDecl *VisitPackExpansionType(const PackExpansionType *T) {
|
||||
return Visit(T->getPattern());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
int indexAdjustment,
|
||||
@ -2143,6 +2281,46 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// In abbreviated templates, TemplateTypeParmDecls with possible
|
||||
// TypeConstraints are created when the parameter list is originally parsed.
|
||||
// The TypeConstraints can therefore reference other functions parameters in
|
||||
// the abbreviated function template, which is why we must instantiate them
|
||||
// here, when the instantiated versions of those referenced parameters are in
|
||||
// scope.
|
||||
if (TemplateTypeParmDecl *TTP =
|
||||
GetContainedInventedTypeParmVisitor().Visit(OldDI->getType())) {
|
||||
if (const TypeConstraint *TC = TTP->getTypeConstraint()) {
|
||||
auto *Inst = cast_or_null<TemplateTypeParmDecl>(
|
||||
FindInstantiatedDecl(TTP->getLocation(), TTP, TemplateArgs));
|
||||
// We will first get here when instantiating the abbreviated function
|
||||
// template's described function, but we might also get here later.
|
||||
// Make sure we do not instantiate the TypeConstraint more than once.
|
||||
if (Inst && !Inst->getTypeConstraint()) {
|
||||
// TODO: Concepts: do not instantiate the constraint (delayed constraint
|
||||
// substitution)
|
||||
const ASTTemplateArgumentListInfo *TemplArgInfo
|
||||
= TC->getTemplateArgsAsWritten();
|
||||
TemplateArgumentListInfo InstArgs;
|
||||
|
||||
if (TemplArgInfo) {
|
||||
InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
|
||||
InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
|
||||
if (Subst(TemplArgInfo->getTemplateArgs(),
|
||||
TemplArgInfo->NumTemplateArgs, InstArgs, TemplateArgs))
|
||||
return nullptr;
|
||||
}
|
||||
if (AttachTypeConstraint(
|
||||
TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
|
||||
TC->getNamedConcept(), &InstArgs, Inst,
|
||||
TTP->isParameterPack()
|
||||
? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
|
||||
->getEllipsisLoc()
|
||||
: SourceLocation()))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
|
||||
OldParm->getInnerLocStart(),
|
||||
OldParm->getLocation(),
|
||||
|
@ -1837,6 +1837,23 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
|
||||
return nullptr;
|
||||
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
|
||||
|
||||
if (TemplateParams && TemplateParams->size()) {
|
||||
auto *LastParam =
|
||||
dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
|
||||
if (LastParam && LastParam->isImplicit() &&
|
||||
LastParam->hasTypeConstraint()) {
|
||||
// In abbreviated templates, the type-constraints of invented template
|
||||
// type parameters are instantiated with the function type, invalidating
|
||||
// the TemplateParameterList which relied on the template type parameter
|
||||
// not having a type constraint. Recreate the TemplateParameterList with
|
||||
// the updated parameter list.
|
||||
TemplateParams = TemplateParameterList::Create(
|
||||
SemaRef.Context, TemplateParams->getTemplateLoc(),
|
||||
TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
|
||||
TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
|
||||
}
|
||||
}
|
||||
|
||||
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
|
||||
if (QualifierLoc) {
|
||||
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
|
||||
@ -2177,6 +2194,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
|
||||
return nullptr;
|
||||
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
|
||||
|
||||
if (TemplateParams && TemplateParams->size()) {
|
||||
auto *LastParam =
|
||||
dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
|
||||
if (LastParam && LastParam->isImplicit() &&
|
||||
LastParam->hasTypeConstraint()) {
|
||||
// In abbreviated templates, the type-constraints of invented template
|
||||
// type parameters are instantiated with the function type, invalidating
|
||||
// the TemplateParameterList which relied on the template type parameter
|
||||
// not having a type constraint. Recreate the TemplateParameterList with
|
||||
// the updated parameter list.
|
||||
TemplateParams = TemplateParameterList::Create(
|
||||
SemaRef.Context, TemplateParams->getTemplateLoc(),
|
||||
TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
|
||||
TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
|
||||
}
|
||||
}
|
||||
|
||||
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
|
||||
if (QualifierLoc) {
|
||||
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
|
||||
@ -2190,6 +2224,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
|
||||
if (TrailingRequiresClause) {
|
||||
EnterExpressionEvaluationContext ConstantEvaluated(
|
||||
SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
|
||||
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
|
||||
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext,
|
||||
D->getMethodQualifiers(), ThisContext);
|
||||
ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
|
||||
TemplateArgs);
|
||||
if (SubstRC.isInvalid())
|
||||
@ -2522,28 +2559,34 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
|
||||
Inst->setAccess(AS_public);
|
||||
Inst->setImplicit(D->isImplicit());
|
||||
if (auto *TC = D->getTypeConstraint()) {
|
||||
// TODO: Concepts: do not instantiate the constraint (delayed constraint
|
||||
// substitution)
|
||||
const ASTTemplateArgumentListInfo *TemplArgInfo
|
||||
= TC->getTemplateArgsAsWritten();
|
||||
TemplateArgumentListInfo InstArgs;
|
||||
if (!D->isImplicit()) {
|
||||
// Invented template parameter type constraints will be instantiated with
|
||||
// the corresponding auto-typed parameter as it might reference other
|
||||
// parameters.
|
||||
|
||||
if (TemplArgInfo) {
|
||||
InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
|
||||
InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
|
||||
if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
|
||||
TemplArgInfo->NumTemplateArgs,
|
||||
InstArgs, TemplateArgs))
|
||||
// TODO: Concepts: do not instantiate the constraint (delayed constraint
|
||||
// substitution)
|
||||
const ASTTemplateArgumentListInfo *TemplArgInfo
|
||||
= TC->getTemplateArgsAsWritten();
|
||||
TemplateArgumentListInfo InstArgs;
|
||||
|
||||
if (TemplArgInfo) {
|
||||
InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
|
||||
InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
|
||||
if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
|
||||
TemplArgInfo->NumTemplateArgs,
|
||||
InstArgs, TemplateArgs))
|
||||
return nullptr;
|
||||
}
|
||||
if (SemaRef.AttachTypeConstraint(
|
||||
TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
|
||||
TC->getNamedConcept(), &InstArgs, Inst,
|
||||
D->isParameterPack()
|
||||
? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
|
||||
->getEllipsisLoc()
|
||||
: SourceLocation()))
|
||||
return nullptr;
|
||||
}
|
||||
if (SemaRef.AttachTypeConstraint(
|
||||
TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
|
||||
TC->getNamedConcept(), &InstArgs, Inst,
|
||||
D->isParameterPack()
|
||||
? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
|
||||
->getEllipsisLoc()
|
||||
: SourceLocation()))
|
||||
return nullptr;
|
||||
}
|
||||
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
|
||||
TypeSourceInfo *InstantiatedDefaultArg =
|
||||
@ -4246,24 +4289,29 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
|
||||
Sema::ContextRAII savedContext(*this, Decl);
|
||||
LocalInstantiationScope Scope(*this);
|
||||
|
||||
MultiLevelTemplateArgumentList MLTAL =
|
||||
getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
|
||||
|
||||
// If this is not an explicit specialization - we need to get the instantiated
|
||||
// version of the template arguments and add them to scope for the
|
||||
// substitution.
|
||||
if (Decl->isTemplateInstantiation()) {
|
||||
InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(),
|
||||
InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(),
|
||||
MLTAL.getInnermost(), SourceRange());
|
||||
TemplateArgs, SourceRange());
|
||||
if (Inst.isInvalid())
|
||||
return true;
|
||||
MultiLevelTemplateArgumentList MLTAL(
|
||||
*Decl->getTemplateSpecializationArgs());
|
||||
if (addInstantiatedParametersToScope(
|
||||
*this, Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(),
|
||||
Scope, MLTAL))
|
||||
return true;
|
||||
}
|
||||
|
||||
Qualifiers ThisQuals;
|
||||
CXXRecordDecl *Record = nullptr;
|
||||
if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
|
||||
ThisQuals = Method->getMethodQualifiers();
|
||||
Record = Method->getParent();
|
||||
}
|
||||
CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
|
||||
return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
|
||||
PointOfInstantiation, Satisfaction);
|
||||
}
|
||||
|
@ -555,7 +555,7 @@ void ASTDeclReader::Visit(Decl *D) {
|
||||
|
||||
void ASTDeclReader::VisitDecl(Decl *D) {
|
||||
if (D->isTemplateParameter() || D->isTemplateParameterPack() ||
|
||||
isa<ParmVarDecl>(D)) {
|
||||
isa<ParmVarDecl>(D) || isa<ObjCTypeParamDecl>(D)) {
|
||||
// We don't want to deserialize the DeclContext of a template
|
||||
// parameter or of a parameter of a function template immediately. These
|
||||
// entities might be used in the formulation of its DeclContext (for
|
||||
|
@ -607,10 +607,17 @@ window.addEventListener("keydown", function (event) {
|
||||
)<<<";
|
||||
}
|
||||
|
||||
static bool shouldDisplayPopUpRange(const SourceRange &Range) {
|
||||
return !(Range.getBegin().isMacroID() || Range.getEnd().isMacroID());
|
||||
}
|
||||
|
||||
static void
|
||||
HandlePopUpPieceStartTag(Rewriter &R,
|
||||
const std::vector<SourceRange> &PopUpRanges) {
|
||||
for (const auto &Range : PopUpRanges) {
|
||||
if (!shouldDisplayPopUpRange(Range))
|
||||
continue;
|
||||
|
||||
html::HighlightRange(R, Range.getBegin(), Range.getEnd(), "",
|
||||
"<table class='variable_popup'><tbody>",
|
||||
/*IsTokenRange=*/true);
|
||||
@ -626,6 +633,8 @@ static void HandlePopUpPieceEndTag(Rewriter &R,
|
||||
llvm::raw_svector_ostream Out(Buf);
|
||||
|
||||
SourceRange Range(Piece.getLocation().asRange());
|
||||
if (!shouldDisplayPopUpRange(Range))
|
||||
return;
|
||||
|
||||
// Write out the path indices with a right arrow and the message as a row.
|
||||
Out << "<tr><td valign='top'><div class='PathIndex PathIndexPopUp'>"
|
||||
@ -870,7 +879,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter &R, FileID BugFileID,
|
||||
<< (num - 1)
|
||||
<< "\" title=\"Previous event ("
|
||||
<< (num - 1)
|
||||
<< ")\">←</a></div></td>";
|
||||
<< ")\">←</a></div>";
|
||||
}
|
||||
|
||||
os << "</td><td>";
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
@ -69,7 +70,7 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message,
|
||||
// We cannot recover from llvm errors. When reporting a fatal error, exit
|
||||
// with status 70 to generate crash diagnostics. For BSD systems this is
|
||||
// defined as an internal software error. Otherwise, exit with status 1.
|
||||
exit(GenCrashDiag ? 70 : 1);
|
||||
llvm::sys::Process::Exit(GenCrashDiag ? 70 : 1);
|
||||
}
|
||||
|
||||
#ifdef CLANG_HAVE_RLIMITS
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
@ -547,7 +548,7 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message,
|
||||
Diags.Report(diag::err_fe_error_backend) << Message;
|
||||
|
||||
// We cannot recover from llvm errors.
|
||||
exit(1);
|
||||
sys::Process::Exit(1);
|
||||
}
|
||||
|
||||
int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
|
||||
|
@ -23,9 +23,12 @@
|
||||
#include <errno.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <objc/objc-sync.h>
|
||||
#include <os/lock.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#if defined(__has_include) && __has_include(<os/lock.h>)
|
||||
#include <os/lock.h>
|
||||
#endif
|
||||
|
||||
#if defined(__has_include) && __has_include(<xpc/xpc.h>)
|
||||
#include <xpc/xpc.h>
|
||||
#endif // #if defined(__has_include) && __has_include(<xpc/xpc.h>)
|
||||
@ -247,6 +250,8 @@ TSAN_INTERCEPTOR(void, os_lock_unlock, void *lock) {
|
||||
REAL(os_lock_unlock)(lock);
|
||||
}
|
||||
|
||||
#if defined(__has_include) && __has_include(<os/lock.h>)
|
||||
|
||||
TSAN_INTERCEPTOR(void, os_unfair_lock_lock, os_unfair_lock_t lock) {
|
||||
if (!cur_thread()->is_inited || cur_thread()->is_dead) {
|
||||
return REAL(os_unfair_lock_lock)(lock);
|
||||
@ -286,6 +291,8 @@ TSAN_INTERCEPTOR(void, os_unfair_lock_unlock, os_unfair_lock_t lock) {
|
||||
REAL(os_unfair_lock_unlock)(lock);
|
||||
}
|
||||
|
||||
#endif // #if defined(__has_include) && __has_include(<os/lock.h>)
|
||||
|
||||
#if defined(__has_include) && __has_include(<xpc/xpc.h>)
|
||||
|
||||
TSAN_INTERCEPTOR(void, xpc_connection_set_event_handler,
|
||||
|
@ -342,6 +342,10 @@
|
||||
# define _LIBCPP_HAS_ALIGNED_ALLOC
|
||||
# define _LIBCPP_HAS_QUICK_EXIT
|
||||
# define _LIBCPP_HAS_C11_FEATURES
|
||||
# if __FreeBSD_version >= 1300064 || \
|
||||
(__FreeBSD_version >= 1201504 && __FreeBSD_version < 1300000)
|
||||
# define _LIBCPP_HAS_TIMESPEC_GET
|
||||
# endif
|
||||
# elif defined(__BIONIC__)
|
||||
# define _LIBCPP_HAS_C11_FEATURES
|
||||
# if __ANDROID_API__ >= 21
|
||||
|
@ -275,8 +275,8 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
|
||||
case R_ARM_PLT32:
|
||||
case R_ARM_JUMP24:
|
||||
// Source is ARM, all PLT entries are ARM so no interworking required.
|
||||
// Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
|
||||
if (expr == R_PC && ((s.getVA() & 1) == 1))
|
||||
// Otherwise we need to interwork if STT_FUNC Symbol has bit 0 set (Thumb).
|
||||
if (s.isFunc() && expr == R_PC && (s.getVA() & 1))
|
||||
return true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case R_ARM_CALL: {
|
||||
@ -286,8 +286,8 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
|
||||
case R_ARM_THM_JUMP19:
|
||||
case R_ARM_THM_JUMP24:
|
||||
// Source is Thumb, all PLT entries are ARM so interworking is required.
|
||||
// Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
|
||||
if (expr == R_PLT_PC || ((s.getVA() & 1) == 0))
|
||||
// Otherwise we need to interwork if STT_FUNC Symbol has bit 0 clear (ARM).
|
||||
if (expr == R_PLT_PC || (s.isFunc() && (s.getVA() & 1) == 0))
|
||||
return true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case R_ARM_THM_CALL: {
|
||||
|
@ -67,6 +67,18 @@ static void writeFromHalf16(uint8_t *loc, uint32_t insn) {
|
||||
}
|
||||
|
||||
void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
|
||||
// Create canonical PLT entries for non-PIE code. Compilers don't generate
|
||||
// non-GOT-non-PLT relocations referencing external functions for -fpie/-fPIE.
|
||||
uint32_t glink = in.plt->getVA(); // VA of .glink
|
||||
if (!config->isPic) {
|
||||
for (const Symbol *sym : in.plt->entries)
|
||||
if (sym->needsPltAddr) {
|
||||
writePPC32PltCallStub(buf, sym->getGotPltVA(), nullptr, 0);
|
||||
buf += 16;
|
||||
glink += 16;
|
||||
}
|
||||
}
|
||||
|
||||
// On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an
|
||||
// absolute address from a specific .plt slot (usually called .got.plt on
|
||||
// other targets) and jumps there.
|
||||
@ -85,15 +97,14 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
|
||||
// computes the PLT index (by computing the distance from the landing b to
|
||||
// itself) and calls _dl_runtime_resolve() (in glibc).
|
||||
uint32_t got = in.got->getVA();
|
||||
uint32_t glink = in.plt->getVA(); // VA of .glink
|
||||
const uint8_t *end = buf + 64;
|
||||
if (config->isPic) {
|
||||
uint32_t afterBcl = in.plt->getSize() - target->pltHeaderSize + 12;
|
||||
uint32_t afterBcl = 4 * in.plt->getNumEntries() + 12;
|
||||
uint32_t gotBcl = got + 4 - (glink + afterBcl);
|
||||
write32(buf + 0, 0x3d6b0000 | ha(afterBcl)); // addis r11,r11,1f-glink@ha
|
||||
write32(buf + 4, 0x7c0802a6); // mflr r0
|
||||
write32(buf + 8, 0x429f0005); // bcl 20,30,.+4
|
||||
write32(buf + 12, 0x396b0000 | lo(afterBcl)); // 1: addi r11,r11,1b-.glink@l
|
||||
write32(buf + 12, 0x396b0000 | lo(afterBcl)); // 1: addi r11,r11,1b-glink@l
|
||||
write32(buf + 16, 0x7d8802a6); // mflr r12
|
||||
write32(buf + 20, 0x7c0803a6); // mtlr r0
|
||||
write32(buf + 24, 0x7d6c5850); // sub r11,r11,r12
|
||||
@ -113,16 +124,16 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
|
||||
buf += 56;
|
||||
} else {
|
||||
write32(buf + 0, 0x3d800000 | ha(got + 4)); // lis r12,GOT+4@ha
|
||||
write32(buf + 4, 0x3d6b0000 | ha(-glink)); // addis r11,r11,-Glink@ha
|
||||
write32(buf + 4, 0x3d6b0000 | ha(-glink)); // addis r11,r11,-glink@ha
|
||||
if (ha(got + 4) == ha(got + 8))
|
||||
write32(buf + 8, 0x800c0000 | lo(got + 4)); // lwz r0,GOT+4@l(r12)
|
||||
else
|
||||
write32(buf + 8, 0x840c0000 | lo(got + 4)); // lwzu r0,GOT+4@l(r12)
|
||||
write32(buf + 12, 0x396b0000 | lo(-glink)); // addi r11,r11,-Glink@l
|
||||
write32(buf + 12, 0x396b0000 | lo(-glink)); // addi r11,r11,-glink@l
|
||||
write32(buf + 16, 0x7c0903a6); // mtctr r0
|
||||
write32(buf + 20, 0x7c0b5a14); // add r0,r11,r11
|
||||
if (ha(got + 4) == ha(got + 8))
|
||||
write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@ha(r12)
|
||||
write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@l(r12)
|
||||
else
|
||||
write32(buf + 24, 0x818c0000 | 4); // lwz r12,4(r12)
|
||||
write32(buf + 28, 0x7d605a14); // add r11,r0,r11
|
||||
@ -146,7 +157,7 @@ PPC::PPC() {
|
||||
gotBaseSymInGotPlt = false;
|
||||
gotHeaderEntriesNum = 3;
|
||||
gotPltHeaderEntriesNum = 0;
|
||||
pltHeaderSize = 64; // size of PLTresolve in .glink
|
||||
pltHeaderSize = 0;
|
||||
pltEntrySize = 4;
|
||||
ipltEntrySize = 16;
|
||||
|
||||
@ -178,25 +189,25 @@ void PPC::writeGotHeader(uint8_t *buf) const {
|
||||
|
||||
void PPC::writeGotPlt(uint8_t *buf, const Symbol &s) const {
|
||||
// Address of the symbol resolver stub in .glink .
|
||||
write32(buf, in.plt->getVA() + 4 * s.pltIndex);
|
||||
write32(buf, in.plt->getVA() + in.plt->headerSize + 4 * s.pltIndex);
|
||||
}
|
||||
|
||||
bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file,
|
||||
uint64_t branchAddr, const Symbol &s, int64_t /*a*/) const {
|
||||
if (type != R_PPC_REL24 && type != R_PPC_PLTREL24)
|
||||
uint64_t branchAddr, const Symbol &s, int64_t a) const {
|
||||
if (type != R_PPC_LOCAL24PC && type != R_PPC_REL24 && type != R_PPC_PLTREL24)
|
||||
return false;
|
||||
if (s.isInPlt())
|
||||
return true;
|
||||
if (s.isUndefWeak())
|
||||
return false;
|
||||
return !(expr == R_PC && PPC::inBranchRange(type, branchAddr, s.getVA()));
|
||||
return !PPC::inBranchRange(type, branchAddr, s.getVA(a));
|
||||
}
|
||||
|
||||
uint32_t PPC::getThunkSectionSpacing() const { return 0x2000000; }
|
||||
|
||||
bool PPC::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
|
||||
uint64_t offset = dst - src;
|
||||
if (type == R_PPC_REL24 || type == R_PPC_PLTREL24)
|
||||
if (type == R_PPC_LOCAL24PC || type == R_PPC_REL24 || type == R_PPC_PLTREL24)
|
||||
return isInt<26>(offset);
|
||||
llvm_unreachable("unsupported relocation type used in branch");
|
||||
}
|
||||
@ -219,13 +230,13 @@ RelExpr PPC::getRelExpr(RelType type, const Symbol &s,
|
||||
return R_DTPREL;
|
||||
case R_PPC_REL14:
|
||||
case R_PPC_REL32:
|
||||
case R_PPC_LOCAL24PC:
|
||||
case R_PPC_REL16_LO:
|
||||
case R_PPC_REL16_HI:
|
||||
case R_PPC_REL16_HA:
|
||||
return R_PC;
|
||||
case R_PPC_GOT16:
|
||||
return R_GOT_OFF;
|
||||
case R_PPC_LOCAL24PC:
|
||||
case R_PPC_REL24:
|
||||
return R_PLT_PC;
|
||||
case R_PPC_PLTREL24:
|
||||
|
@ -485,6 +485,14 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef<RelTy> rels) {
|
||||
p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr;
|
||||
else if (config->relocatable && type != target->noneRel)
|
||||
sec->relocations.push_back({R_ABS, type, rel.r_offset, addend, &sym});
|
||||
} else if (config->emachine == EM_PPC && type == R_PPC_PLTREL24 &&
|
||||
p->r_addend >= 0x8000) {
|
||||
// Similar to R_MIPS_GPREL{16,32}. If the addend of R_PPC_PLTREL24
|
||||
// indicates that r30 is relative to the input section .got2
|
||||
// (r_addend>=0x8000), after linking, r30 should be relative to the output
|
||||
// section .got2 . To compensate for the shift, adjust r_addend by
|
||||
// ppc32Got2OutSecOff.
|
||||
p->r_addend += sec->file->ppc32Got2OutSecOff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1198,10 +1198,16 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
|
||||
getLocation(sec, sym, offset));
|
||||
if (!sym.isInPlt())
|
||||
addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
|
||||
if (!sym.isDefined())
|
||||
if (!sym.isDefined()) {
|
||||
replaceWithDefined(
|
||||
sym, in.plt,
|
||||
target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
|
||||
if (config->emachine == EM_PPC) {
|
||||
// PPC32 canonical PLT entries are at the beginning of .glink
|
||||
cast<Defined>(sym).value = in.plt->headerSize;
|
||||
in.plt->headerSize += 16;
|
||||
}
|
||||
}
|
||||
sym.needsPltAddr = true;
|
||||
sec.relocations.push_back({expr, type, offset, addend, &sym});
|
||||
return;
|
||||
@ -1298,10 +1304,10 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
|
||||
if (expr == R_GOT_PC && !isAbsoluteValue(sym)) {
|
||||
expr = target->adjustRelaxExpr(type, relocatedAddr, expr);
|
||||
} else {
|
||||
// Addend of R_PPC_PLTREL24 is used to choose call stub type. It should be
|
||||
// ignored if optimized to R_PC.
|
||||
// The 0x8000 bit of r_addend of R_PPC_PLTREL24 is used to choose call
|
||||
// stub type. It should be ignored if optimized to R_PC.
|
||||
if (config->emachine == EM_PPC && expr == R_PPC32_PLTREL)
|
||||
addend = 0;
|
||||
addend &= ~0x8000;
|
||||
expr = fromPlt(expr);
|
||||
}
|
||||
}
|
||||
@ -1752,6 +1758,37 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *os,
|
||||
uint64_t off) {
|
||||
auto *ts = make<ThunkSection>(os, off);
|
||||
ts->partition = os->partition;
|
||||
if ((config->fixCortexA53Errata843419 || config->fixCortexA8) &&
|
||||
!isd->sections.empty()) {
|
||||
// The errata fixes are sensitive to addresses modulo 4 KiB. When we add
|
||||
// thunks we disturb the base addresses of sections placed after the thunks
|
||||
// this makes patches we have generated redundant, and may cause us to
|
||||
// generate more patches as different instructions are now in sensitive
|
||||
// locations. When we generate more patches we may force more branches to
|
||||
// go out of range, causing more thunks to be generated. In pathological
|
||||
// cases this can cause the address dependent content pass not to converge.
|
||||
// We fix this by rounding up the size of the ThunkSection to 4KiB, this
|
||||
// limits the insertion of a ThunkSection on the addresses modulo 4 KiB,
|
||||
// which means that adding Thunks to the section does not invalidate
|
||||
// errata patches for following code.
|
||||
// Rounding up the size to 4KiB has consequences for code-size and can
|
||||
// trip up linker script defined assertions. For example the linux kernel
|
||||
// has an assertion that what LLD represents as an InputSectionDescription
|
||||
// does not exceed 4 KiB even if the overall OutputSection is > 128 Mib.
|
||||
// We use the heuristic of rounding up the size when both of the following
|
||||
// conditions are true:
|
||||
// 1.) The OutputSection is larger than the ThunkSectionSpacing. This
|
||||
// accounts for the case where no single InputSectionDescription is
|
||||
// larger than the OutputSection size. This is conservative but simple.
|
||||
// 2.) The InputSectionDescription is larger than 4 KiB. This will prevent
|
||||
// any assertion failures that an InputSectionDescription is < 4 KiB
|
||||
// in size.
|
||||
uint64_t isdSize = isd->sections.back()->outSecOff +
|
||||
isd->sections.back()->getSize() -
|
||||
isd->sections.front()->outSecOff;
|
||||
if (os->size > target->getThunkSectionSpacing() && isdSize > 4096)
|
||||
ts->roundUpSizeForErrata = true;
|
||||
}
|
||||
isd->thunkSections.push_back({ts, pass});
|
||||
return ts;
|
||||
}
|
||||
@ -1820,9 +1857,7 @@ bool ThunkCreator::normalizeExistingThunk(Relocation &rel, uint64_t src) {
|
||||
rel.sym->getVA(rel.addend) + getPCBias(rel.type)))
|
||||
return true;
|
||||
rel.sym = &t->destination;
|
||||
// TODO Restore addend on all targets.
|
||||
if (config->emachine == EM_AARCH64 || config->emachine == EM_PPC64)
|
||||
rel.addend = t->addend;
|
||||
rel.addend = t->addend;
|
||||
if (rel.sym->isInPlt())
|
||||
rel.expr = toPlt(rel.expr);
|
||||
}
|
||||
@ -1900,16 +1935,11 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) {
|
||||
rel.sym = t->getThunkTargetSym();
|
||||
rel.expr = fromPlt(rel.expr);
|
||||
|
||||
// On AArch64 and PPC64, a jump/call relocation may be encoded as
|
||||
// On AArch64 and PPC, a jump/call relocation may be encoded as
|
||||
// STT_SECTION + non-zero addend, clear the addend after
|
||||
// redirection.
|
||||
//
|
||||
// The addend of R_PPC_PLTREL24 should be ignored after changing to
|
||||
// R_PC.
|
||||
if (config->emachine == EM_AARCH64 ||
|
||||
config->emachine == EM_PPC64 ||
|
||||
(config->emachine == EM_PPC && rel.type == R_PPC_PLTREL24))
|
||||
rel.addend = 0;
|
||||
if (config->emachine != EM_MIPS)
|
||||
rel.addend = -getPCBias(rel.type);
|
||||
}
|
||||
|
||||
for (auto &p : isd->thunkSections)
|
||||
|
@ -2449,6 +2449,9 @@ PltSection::PltSection()
|
||||
if (config->emachine == EM_PPC || config->emachine == EM_PPC64) {
|
||||
name = ".glink";
|
||||
alignment = 4;
|
||||
// PLTresolve is at the end.
|
||||
if (config->emachine == EM_PPC)
|
||||
footerSize = 64;
|
||||
}
|
||||
|
||||
// On x86 when IBT is enabled, this section contains the second PLT (lazy
|
||||
@ -2486,7 +2489,7 @@ void PltSection::addEntry(Symbol &sym) {
|
||||
}
|
||||
|
||||
size_t PltSection::getSize() const {
|
||||
return headerSize + entries.size() * target->pltEntrySize;
|
||||
return headerSize + entries.size() * target->pltEntrySize + footerSize;
|
||||
}
|
||||
|
||||
bool PltSection::isNeeded() const {
|
||||
@ -3451,19 +3454,14 @@ bool ARMExidxSyntheticSection::classof(const SectionBase *d) {
|
||||
}
|
||||
|
||||
ThunkSection::ThunkSection(OutputSection *os, uint64_t off)
|
||||
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
|
||||
config->wordsize, ".text.thunk") {
|
||||
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4,
|
||||
".text.thunk") {
|
||||
this->parent = os;
|
||||
this->outSecOff = off;
|
||||
}
|
||||
|
||||
// When the errata patching is on, we round the size up to a 4 KiB
|
||||
// boundary. This limits the effect that adding Thunks has on the addresses
|
||||
// of the program modulo 4 KiB. As the errata patching is sensitive to address
|
||||
// modulo 4 KiB this can prevent further patches from being needed due to
|
||||
// Thunk insertion.
|
||||
size_t ThunkSection::getSize() const {
|
||||
if (config->fixCortexA53Errata843419 || config->fixCortexA8)
|
||||
if (roundUpSizeForErrata)
|
||||
return alignTo(size, 4096);
|
||||
return size;
|
||||
}
|
||||
|
@ -683,9 +683,9 @@ class PltSection : public SyntheticSection {
|
||||
void addEntry(Symbol &sym);
|
||||
size_t getNumEntries() const { return entries.size(); }
|
||||
|
||||
size_t headerSize = 0;
|
||||
size_t headerSize;
|
||||
size_t footerSize = 0;
|
||||
|
||||
private:
|
||||
std::vector<const Symbol *> entries;
|
||||
};
|
||||
|
||||
@ -1069,6 +1069,10 @@ class ThunkSection : public SyntheticSection {
|
||||
InputSection *getTargetInputSection() const;
|
||||
bool assignOffsets();
|
||||
|
||||
// When true, round up reported size of section to 4 KiB. See comment
|
||||
// in addThunkSection() for more details.
|
||||
bool roundUpSizeForErrata = false;
|
||||
|
||||
private:
|
||||
std::vector<Thunk *> thunks;
|
||||
size_t size = 0;
|
||||
|
@ -245,8 +245,7 @@ class PPC32PltCallStub final : public Thunk {
|
||||
// decide the offsets in the call stub.
|
||||
PPC32PltCallStub(const InputSection &isec, const Relocation &rel,
|
||||
Symbol &dest)
|
||||
: Thunk(dest, rel.type == R_PPC_PLTREL24 ? rel.addend : 0),
|
||||
file(isec.file) {}
|
||||
: Thunk(dest, rel.addend), file(isec.file) {}
|
||||
uint32_t size() override { return 16; }
|
||||
void writeTo(uint8_t *buf) override;
|
||||
void addSymbols(ThunkSection &isec) override;
|
||||
@ -257,6 +256,14 @@ class PPC32PltCallStub final : public Thunk {
|
||||
const InputFile *file;
|
||||
};
|
||||
|
||||
class PPC32LongThunk final : public Thunk {
|
||||
public:
|
||||
PPC32LongThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
|
||||
uint32_t size() override { return config->isPic ? 32 : 16; }
|
||||
void writeTo(uint8_t *buf) override;
|
||||
void addSymbols(ThunkSection &isec) override;
|
||||
};
|
||||
|
||||
// PPC64 Plt call stubs.
|
||||
// Any call site that needs to call through a plt entry needs a call stub in
|
||||
// the .text section. The call stub is responsible for:
|
||||
@ -765,6 +772,33 @@ bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
|
||||
return !config->isPic || (isec.file == file && rel.addend == addend);
|
||||
}
|
||||
|
||||
void PPC32LongThunk::addSymbols(ThunkSection &isec) {
|
||||
addSymbol(saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
|
||||
isec);
|
||||
}
|
||||
|
||||
void PPC32LongThunk::writeTo(uint8_t *buf) {
|
||||
auto ha = [](uint32_t v) -> uint16_t { return (v + 0x8000) >> 16; };
|
||||
auto lo = [](uint32_t v) -> uint16_t { return v; };
|
||||
uint32_t d = destination.getVA(addend);
|
||||
if (config->isPic) {
|
||||
uint32_t off = d - (getThunkTargetSym()->getVA() + 8);
|
||||
write32(buf + 0, 0x7c0802a6); // mflr r12,0
|
||||
write32(buf + 4, 0x429f0005); // bcl r20,r31,.+4
|
||||
write32(buf + 8, 0x7d8802a6); // mtctr r12
|
||||
write32(buf + 12, 0x3d8c0000 | ha(off)); // addis r12,r12,off@ha
|
||||
write32(buf + 16, 0x398c0000 | lo(off)); // addi r12,r12,off@l
|
||||
write32(buf + 20, 0x7c0803a6); // mtlr r0
|
||||
buf += 24;
|
||||
} else {
|
||||
write32(buf + 0, 0x3d800000 | ha(d)); // lis r12,d@ha
|
||||
write32(buf + 4, 0x398c0000 | lo(d)); // addi r12,r12,d@l
|
||||
buf += 8;
|
||||
}
|
||||
write32(buf + 0, 0x7d8903a6); // mtctr r12
|
||||
write32(buf + 4, 0x4e800420); // bctr
|
||||
}
|
||||
|
||||
void writePPC64LoadAndBranch(uint8_t *buf, int64_t offset) {
|
||||
uint16_t offHa = (offset + 0x8000) >> 16;
|
||||
uint16_t offLo = offset & 0xffff;
|
||||
@ -902,9 +936,12 @@ static Thunk *addThunkMips(RelType type, Symbol &s) {
|
||||
|
||||
static Thunk *addThunkPPC32(const InputSection &isec, const Relocation &rel,
|
||||
Symbol &s) {
|
||||
assert((rel.type == R_PPC_REL24 || rel.type == R_PPC_PLTREL24) &&
|
||||
assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
|
||||
rel.type == R_PPC_PLTREL24) &&
|
||||
"unexpected relocation type for thunk");
|
||||
return make<PPC32PltCallStub>(isec, rel, s);
|
||||
if (s.isInPlt())
|
||||
return make<PPC32PltCallStub>(isec, rel, s);
|
||||
return make<PPC32LongThunk>(s, rel.addend);
|
||||
}
|
||||
|
||||
static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {
|
||||
|
@ -30,6 +30,14 @@ ELF Improvements
|
||||
with GNU now. (`r375051
|
||||
<https://github.com/llvm/llvm-project/commit/48993d5ab9413f0e5b94dfa292a233ce55b09e3e>`_)
|
||||
|
||||
* New ``elf32btsmipn32_fbsd`` and ``elf32ltsmipn32_fbsd`` emulations
|
||||
are supported.
|
||||
|
||||
* Relax MIPS ``jalr``and ``jr`` instructions marked by the ``R_MIPS_JALR``
|
||||
relocation.
|
||||
|
||||
* Reduced size of linked MIPS binaries.
|
||||
|
||||
COFF Improvements
|
||||
-----------------
|
||||
|
||||
@ -38,7 +46,33 @@ COFF Improvements
|
||||
MinGW Improvements
|
||||
------------------
|
||||
|
||||
* ...
|
||||
* Allow using custom .edata sections from input object files (for use
|
||||
by Wine)
|
||||
(`dadc6f248868 <https://reviews.llvm.org/rGdadc6f248868>`)
|
||||
|
||||
* Don't implicitly create import libraries unless requested
|
||||
(`6540e55067e3 <https://reviews.llvm.org/rG6540e55067e3>`)
|
||||
|
||||
* Support merging multiple resource object files
|
||||
(`3d3a9b3b413d <https://reviews.llvm.org/rG3d3a9b3b413d>`)
|
||||
and properly handle the default manifest object files that GCC can pass
|
||||
(`d581dd501381 <https://reviews.llvm.org/rGd581dd501381>`)
|
||||
|
||||
* Demangle itanium symbol names in warnings/error messages
|
||||
(`a66fc1c99f3e <https://reviews.llvm.org/rGa66fc1c99f3e>`)
|
||||
|
||||
* Print source locations for undefined references and duplicate symbols,
|
||||
if possible
|
||||
(`1d06d48bb346 <https://reviews.llvm.org/rG1d06d48bb346>`)
|
||||
and
|
||||
(`b38f577c015c <https://reviews.llvm.org/rGb38f577c015c>`)
|
||||
|
||||
* Look for more filename patterns when resolving ``-l`` options
|
||||
(`0226c35262df <https://reviews.llvm.org/rG0226c35262df>`)
|
||||
|
||||
* Don't error out on duplicate absolute symbols with the same value
|
||||
(which can happen for the default-null symbol for weak symbols)
|
||||
(`1737cc750c46 <https://reviews.llvm.org/rG1737cc750c46>`)
|
||||
|
||||
MachO Improvements
|
||||
------------------
|
||||
|
@ -69,6 +69,8 @@ FormatCache::Entry &FormatCache::GetEntry(ConstString type) {
|
||||
return m_map[type];
|
||||
}
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
template<> bool FormatCache::Entry::IsCached<lldb::TypeFormatImplSP>() {
|
||||
return IsFormatCached();
|
||||
}
|
||||
@ -79,6 +81,8 @@ template<> bool FormatCache::Entry::IsCached<lldb::SyntheticChildrenSP>() {
|
||||
return IsSyntheticCached();
|
||||
}
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
template <typename ImplSP>
|
||||
bool FormatCache::Get(ConstString type, ImplSP &format_impl_sp) {
|
||||
std::lock_guard<std::recursive_mutex> guard(m_mutex);
|
||||
|
@ -55,6 +55,8 @@ bool LanguageCategory::Get(FormattersMatchData &match_data,
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
/// Explicit instantiations for the three types.
|
||||
/// \{
|
||||
template bool
|
||||
@ -83,6 +85,8 @@ auto &LanguageCategory::GetHardcodedFinder<lldb::SyntheticChildrenSP>() {
|
||||
return m_hardcoded_synthetics;
|
||||
}
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
template <typename ImplSP>
|
||||
bool LanguageCategory::GetHardcoded(FormatManager &fmt_mgr,
|
||||
FormattersMatchData &match_data,
|
||||
|
@ -65,7 +65,8 @@ static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp,
|
||||
else {
|
||||
for (auto &entry : args.entries()) {
|
||||
if (!entry.ref().empty())
|
||||
option_arg_vector->emplace_back("<argument>", -1, entry.ref());
|
||||
option_arg_vector->emplace_back(std::string("<argument>"), -1,
|
||||
std::string(entry.ref()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1061,8 +1061,8 @@ llvm::Expected<Args> Options::ParseAlias(const Args &args,
|
||||
}
|
||||
if (!option_arg)
|
||||
option_arg = "<no-argument>";
|
||||
option_arg_vector->emplace_back(option_str.GetString(), has_arg,
|
||||
option_arg);
|
||||
option_arg_vector->emplace_back(std::string(option_str.GetString()),
|
||||
has_arg, std::string(option_arg));
|
||||
|
||||
// Find option in the argument list; also see if it was supposed to take an
|
||||
// argument and if one was supplied. Remove option (and argument, if
|
||||
|
@ -85,35 +85,6 @@ static bool DeclKindIsCXXClass(clang::Decl::Kind decl_kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct BitfieldInfo {
|
||||
uint64_t bit_size;
|
||||
uint64_t bit_offset;
|
||||
|
||||
BitfieldInfo()
|
||||
: bit_size(LLDB_INVALID_ADDRESS), bit_offset(LLDB_INVALID_ADDRESS) {}
|
||||
|
||||
void Clear() {
|
||||
bit_size = LLDB_INVALID_ADDRESS;
|
||||
bit_offset = LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
bool IsValid() const {
|
||||
return (bit_size != LLDB_INVALID_ADDRESS) &&
|
||||
(bit_offset != LLDB_INVALID_ADDRESS);
|
||||
}
|
||||
|
||||
bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const {
|
||||
if (IsValid()) {
|
||||
// This bitfield info is valid, so any subsequent bitfields must not
|
||||
// overlap and must be at a higher bit offset than any previous bitfield
|
||||
// + size.
|
||||
return (bit_size + bit_offset) <= next_bit_offset;
|
||||
} else {
|
||||
// If the this BitfieldInfo is not valid, then any offset isOK
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ClangASTImporter &DWARFASTParserClang::GetClangASTImporter() {
|
||||
if (!m_clang_ast_importer_up) {
|
||||
@ -2419,7 +2390,7 @@ void DWARFASTParserClang::ParseSingleMember(
|
||||
lldb::AccessType &default_accessibility,
|
||||
DelayedPropertyList &delayed_properties,
|
||||
lldb_private::ClangASTImporter::LayoutInfo &layout_info,
|
||||
BitfieldInfo &last_field_info) {
|
||||
FieldInfo &last_field_info) {
|
||||
ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
|
||||
const dw_tag_t tag = die.Tag();
|
||||
// Get the parent byte size so we can verify any members will fit
|
||||
@ -2453,6 +2424,14 @@ void DWARFASTParserClang::ParseSingleMember(
|
||||
const dw_attr_t attr = attributes.AttributeAtIndex(i);
|
||||
DWARFFormValue form_value;
|
||||
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
|
||||
// DW_AT_data_member_location indicates the byte offset of the
|
||||
// word from the base address of the structure.
|
||||
//
|
||||
// DW_AT_bit_offset indicates how many bits into the word
|
||||
// (according to the host endianness) the low-order bit of the
|
||||
// field starts. AT_bit_offset can be negative.
|
||||
//
|
||||
// DW_AT_bit_size indicates the size of the field in bits.
|
||||
switch (attr) {
|
||||
case DW_AT_name:
|
||||
name = form_value.AsCString();
|
||||
@ -2603,36 +2582,24 @@ void DWARFASTParserClang::ParseSingleMember(
|
||||
Type *member_type = die.ResolveTypeUID(encoding_form.Reference());
|
||||
|
||||
clang::FieldDecl *field_decl = nullptr;
|
||||
const uint64_t character_width = 8;
|
||||
const uint64_t word_width = 32;
|
||||
if (tag == DW_TAG_member) {
|
||||
if (member_type) {
|
||||
CompilerType member_clang_type = member_type->GetLayoutCompilerType();
|
||||
|
||||
if (accessibility == eAccessNone)
|
||||
accessibility = default_accessibility;
|
||||
member_accessibilities.push_back(accessibility);
|
||||
|
||||
uint64_t field_bit_offset =
|
||||
(member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8));
|
||||
if (bit_size > 0) {
|
||||
|
||||
BitfieldInfo this_field_info;
|
||||
if (bit_size > 0) {
|
||||
FieldInfo this_field_info;
|
||||
this_field_info.bit_offset = field_bit_offset;
|
||||
this_field_info.bit_size = bit_size;
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// How to locate a field given the DWARF debug information
|
||||
//
|
||||
// AT_byte_size indicates the size of the word in which the bit
|
||||
// offset must be interpreted.
|
||||
//
|
||||
// AT_data_member_location indicates the byte offset of the
|
||||
// word from the base address of the structure.
|
||||
//
|
||||
// AT_bit_offset indicates how many bits into the word
|
||||
// (according to the host endianness) the low-order bit of the
|
||||
// field starts. AT_bit_offset can be negative.
|
||||
//
|
||||
// AT_bit_size indicates the size of the field in bits.
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
if (data_bit_offset != UINT64_MAX) {
|
||||
this_field_info.bit_offset = data_bit_offset;
|
||||
} else {
|
||||
@ -2649,8 +2616,9 @@ void DWARFASTParserClang::ParseSingleMember(
|
||||
}
|
||||
|
||||
if ((this_field_info.bit_offset >= parent_bit_size) ||
|
||||
!last_field_info.NextBitfieldOffsetIsValid(
|
||||
this_field_info.bit_offset)) {
|
||||
(last_field_info.IsBitfield() &&
|
||||
!last_field_info.NextBitfieldOffsetIsValid(
|
||||
this_field_info.bit_offset))) {
|
||||
ObjectFile *objfile = die.GetDWARF()->GetObjectFile();
|
||||
objfile->GetModule()->ReportWarning(
|
||||
"0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid "
|
||||
@ -2659,40 +2627,12 @@ void DWARFASTParserClang::ParseSingleMember(
|
||||
"compiler and include the preprocessed output for %s\n",
|
||||
die.GetID(), DW_TAG_value_to_name(tag), name,
|
||||
this_field_info.bit_offset, GetUnitName(parent_die).c_str());
|
||||
this_field_info.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the field bit offset we will report for layout
|
||||
field_bit_offset = this_field_info.bit_offset;
|
||||
|
||||
// If the member to be emitted did not start on a character
|
||||
// boundary and there is empty space between the last field and
|
||||
// this one, then we need to emit an anonymous member filling
|
||||
// up the space up to its start. There are three cases here:
|
||||
//
|
||||
// 1 If the previous member ended on a character boundary, then
|
||||
// we can emit an
|
||||
// anonymous member starting at the most recent character
|
||||
// boundary.
|
||||
//
|
||||
// 2 If the previous member did not end on a character boundary
|
||||
// and the distance
|
||||
// from the end of the previous member to the current member
|
||||
// is less than a
|
||||
// word width, then we can emit an anonymous member starting
|
||||
// right after the
|
||||
// previous member and right before this member.
|
||||
//
|
||||
// 3 If the previous member did not end on a character boundary
|
||||
// and the distance
|
||||
// from the end of the previous member to the current member
|
||||
// is greater than
|
||||
// or equal a word width, then we act as in Case 1.
|
||||
|
||||
const uint64_t character_width = 8;
|
||||
const uint64_t word_width = 32;
|
||||
|
||||
// Objective-C has invalid DW_AT_bit_offset values in older
|
||||
// versions of clang, so we have to be careful and only insert
|
||||
// unnamed bitfields if we have a new enough clang.
|
||||
@ -2704,53 +2644,57 @@ void DWARFASTParserClang::ParseSingleMember(
|
||||
die.GetCU()->Supports_unnamed_objc_bitfields();
|
||||
|
||||
if (detect_unnamed_bitfields) {
|
||||
BitfieldInfo anon_field_info;
|
||||
clang::Optional<FieldInfo> unnamed_field_info;
|
||||
uint64_t last_field_end = 0;
|
||||
|
||||
if ((this_field_info.bit_offset % character_width) !=
|
||||
0) // not char aligned
|
||||
{
|
||||
uint64_t last_field_end = 0;
|
||||
last_field_end =
|
||||
last_field_info.bit_offset + last_field_info.bit_size;
|
||||
|
||||
if (last_field_info.IsValid())
|
||||
last_field_end =
|
||||
last_field_info.bit_offset + last_field_info.bit_size;
|
||||
|
||||
if (this_field_info.bit_offset != last_field_end) {
|
||||
if (((last_field_end % character_width) == 0) || // case 1
|
||||
(this_field_info.bit_offset - last_field_end >=
|
||||
word_width)) // case 3
|
||||
{
|
||||
anon_field_info.bit_size =
|
||||
this_field_info.bit_offset % character_width;
|
||||
anon_field_info.bit_offset =
|
||||
this_field_info.bit_offset - anon_field_info.bit_size;
|
||||
} else // case 2
|
||||
{
|
||||
anon_field_info.bit_size =
|
||||
this_field_info.bit_offset - last_field_end;
|
||||
anon_field_info.bit_offset = last_field_end;
|
||||
}
|
||||
}
|
||||
if (!last_field_info.IsBitfield()) {
|
||||
// The last field was not a bit-field...
|
||||
// but if it did take up the entire word then we need to extend
|
||||
// last_field_end so the bit-field does not step into the last
|
||||
// fields padding.
|
||||
if (last_field_end != 0 && ((last_field_end % word_width) != 0))
|
||||
last_field_end += word_width - (last_field_end % word_width);
|
||||
}
|
||||
|
||||
if (anon_field_info.IsValid()) {
|
||||
// If we have a gap between the last_field_end and the current
|
||||
// field we have an unnamed bit-field
|
||||
if (this_field_info.bit_offset != last_field_end &&
|
||||
!(this_field_info.bit_offset < last_field_end)) {
|
||||
unnamed_field_info = FieldInfo{};
|
||||
unnamed_field_info->bit_size =
|
||||
this_field_info.bit_offset - last_field_end;
|
||||
unnamed_field_info->bit_offset = last_field_end;
|
||||
}
|
||||
|
||||
if (unnamed_field_info) {
|
||||
clang::FieldDecl *unnamed_bitfield_decl =
|
||||
ClangASTContext::AddFieldToRecordType(
|
||||
class_clang_type, llvm::StringRef(),
|
||||
m_ast.GetBuiltinTypeForEncodingAndBitSize(eEncodingSint,
|
||||
word_width),
|
||||
accessibility, anon_field_info.bit_size);
|
||||
accessibility, unnamed_field_info->bit_size);
|
||||
|
||||
layout_info.field_offsets.insert(std::make_pair(
|
||||
unnamed_bitfield_decl, anon_field_info.bit_offset));
|
||||
unnamed_bitfield_decl, unnamed_field_info->bit_offset));
|
||||
}
|
||||
}
|
||||
|
||||
last_field_info = this_field_info;
|
||||
last_field_info.SetIsBitfield(true);
|
||||
} else {
|
||||
last_field_info.Clear();
|
||||
last_field_info.bit_offset = field_bit_offset;
|
||||
|
||||
if (llvm::Optional<uint64_t> clang_type_size =
|
||||
member_clang_type.GetByteSize(nullptr)) {
|
||||
last_field_info.bit_size = *clang_type_size * character_width;
|
||||
}
|
||||
|
||||
last_field_info.SetIsBitfield(false);
|
||||
}
|
||||
|
||||
CompilerType member_clang_type = member_type->GetLayoutCompilerType();
|
||||
if (!member_clang_type.IsCompleteType())
|
||||
member_clang_type.GetCompleteType();
|
||||
|
||||
@ -2885,7 +2829,7 @@ bool DWARFASTParserClang::ParseChildMembers(
|
||||
if (!parent_die)
|
||||
return false;
|
||||
|
||||
BitfieldInfo last_field_info;
|
||||
FieldInfo last_field_info;
|
||||
|
||||
ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
|
||||
ClangASTContext *ast =
|
||||
|
@ -170,33 +170,20 @@ class DWARFASTParserClang : public DWARFASTParser {
|
||||
lldb::ModuleSP GetModuleForType(const DWARFDIE &die);
|
||||
|
||||
private:
|
||||
struct BitfieldInfo {
|
||||
uint64_t bit_size;
|
||||
uint64_t bit_offset;
|
||||
struct FieldInfo {
|
||||
uint64_t bit_size = 0;
|
||||
uint64_t bit_offset = 0;
|
||||
bool is_bitfield = false;
|
||||
|
||||
BitfieldInfo()
|
||||
: bit_size(LLDB_INVALID_ADDRESS), bit_offset(LLDB_INVALID_ADDRESS) {}
|
||||
FieldInfo() = default;
|
||||
|
||||
void Clear() {
|
||||
bit_size = LLDB_INVALID_ADDRESS;
|
||||
bit_offset = LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
bool IsValid() const {
|
||||
return (bit_size != LLDB_INVALID_ADDRESS) &&
|
||||
(bit_offset != LLDB_INVALID_ADDRESS);
|
||||
}
|
||||
void SetIsBitfield(bool flag) { is_bitfield = flag; }
|
||||
bool IsBitfield() { return is_bitfield; }
|
||||
|
||||
bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const {
|
||||
if (IsValid()) {
|
||||
// This bitfield info is valid, so any subsequent bitfields must not
|
||||
// overlap and must be at a higher bit offset than any previous bitfield
|
||||
// + size.
|
||||
return (bit_size + bit_offset) <= next_bit_offset;
|
||||
} else {
|
||||
// If the this BitfieldInfo is not valid, then any offset isOK
|
||||
return true;
|
||||
}
|
||||
// Any subsequent bitfields must not overlap and must be at a higher
|
||||
// bit offset than any previous bitfield + size.
|
||||
return (bit_size + bit_offset) <= next_bit_offset;
|
||||
}
|
||||
};
|
||||
|
||||
@ -208,7 +195,7 @@ class DWARFASTParserClang : public DWARFASTParser {
|
||||
lldb::AccessType &default_accessibility,
|
||||
DelayedPropertyList &delayed_properties,
|
||||
lldb_private::ClangASTImporter::LayoutInfo &layout_info,
|
||||
BitfieldInfo &last_field_info);
|
||||
FieldInfo &last_field_info);
|
||||
|
||||
bool CompleteRecordType(const DWARFDIE &die, lldb_private::Type *type,
|
||||
lldb_private::CompilerType &clang_type);
|
||||
|
@ -77,7 +77,8 @@ namespace llvm {
|
||||
static constexpr size_t strLen(const char *Str) {
|
||||
#if __cplusplus > 201402L
|
||||
return std::char_traits<char>::length(Str);
|
||||
#elif __has_builtin(__builtin_strlen) || defined(__GNUC__) || defined(_MSC_VER)
|
||||
#elif __has_builtin(__builtin_strlen) || defined(__GNUC__) || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1916)
|
||||
return __builtin_strlen(Str);
|
||||
#else
|
||||
const char *Begin = Str;
|
||||
|
@ -135,7 +135,6 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
MapVector<const MCSymbol *, GOTEquivUsePair> GlobalGOTEquivs;
|
||||
|
||||
private:
|
||||
MCSymbol *CurrentFnBegin = nullptr;
|
||||
MCSymbol *CurrentFnEnd = nullptr;
|
||||
MCSymbol *CurExceptionSym = nullptr;
|
||||
|
||||
@ -148,6 +147,8 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
static char ID;
|
||||
|
||||
protected:
|
||||
MCSymbol *CurrentFnBegin = nullptr;
|
||||
|
||||
/// Protected struct HandlerInfo and Handlers permit target extended
|
||||
/// AsmPrinter adds their own handlers.
|
||||
struct HandlerInfo {
|
||||
|
@ -13,7 +13,9 @@
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Layer.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
@ -28,24 +30,31 @@ namespace orc {
|
||||
|
||||
class JITTargetMachineBuilder;
|
||||
|
||||
IRMaterializationUnit::ManglingOptions
|
||||
irManglingOptionsFromTargetOptions(const TargetOptions &Opts);
|
||||
|
||||
/// Simple compile functor: Takes a single IR module and returns an ObjectFile.
|
||||
/// This compiler supports a single compilation thread and LLVMContext only.
|
||||
/// For multithreaded compilation, use ConcurrentIRCompiler below.
|
||||
class SimpleCompiler {
|
||||
class SimpleCompiler : public IRCompileLayer::IRCompiler {
|
||||
public:
|
||||
using CompileResult = std::unique_ptr<MemoryBuffer>;
|
||||
|
||||
/// Construct a simple compile functor with the given target.
|
||||
SimpleCompiler(TargetMachine &TM, ObjectCache *ObjCache = nullptr)
|
||||
: TM(TM), ObjCache(ObjCache) {}
|
||||
: IRCompiler(irManglingOptionsFromTargetOptions(TM.Options)), TM(TM),
|
||||
ObjCache(ObjCache) {}
|
||||
|
||||
/// Set an ObjectCache to query before compiling.
|
||||
void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; }
|
||||
|
||||
/// Compile a Module to an ObjectFile.
|
||||
CompileResult operator()(Module &M);
|
||||
Expected<CompileResult> operator()(Module &M) override;
|
||||
|
||||
private:
|
||||
IRMaterializationUnit::ManglingOptions
|
||||
manglingOptionsForTargetMachine(const TargetMachine &TM);
|
||||
|
||||
CompileResult tryToLoadFromObjectCache(const Module &M);
|
||||
void notifyObjectCompiled(const Module &M, const MemoryBuffer &ObjBuffer);
|
||||
|
||||
@ -73,14 +82,14 @@ class TMOwningSimpleCompiler : public SimpleCompiler {
|
||||
///
|
||||
/// This class creates a new TargetMachine and SimpleCompiler instance for each
|
||||
/// compile.
|
||||
class ConcurrentIRCompiler {
|
||||
class ConcurrentIRCompiler : public IRCompileLayer::IRCompiler {
|
||||
public:
|
||||
ConcurrentIRCompiler(JITTargetMachineBuilder JTMB,
|
||||
ObjectCache *ObjCache = nullptr);
|
||||
|
||||
void setObjectCache(ObjectCache *ObjCache) { this->ObjCache = ObjCache; }
|
||||
|
||||
std::unique_ptr<MemoryBuffer> operator()(Module &M);
|
||||
Expected<std::unique_ptr<MemoryBuffer>> operator()(Module &M) override;
|
||||
|
||||
private:
|
||||
JITTargetMachineBuilder JTMB;
|
||||
|
@ -489,13 +489,18 @@ class MaterializationResponsibility {
|
||||
/// is guaranteed to return Error::success() and can be wrapped with cantFail.
|
||||
Error notifyEmitted();
|
||||
|
||||
/// Adds new symbols to the JITDylib and this responsibility instance.
|
||||
/// JITDylib entries start out in the materializing state.
|
||||
/// Attempt to claim responsibility for new definitions. This method can be
|
||||
/// used to claim responsibility for symbols that are added to a
|
||||
/// materialization unit during the compilation process (e.g. literal pool
|
||||
/// symbols). Symbol linkage rules are the same as for symbols that are
|
||||
/// defined up front: duplicate strong definitions will result in errors.
|
||||
/// Duplicate weak definitions will be discarded (in which case they will
|
||||
/// not be added to this responsibility instance).
|
||||
///
|
||||
/// This method can be used by materialization units that want to add
|
||||
/// additional symbols at materialization time (e.g. stubs, compile
|
||||
/// callbacks, metadata).
|
||||
Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
|
||||
Error defineMaterializing(SymbolFlagsMap SymbolFlags);
|
||||
|
||||
/// Notify all not-yet-emitted covered by this MaterializationResponsibility
|
||||
/// instance that an error has occurred.
|
||||
@ -1023,7 +1028,7 @@ class JITDylib {
|
||||
const SymbolStringPtr &DependantName,
|
||||
MaterializingInfo &EmittedMI);
|
||||
|
||||
Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
|
||||
Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags);
|
||||
|
||||
void replace(std::unique_ptr<MaterializationUnit> MU);
|
||||
|
||||
|
@ -29,14 +29,29 @@ namespace orc {
|
||||
|
||||
class IRCompileLayer : public IRLayer {
|
||||
public:
|
||||
using CompileFunction =
|
||||
std::function<Expected<std::unique_ptr<MemoryBuffer>>(Module &)>;
|
||||
class IRCompiler {
|
||||
public:
|
||||
IRCompiler(IRMaterializationUnit::ManglingOptions MO) : MO(std::move(MO)) {}
|
||||
virtual ~IRCompiler();
|
||||
const IRMaterializationUnit::ManglingOptions &getManglingOptions() const {
|
||||
return MO;
|
||||
}
|
||||
virtual Expected<std::unique_ptr<MemoryBuffer>> operator()(Module &M) = 0;
|
||||
|
||||
protected:
|
||||
IRMaterializationUnit::ManglingOptions &manglingOptions() { return MO; }
|
||||
|
||||
private:
|
||||
IRMaterializationUnit::ManglingOptions MO;
|
||||
};
|
||||
|
||||
using NotifyCompiledFunction =
|
||||
std::function<void(VModuleKey K, ThreadSafeModule TSM)>;
|
||||
|
||||
IRCompileLayer(ExecutionSession &ES, ObjectLayer &BaseLayer,
|
||||
CompileFunction Compile);
|
||||
std::unique_ptr<IRCompiler> Compile);
|
||||
|
||||
IRCompiler &getCompiler() { return *Compile; }
|
||||
|
||||
void setNotifyCompiled(NotifyCompiledFunction NotifyCompiled);
|
||||
|
||||
@ -45,7 +60,8 @@ class IRCompileLayer : public IRLayer {
|
||||
private:
|
||||
mutable std::mutex IRLayerMutex;
|
||||
ObjectLayer &BaseLayer;
|
||||
CompileFunction Compile;
|
||||
std::unique_ptr<IRCompiler> Compile;
|
||||
const IRMaterializationUnit::ManglingOptions *ManglingOpts;
|
||||
NotifyCompiledFunction NotifyCompiled = NotifyCompiledFunction();
|
||||
};
|
||||
|
||||
@ -90,7 +106,10 @@ class LegacyIRCompileLayer {
|
||||
/// Compile the module, and add the resulting object to the base layer
|
||||
/// along with the given memory manager and symbol resolver.
|
||||
Error addModule(VModuleKey K, std::unique_ptr<Module> M) {
|
||||
if (auto Err = BaseLayer.addObject(std::move(K), Compile(*M)))
|
||||
auto Obj = Compile(*M);
|
||||
if (!Obj)
|
||||
return Obj.takeError();
|
||||
if (auto Err = BaseLayer.addObject(std::move(K), std::move(*Obj)))
|
||||
return Err;
|
||||
if (NotifyCompiled)
|
||||
NotifyCompiled(std::move(K), std::move(M));
|
||||
|
@ -124,7 +124,7 @@ class LLJIT {
|
||||
static std::unique_ptr<ObjectLayer>
|
||||
createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES);
|
||||
|
||||
static Expected<IRCompileLayer::CompileFunction>
|
||||
static Expected<std::unique_ptr<IRCompileLayer::IRCompiler>>
|
||||
createCompileFunction(LLJITBuilderState &S, JITTargetMachineBuilder JTMB);
|
||||
|
||||
/// Create an LLJIT instance with a single compile thread.
|
||||
@ -192,7 +192,7 @@ class LLJITBuilderState {
|
||||
ExecutionSession &, const Triple &TT)>;
|
||||
|
||||
using CompileFunctionCreator =
|
||||
std::function<Expected<IRCompileLayer::CompileFunction>(
|
||||
std::function<Expected<std::unique_ptr<IRCompileLayer::IRCompiler>>(
|
||||
JITTargetMachineBuilder JTMB)>;
|
||||
|
||||
std::unique_ptr<ExecutionSession> ES;
|
||||
|
@ -21,15 +21,62 @@
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// IRMaterializationUnit is a convenient base class for MaterializationUnits
|
||||
/// wrapping LLVM IR. Represents materialization responsibility for all symbols
|
||||
/// in the given module. If symbols are overridden by other definitions, then
|
||||
/// their linkage is changed to available-externally.
|
||||
class IRMaterializationUnit : public MaterializationUnit {
|
||||
public:
|
||||
struct ManglingOptions {
|
||||
bool EmulatedTLS = false;
|
||||
};
|
||||
|
||||
using SymbolNameToDefinitionMap = std::map<SymbolStringPtr, GlobalValue *>;
|
||||
|
||||
/// Create an IRMaterializationLayer. Scans the module to build the
|
||||
/// SymbolFlags and SymbolToDefinition maps.
|
||||
IRMaterializationUnit(ExecutionSession &ES, const ManglingOptions &MO,
|
||||
ThreadSafeModule TSM, VModuleKey K);
|
||||
|
||||
/// Create an IRMaterializationLayer from a module, and pre-existing
|
||||
/// SymbolFlags and SymbolToDefinition maps. The maps must provide
|
||||
/// entries for each definition in M.
|
||||
/// This constructor is useful for delegating work from one
|
||||
/// IRMaterializationUnit to another.
|
||||
IRMaterializationUnit(ThreadSafeModule TSM, VModuleKey K,
|
||||
SymbolFlagsMap SymbolFlags,
|
||||
SymbolNameToDefinitionMap SymbolToDefinition);
|
||||
|
||||
/// Return the ModuleIdentifier as the name for this MaterializationUnit.
|
||||
StringRef getName() const override;
|
||||
|
||||
const ThreadSafeModule &getModule() const { return TSM; }
|
||||
|
||||
protected:
|
||||
ThreadSafeModule TSM;
|
||||
SymbolNameToDefinitionMap SymbolToDefinition;
|
||||
|
||||
private:
|
||||
void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
|
||||
};
|
||||
|
||||
/// Interface for layers that accept LLVM IR.
|
||||
class IRLayer {
|
||||
public:
|
||||
IRLayer(ExecutionSession &ES);
|
||||
IRLayer(ExecutionSession &ES,
|
||||
const IRMaterializationUnit::ManglingOptions *&MO)
|
||||
: ES(ES), MO(MO) {}
|
||||
|
||||
virtual ~IRLayer();
|
||||
|
||||
/// Returns the ExecutionSession for this layer.
|
||||
ExecutionSession &getExecutionSession() { return ES; }
|
||||
|
||||
/// Get the mangling options for this layer.
|
||||
const IRMaterializationUnit::ManglingOptions *&getManglingOptions() const {
|
||||
return MO;
|
||||
}
|
||||
|
||||
/// Sets the CloneToNewContextOnEmit flag (false by default).
|
||||
///
|
||||
/// When set, IR modules added to this layer will be cloned on to a new
|
||||
@ -57,49 +104,15 @@ class IRLayer {
|
||||
private:
|
||||
bool CloneToNewContextOnEmit = false;
|
||||
ExecutionSession &ES;
|
||||
};
|
||||
|
||||
/// IRMaterializationUnit is a convenient base class for MaterializationUnits
|
||||
/// wrapping LLVM IR. Represents materialization responsibility for all symbols
|
||||
/// in the given module. If symbols are overridden by other definitions, then
|
||||
/// their linkage is changed to available-externally.
|
||||
class IRMaterializationUnit : public MaterializationUnit {
|
||||
public:
|
||||
using SymbolNameToDefinitionMap = std::map<SymbolStringPtr, GlobalValue *>;
|
||||
|
||||
/// Create an IRMaterializationLayer. Scans the module to build the
|
||||
/// SymbolFlags and SymbolToDefinition maps.
|
||||
IRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM,
|
||||
VModuleKey K);
|
||||
|
||||
/// Create an IRMaterializationLayer from a module, and pre-existing
|
||||
/// SymbolFlags and SymbolToDefinition maps. The maps must provide
|
||||
/// entries for each definition in M.
|
||||
/// This constructor is useful for delegating work from one
|
||||
/// IRMaterializationUnit to another.
|
||||
IRMaterializationUnit(ThreadSafeModule TSM, VModuleKey K,
|
||||
SymbolFlagsMap SymbolFlags,
|
||||
SymbolNameToDefinitionMap SymbolToDefinition);
|
||||
|
||||
/// Return the ModuleIdentifier as the name for this MaterializationUnit.
|
||||
StringRef getName() const override;
|
||||
|
||||
const ThreadSafeModule &getModule() const { return TSM; }
|
||||
|
||||
protected:
|
||||
ThreadSafeModule TSM;
|
||||
SymbolNameToDefinitionMap SymbolToDefinition;
|
||||
|
||||
private:
|
||||
void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
|
||||
const IRMaterializationUnit::ManglingOptions *&MO;
|
||||
};
|
||||
|
||||
/// MaterializationUnit that materializes modules by calling the 'emit' method
|
||||
/// on the given IRLayer.
|
||||
class BasicIRLayerMaterializationUnit : public IRMaterializationUnit {
|
||||
public:
|
||||
BasicIRLayerMaterializationUnit(IRLayer &L, VModuleKey K,
|
||||
ThreadSafeModule TSM);
|
||||
BasicIRLayerMaterializationUnit(IRLayer &L, const ManglingOptions &MO,
|
||||
ThreadSafeModule TSM, VModuleKey K);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -182,8 +182,8 @@ class IRSpeculationLayer : public IRLayer {
|
||||
IRSpeculationLayer(ExecutionSession &ES, IRCompileLayer &BaseLayer,
|
||||
Speculator &Spec, MangleAndInterner &Mangle,
|
||||
ResultEval Interpreter)
|
||||
: IRLayer(ES), NextLayer(BaseLayer), S(Spec), Mangle(Mangle),
|
||||
QueryAnalysis(Interpreter) {}
|
||||
: IRLayer(ES, BaseLayer.getManglingOptions()), NextLayer(BaseLayer),
|
||||
S(Spec), Mangle(Mangle), QueryAnalysis(Interpreter) {}
|
||||
|
||||
void emit(MaterializationResponsibility R, ThreadSafeModule TSM);
|
||||
|
||||
|
@ -99,7 +99,8 @@ class CrashRecoveryContext {
|
||||
|
||||
/// Explicitly trigger a crash recovery in the current process, and
|
||||
/// return failure from RunSafely(). This function does not return.
|
||||
void HandleCrash();
|
||||
LLVM_ATTRIBUTE_NORETURN
|
||||
void HandleExit(int RetCode);
|
||||
|
||||
/// In case of a crash, this is the crash identifier.
|
||||
int RetCode = 0;
|
||||
|
@ -201,6 +201,12 @@ class Process {
|
||||
/// Get the result of a process wide random number generator. The
|
||||
/// generator will be automatically seeded in non-deterministic fashion.
|
||||
static unsigned GetRandomNumber();
|
||||
|
||||
/// Equivalent to ::exit(), except when running inside a CrashRecoveryContext.
|
||||
/// In that case, the control flow will resume after RunSafely(), like for a
|
||||
/// crash, rather than exiting the current process.
|
||||
LLVM_ATTRIBUTE_NORETURN
|
||||
static void Exit(int RetCode);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ class PassManagerBuilder {
|
||||
typedef std::function<void(const PassManagerBuilder &Builder,
|
||||
legacy::PassManagerBase &PM)>
|
||||
ExtensionFn;
|
||||
typedef int GlobalExtensionID;
|
||||
|
||||
enum ExtensionPointTy {
|
||||
/// EP_EarlyAsPossible - This extension point allows adding passes before
|
||||
/// any other transformations, allowing them to see the code as it is coming
|
||||
@ -193,7 +195,17 @@ class PassManagerBuilder {
|
||||
/// Adds an extension that will be used by all PassManagerBuilder instances.
|
||||
/// This is intended to be used by plugins, to register a set of
|
||||
/// optimisations to run automatically.
|
||||
static void addGlobalExtension(ExtensionPointTy Ty, ExtensionFn Fn);
|
||||
///
|
||||
/// \returns A global extension identifier that can be used to remove the
|
||||
/// extension.
|
||||
static GlobalExtensionID addGlobalExtension(ExtensionPointTy Ty,
|
||||
ExtensionFn Fn);
|
||||
/// Removes an extension that was previously added using addGlobalExtension.
|
||||
/// This is also intended to be used by plugins, to remove any extension that
|
||||
/// was previously registered before being unloaded.
|
||||
///
|
||||
/// \param ExtensionID Identifier of the extension to be removed.
|
||||
static void removeGlobalExtension(GlobalExtensionID ExtensionID);
|
||||
void addExtension(ExtensionPointTy Ty, ExtensionFn Fn);
|
||||
|
||||
private:
|
||||
@ -222,10 +234,20 @@ class PassManagerBuilder {
|
||||
/// used by optimizer plugins to allow all front ends to transparently use
|
||||
/// them. Create a static instance of this class in your plugin, providing a
|
||||
/// private function that the PassManagerBuilder can use to add your passes.
|
||||
struct RegisterStandardPasses {
|
||||
class RegisterStandardPasses {
|
||||
PassManagerBuilder::GlobalExtensionID ExtensionID;
|
||||
|
||||
public:
|
||||
RegisterStandardPasses(PassManagerBuilder::ExtensionPointTy Ty,
|
||||
PassManagerBuilder::ExtensionFn Fn) {
|
||||
PassManagerBuilder::addGlobalExtension(Ty, std::move(Fn));
|
||||
ExtensionID = PassManagerBuilder::addGlobalExtension(Ty, std::move(Fn));
|
||||
}
|
||||
|
||||
~RegisterStandardPasses() {
|
||||
// If the collection holding the global extensions is destroyed after the
|
||||
// plugin is unloaded, the extension has to be removed here. Indeed, the
|
||||
// destructor of the ExtensionFn may reference code in the plugin.
|
||||
PassManagerBuilder::removeGlobalExtension(ExtensionID);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -709,15 +709,21 @@ void AsmPrinter::EmitFunctionHeader() {
|
||||
// Emit M NOPs for -fpatchable-function-entry=N,M where M>0. We arbitrarily
|
||||
// place prefix data before NOPs.
|
||||
unsigned PatchableFunctionPrefix = 0;
|
||||
unsigned PatchableFunctionEntry = 0;
|
||||
(void)F.getFnAttribute("patchable-function-prefix")
|
||||
.getValueAsString()
|
||||
.getAsInteger(10, PatchableFunctionPrefix);
|
||||
(void)F.getFnAttribute("patchable-function-entry")
|
||||
.getValueAsString()
|
||||
.getAsInteger(10, PatchableFunctionEntry);
|
||||
if (PatchableFunctionPrefix) {
|
||||
CurrentPatchableFunctionEntrySym =
|
||||
OutContext.createLinkerPrivateTempSymbol();
|
||||
OutStreamer->EmitLabel(CurrentPatchableFunctionEntrySym);
|
||||
emitNops(PatchableFunctionPrefix);
|
||||
} else {
|
||||
} else if (PatchableFunctionEntry) {
|
||||
// May be reassigned when emitting the body, to reference the label after
|
||||
// the initial BTI (AArch64) or endbr32/endbr64 (x86).
|
||||
CurrentPatchableFunctionEntrySym = CurrentFnBegin;
|
||||
}
|
||||
|
||||
|
@ -968,8 +968,8 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(
|
||||
addAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_target),
|
||||
MachineLocation(CallReg));
|
||||
} else {
|
||||
DIE *CalleeDIE = getDIE(CalleeSP);
|
||||
assert(CalleeDIE && "Could not find DIE for call site entry origin");
|
||||
DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP);
|
||||
assert(CalleeDIE && "Could not create DIE for call site entry origin");
|
||||
addDIEEntry(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_origin),
|
||||
*CalleeDIE);
|
||||
}
|
||||
|
@ -540,14 +540,6 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU,
|
||||
}
|
||||
}
|
||||
|
||||
DIE &DwarfDebug::constructSubprogramDefinitionDIE(const DISubprogram *SP) {
|
||||
DICompileUnit *Unit = SP->getUnit();
|
||||
assert(SP->isDefinition() && "Subprogram not a definition");
|
||||
assert(Unit && "Subprogram definition without parent unit");
|
||||
auto &CU = getOrCreateDwarfCompileUnit(Unit);
|
||||
return *CU.getOrCreateSubprogramDIE(SP);
|
||||
}
|
||||
|
||||
/// Try to interpret values loaded into registers that forward parameters
|
||||
/// for \p CallMI. Store parameters with interpreted value into \p Params.
|
||||
static void collectCallSiteParameters(const MachineInstr *CallMI,
|
||||
@ -758,17 +750,6 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
|
||||
if (!CalleeDecl || !CalleeDecl->getSubprogram())
|
||||
continue;
|
||||
CalleeSP = CalleeDecl->getSubprogram();
|
||||
|
||||
if (CalleeSP->isDefinition()) {
|
||||
// Ensure that a subprogram DIE for the callee is available in the
|
||||
// appropriate CU.
|
||||
constructSubprogramDefinitionDIE(CalleeSP);
|
||||
} else {
|
||||
// Create the declaration DIE if it is missing. This is required to
|
||||
// support compilation of old bitcode with an incomplete list of
|
||||
// retained metadata.
|
||||
CU.getOrCreateSubprogramDIE(CalleeSP);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Omit call site entries for runtime calls (objc_msgSend, etc).
|
||||
@ -924,6 +905,11 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) {
|
||||
NewCU.setSection(Asm->getObjFileLowering().getDwarfInfoSection());
|
||||
}
|
||||
|
||||
// Create DIEs for function declarations used for call site debug info.
|
||||
for (auto Scope : DIUnit->getRetainedTypes())
|
||||
if (auto *SP = dyn_cast_or_null<DISubprogram>(Scope))
|
||||
NewCU.getOrCreateSubprogramDIE(SP);
|
||||
|
||||
CUMap.insert({DIUnit, &NewCU});
|
||||
CUDieMap.insert({&NewCU.getUnitDie(), &NewCU});
|
||||
return NewCU;
|
||||
|
@ -442,9 +442,6 @@ class DwarfDebug : public DebugHandlerBase {
|
||||
/// Construct a DIE for this abstract scope.
|
||||
void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope);
|
||||
|
||||
/// Construct a DIE for the subprogram definition \p SP and return it.
|
||||
DIE &constructSubprogramDefinitionDIE(const DISubprogram *SP);
|
||||
|
||||
/// Construct DIEs for call site entries describing the calls in \p MF.
|
||||
void constructCallSiteEntryDIEs(const DISubprogram &SP, DwarfCompileUnit &CU,
|
||||
DIE &ScopeDIE, const MachineFunction &MF);
|
||||
|
@ -188,9 +188,8 @@ int64_t DwarfUnit::getDefaultLowerBound() const {
|
||||
|
||||
/// Check whether the DIE for this MDNode can be shared across CUs.
|
||||
bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const {
|
||||
// When the MDNode can be part of the type system (this includes subprogram
|
||||
// declarations *and* subprogram definitions, even local definitions), the
|
||||
// DIE must be shared across CUs.
|
||||
// When the MDNode can be part of the type system, the DIE can be shared
|
||||
// across CUs.
|
||||
// Combining type units and cross-CU DIE sharing is lower value (since
|
||||
// cross-CU DIE sharing is used in LTO and removes type redundancy at that
|
||||
// level already) but may be implementable for some value in projects
|
||||
@ -198,7 +197,9 @@ bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const {
|
||||
// together.
|
||||
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
|
||||
return false;
|
||||
return (isa<DIType>(D) || isa<DISubprogram>(D)) && !DD->generateTypeUnits();
|
||||
return (isa<DIType>(D) ||
|
||||
(isa<DISubprogram>(D) && !cast<DISubprogram>(D)->isDefinition())) &&
|
||||
!DD->generateTypeUnits();
|
||||
}
|
||||
|
||||
DIE *DwarfUnit::getDIE(const DINode *D) const {
|
||||
|
@ -6857,12 +6857,20 @@ static bool splitMergedValStore(StoreInst &SI, const DataLayout &DL,
|
||||
Value *Addr = Builder.CreateBitCast(
|
||||
SI.getOperand(1),
|
||||
SplitStoreType->getPointerTo(SI.getPointerAddressSpace()));
|
||||
if ((IsLE && Upper) || (!IsLE && !Upper))
|
||||
const bool IsOffsetStore = (IsLE && Upper) || (!IsLE && !Upper);
|
||||
if (IsOffsetStore)
|
||||
Addr = Builder.CreateGEP(
|
||||
SplitStoreType, Addr,
|
||||
ConstantInt::get(Type::getInt32Ty(SI.getContext()), 1));
|
||||
MaybeAlign Alignment(SI.getAlignment());
|
||||
if (IsOffsetStore && Alignment) {
|
||||
// When splitting the store in half, naturally one half will retain the
|
||||
// alignment of the original wider store, regardless of whether it was
|
||||
// over-aligned or not, while the other will require adjustment.
|
||||
Alignment = commonAlignment(Alignment, HalfValBitSize / 8);
|
||||
}
|
||||
Builder.CreateAlignedStore(
|
||||
V, Addr, Upper ? SI.getAlignment() / 2 : SI.getAlignment());
|
||||
V, Addr, Alignment.hasValue() ? Alignment.getValue().value() : 0);
|
||||
};
|
||||
|
||||
CreateSplitStore(LValue, false);
|
||||
|
@ -1385,7 +1385,7 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
||||
if (!V) {
|
||||
// Currently the optimizer can produce this; insert an undef to
|
||||
// help debugging. Probably the optimizer should not do this.
|
||||
MIRBuilder.buildDirectDbgValue(0, DI.getVariable(), DI.getExpression());
|
||||
MIRBuilder.buildIndirectDbgValue(0, DI.getVariable(), DI.getExpression());
|
||||
} else if (const auto *CI = dyn_cast<Constant>(V)) {
|
||||
MIRBuilder.buildConstDbgValue(*CI, DI.getVariable(), DI.getExpression());
|
||||
} else {
|
||||
|
@ -107,13 +107,9 @@ MachineIRBuilder::buildIndirectDbgValue(Register Reg, const MDNode *Variable,
|
||||
assert(
|
||||
cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(getDL()) &&
|
||||
"Expected inlined-at fields to agree");
|
||||
// DBG_VALUE insts now carry IR-level indirection in their DIExpression
|
||||
// rather than encoding it in the instruction itself.
|
||||
const DIExpression *DIExpr = cast<DIExpression>(Expr);
|
||||
DIExpr = DIExpression::append(DIExpr, {dwarf::DW_OP_deref});
|
||||
return insertInstr(BuildMI(getMF(), getDL(),
|
||||
getTII().get(TargetOpcode::DBG_VALUE),
|
||||
/*IsIndirect*/ false, Reg, Variable, DIExpr));
|
||||
/*IsIndirect*/ true, Reg, Variable, Expr));
|
||||
}
|
||||
|
||||
MachineInstrBuilder MachineIRBuilder::buildFIDbgValue(int FI,
|
||||
@ -124,15 +120,11 @@ MachineInstrBuilder MachineIRBuilder::buildFIDbgValue(int FI,
|
||||
assert(
|
||||
cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(getDL()) &&
|
||||
"Expected inlined-at fields to agree");
|
||||
// DBG_VALUE insts now carry IR-level indirection in their DIExpression
|
||||
// rather than encoding it in the instruction itself.
|
||||
const DIExpression *DIExpr = cast<DIExpression>(Expr);
|
||||
DIExpr = DIExpression::append(DIExpr, {dwarf::DW_OP_deref});
|
||||
return buildInstr(TargetOpcode::DBG_VALUE)
|
||||
.addFrameIndex(FI)
|
||||
.addReg(0)
|
||||
.addImm(0)
|
||||
.addMetadata(Variable)
|
||||
.addMetadata(DIExpr);
|
||||
.addMetadata(Expr);
|
||||
}
|
||||
|
||||
MachineInstrBuilder MachineIRBuilder::buildConstDbgValue(const Constant &C,
|
||||
@ -156,7 +148,7 @@ MachineInstrBuilder MachineIRBuilder::buildConstDbgValue(const Constant &C,
|
||||
MIB.addReg(0U);
|
||||
}
|
||||
|
||||
return MIB.addReg(0).addMetadata(Variable).addMetadata(Expr);
|
||||
return MIB.addImm(0).addMetadata(Variable).addMetadata(Expr);
|
||||
}
|
||||
|
||||
MachineInstrBuilder MachineIRBuilder::buildDbgLabel(const MDNode *Label) {
|
||||
|
@ -524,6 +524,7 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
|
||||
for (ssize_t k = i, idx = 0; k != j; k = GlobalSet.find_next(k), ++idx) {
|
||||
GlobalValue::LinkageTypes Linkage = Globals[k]->getLinkage();
|
||||
std::string Name = Globals[k]->getName();
|
||||
GlobalValue::VisibilityTypes Visibility = Globals[k]->getVisibility();
|
||||
GlobalValue::DLLStorageClassTypes DLLStorage =
|
||||
Globals[k]->getDLLStorageClass();
|
||||
|
||||
@ -549,6 +550,7 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
|
||||
if (Linkage != GlobalValue::InternalLinkage || !IsMachO) {
|
||||
GlobalAlias *GA = GlobalAlias::create(Tys[StructIdxs[idx]], AddrSpace,
|
||||
Linkage, Name, GEP, &M);
|
||||
GA->setVisibility(Visibility);
|
||||
GA->setDLLStorageClass(DLLStorage);
|
||||
}
|
||||
|
||||
|
@ -100,27 +100,28 @@ enum : unsigned { UndefLocNo = ~0U };
|
||||
/// usage of the location.
|
||||
class DbgValueLocation {
|
||||
public:
|
||||
DbgValueLocation(unsigned LocNo)
|
||||
: LocNo(LocNo) {
|
||||
DbgValueLocation(unsigned LocNo, bool WasIndirect)
|
||||
: LocNo(LocNo), WasIndirect(WasIndirect) {
|
||||
static_assert(sizeof(*this) == sizeof(unsigned), "bad bitfield packing");
|
||||
assert(locNo() == LocNo && "location truncation");
|
||||
}
|
||||
|
||||
DbgValueLocation() : LocNo(0) {}
|
||||
DbgValueLocation() : LocNo(0), WasIndirect(0) {}
|
||||
|
||||
unsigned locNo() const {
|
||||
// Fix up the undef location number, which gets truncated.
|
||||
return LocNo == INT_MAX ? UndefLocNo : LocNo;
|
||||
}
|
||||
bool wasIndirect() const { return WasIndirect; }
|
||||
bool isUndef() const { return locNo() == UndefLocNo; }
|
||||
|
||||
DbgValueLocation changeLocNo(unsigned NewLocNo) const {
|
||||
return DbgValueLocation(NewLocNo);
|
||||
return DbgValueLocation(NewLocNo, WasIndirect);
|
||||
}
|
||||
|
||||
friend inline bool operator==(const DbgValueLocation &LHS,
|
||||
const DbgValueLocation &RHS) {
|
||||
return LHS.LocNo == RHS.LocNo;
|
||||
return LHS.LocNo == RHS.LocNo && LHS.WasIndirect == RHS.WasIndirect;
|
||||
}
|
||||
|
||||
friend inline bool operator!=(const DbgValueLocation &LHS,
|
||||
@ -129,7 +130,8 @@ class DbgValueLocation {
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned LocNo;
|
||||
unsigned LocNo : 31;
|
||||
unsigned WasIndirect : 1;
|
||||
};
|
||||
|
||||
/// Map of where a user value is live, and its location.
|
||||
@ -166,6 +168,10 @@ class UserValue {
|
||||
/// Map of slot indices where this value is live.
|
||||
LocMap locInts;
|
||||
|
||||
/// Set of interval start indexes that have been trimmed to the
|
||||
/// lexical scope.
|
||||
SmallSet<SlotIndex, 2> trimmedDefs;
|
||||
|
||||
/// Insert a DBG_VALUE into MBB at Idx for LocNo.
|
||||
void insertDebugValue(MachineBasicBlock *MBB, SlotIndex StartIdx,
|
||||
SlotIndex StopIdx, DbgValueLocation Loc, bool Spilled,
|
||||
@ -279,8 +285,8 @@ class UserValue {
|
||||
void mapVirtRegs(LDVImpl *LDV);
|
||||
|
||||
/// Add a definition point to this value.
|
||||
void addDef(SlotIndex Idx, const MachineOperand &LocMO) {
|
||||
DbgValueLocation Loc(getLocationNo(LocMO));
|
||||
void addDef(SlotIndex Idx, const MachineOperand &LocMO, bool IsIndirect) {
|
||||
DbgValueLocation Loc(getLocationNo(LocMO), IsIndirect);
|
||||
// Add a singular (Idx,Idx) -> Loc mapping.
|
||||
LocMap::iterator I = locInts.find(Idx);
|
||||
if (!I.valid() || I.start() != Idx)
|
||||
@ -315,10 +321,11 @@ class UserValue {
|
||||
///
|
||||
/// \param LI Scan for copies of the value in LI->reg.
|
||||
/// \param LocNo Location number of LI->reg.
|
||||
/// \param WasIndirect Indicates if the original use of LI->reg was indirect
|
||||
/// \param Kills Points where the range of LocNo could be extended.
|
||||
/// \param [in,out] NewDefs Append (Idx, LocNo) of inserted defs here.
|
||||
void addDefsFromCopies(
|
||||
LiveInterval *LI, unsigned LocNo,
|
||||
LiveInterval *LI, unsigned LocNo, bool WasIndirect,
|
||||
const SmallVectorImpl<SlotIndex> &Kills,
|
||||
SmallVectorImpl<std::pair<SlotIndex, DbgValueLocation>> &NewDefs,
|
||||
MachineRegisterInfo &MRI, LiveIntervals &LIS);
|
||||
@ -538,6 +545,8 @@ void UserValue::print(raw_ostream &OS, const TargetRegisterInfo *TRI) {
|
||||
OS << "undef";
|
||||
else {
|
||||
OS << I.value().locNo();
|
||||
if (I.value().wasIndirect())
|
||||
OS << " ind";
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0, e = locations.size(); i != e; ++i) {
|
||||
@ -646,18 +655,19 @@ bool LDVImpl::handleDebugValue(MachineInstr &MI, SlotIndex Idx) {
|
||||
}
|
||||
|
||||
// Get or create the UserValue for (variable,offset) here.
|
||||
assert(!MI.getOperand(1).isImm() && "DBG_VALUE with indirect flag before "
|
||||
"LiveDebugVariables");
|
||||
bool IsIndirect = MI.getOperand(1).isImm();
|
||||
if (IsIndirect)
|
||||
assert(MI.getOperand(1).getImm() == 0 && "DBG_VALUE with nonzero offset");
|
||||
const DILocalVariable *Var = MI.getDebugVariable();
|
||||
const DIExpression *Expr = MI.getDebugExpression();
|
||||
UserValue *UV =
|
||||
getUserValue(Var, Expr, MI.getDebugLoc());
|
||||
if (!Discard)
|
||||
UV->addDef(Idx, MI.getOperand(0));
|
||||
UV->addDef(Idx, MI.getOperand(0), IsIndirect);
|
||||
else {
|
||||
MachineOperand MO = MachineOperand::CreateReg(0U, false);
|
||||
MO.setIsDebug();
|
||||
UV->addDef(Idx, MO);
|
||||
UV->addDef(Idx, MO, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -765,7 +775,7 @@ void UserValue::extendDef(SlotIndex Idx, DbgValueLocation Loc, LiveRange *LR,
|
||||
}
|
||||
|
||||
void UserValue::addDefsFromCopies(
|
||||
LiveInterval *LI, unsigned LocNo,
|
||||
LiveInterval *LI, unsigned LocNo, bool WasIndirect,
|
||||
const SmallVectorImpl<SlotIndex> &Kills,
|
||||
SmallVectorImpl<std::pair<SlotIndex, DbgValueLocation>> &NewDefs,
|
||||
MachineRegisterInfo &MRI, LiveIntervals &LIS) {
|
||||
@ -829,7 +839,7 @@ void UserValue::addDefsFromCopies(
|
||||
MachineInstr *CopyMI = LIS.getInstructionFromIndex(DstVNI->def);
|
||||
assert(CopyMI && CopyMI->isCopy() && "Bad copy value");
|
||||
unsigned LocNo = getLocationNo(CopyMI->getOperand(0));
|
||||
DbgValueLocation NewLoc(LocNo);
|
||||
DbgValueLocation NewLoc(LocNo, WasIndirect);
|
||||
I.insert(Idx, Idx.getNextSlot(), NewLoc);
|
||||
NewDefs.push_back(std::make_pair(Idx, NewLoc));
|
||||
break;
|
||||
@ -877,7 +887,8 @@ void UserValue::computeIntervals(MachineRegisterInfo &MRI,
|
||||
// sub-register in that regclass). For now, simply skip handling copies if
|
||||
// a sub-register is involved.
|
||||
if (LI && !LocMO.getSubReg())
|
||||
addDefsFromCopies(LI, Loc.locNo(), Kills, Defs, MRI, LIS);
|
||||
addDefsFromCopies(LI, Loc.locNo(), Loc.wasIndirect(), Kills, Defs, MRI,
|
||||
LIS);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -910,6 +921,11 @@ void UserValue::computeIntervals(MachineRegisterInfo &MRI,
|
||||
SlotIndex RStart = LIS.getInstructionIndex(*Range.first);
|
||||
SlotIndex REnd = LIS.getInstructionIndex(*Range.second);
|
||||
|
||||
// Variable locations at the first instruction of a block should be
|
||||
// based on the block's SlotIndex, not the first instruction's index.
|
||||
if (Range.first == Range.first->getParent()->begin())
|
||||
RStart = LIS.getSlotIndexes()->getIndexBefore(*Range.first);
|
||||
|
||||
// At the start of each iteration I has been advanced so that
|
||||
// I.stop() >= PrevEnd. Check for overlap.
|
||||
if (PrevEnd && I.start() < PrevEnd) {
|
||||
@ -922,7 +938,8 @@ void UserValue::computeIntervals(MachineRegisterInfo &MRI,
|
||||
++I;
|
||||
|
||||
// If the interval also overlaps the start of the "next" (i.e.
|
||||
// current) range create a new interval for the remainder
|
||||
// current) range create a new interval for the remainder (which
|
||||
// may be further trimmed).
|
||||
if (RStart < IStop)
|
||||
I.insert(RStart, IStop, Loc);
|
||||
}
|
||||
@ -932,6 +949,13 @@ void UserValue::computeIntervals(MachineRegisterInfo &MRI,
|
||||
if (!I.valid())
|
||||
return;
|
||||
|
||||
if (I.start() < RStart) {
|
||||
// Interval start overlaps range - trim to the scope range.
|
||||
I.setStartUnchecked(RStart);
|
||||
// Remember that this interval was trimmed.
|
||||
trimmedDefs.insert(RStart);
|
||||
}
|
||||
|
||||
// The end of a lexical scope range is the last instruction in the
|
||||
// range. To convert to an interval we need the index of the
|
||||
// instruction after it.
|
||||
@ -1306,14 +1330,21 @@ void UserValue::insertDebugValue(MachineBasicBlock *MBB, SlotIndex StartIdx,
|
||||
// that the original virtual register was a pointer. Also, add the stack slot
|
||||
// offset for the spilled register to the expression.
|
||||
const DIExpression *Expr = Expression;
|
||||
if (Spilled)
|
||||
Expr = DIExpression::prepend(Expr, DIExpression::ApplyOffset, SpillOffset);
|
||||
uint8_t DIExprFlags = DIExpression::ApplyOffset;
|
||||
bool IsIndirect = Loc.wasIndirect();
|
||||
if (Spilled) {
|
||||
if (IsIndirect)
|
||||
DIExprFlags |= DIExpression::DerefAfter;
|
||||
Expr =
|
||||
DIExpression::prepend(Expr, DIExprFlags, SpillOffset);
|
||||
IsIndirect = true;
|
||||
}
|
||||
|
||||
assert((!Spilled || MO.isFI()) && "a spilled location must be a frame index");
|
||||
|
||||
do {
|
||||
BuildMI(*MBB, I, getDebugLoc(), TII.get(TargetOpcode::DBG_VALUE),
|
||||
Spilled, MO, Variable, Expr);
|
||||
IsIndirect, MO, Variable, Expr);
|
||||
|
||||
// Continue and insert DBG_VALUES after every redefinition of register
|
||||
// associated with the debug value within the range
|
||||
@ -1345,6 +1376,12 @@ void UserValue::emitDebugValues(VirtRegMap *VRM, LiveIntervals &LIS,
|
||||
bool Spilled = SpillIt != SpillOffsets.end();
|
||||
unsigned SpillOffset = Spilled ? SpillIt->second : 0;
|
||||
|
||||
// If the interval start was trimmed to the lexical scope insert the
|
||||
// DBG_VALUE at the previous index (otherwise it appears after the
|
||||
// first instruction in the range).
|
||||
if (trimmedDefs.count(Start))
|
||||
Start = Start.getPrevIndex();
|
||||
|
||||
LLVM_DEBUG(dbgs() << "\t[" << Start << ';' << Stop << "):" << Loc.locNo());
|
||||
MachineFunction::iterator MBB = LIS.getMBBFromIndex(Start)->getIterator();
|
||||
SlotIndex MBBEnd = LIS.getMBBEndIdx(&*MBB);
|
||||
|
@ -1393,11 +1393,9 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
|
||||
"Expected inlined-at fields to agree");
|
||||
// A dbg.declare describes the address of a source variable, so lower it
|
||||
// into an indirect DBG_VALUE.
|
||||
auto *Expr = DI->getExpression();
|
||||
Expr = DIExpression::append(Expr, {dwarf::DW_OP_deref});
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ false,
|
||||
*Op, DI->getVariable(), Expr);
|
||||
TII.get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ true,
|
||||
*Op, DI->getVariable(), DI->getExpression());
|
||||
} else {
|
||||
// We can't yet handle anything else here because it would require
|
||||
// generating code, thus altering codegen because of debug info.
|
||||
@ -1421,19 +1419,19 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
|
||||
if (CI->getBitWidth() > 64)
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
|
||||
.addCImm(CI)
|
||||
.addReg(0U)
|
||||
.addImm(0U)
|
||||
.addMetadata(DI->getVariable())
|
||||
.addMetadata(DI->getExpression());
|
||||
else
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
|
||||
.addImm(CI->getZExtValue())
|
||||
.addReg(0U)
|
||||
.addImm(0U)
|
||||
.addMetadata(DI->getVariable())
|
||||
.addMetadata(DI->getExpression());
|
||||
} else if (const auto *CF = dyn_cast<ConstantFP>(V)) {
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
|
||||
.addFPImm(CF)
|
||||
.addReg(0U)
|
||||
.addImm(0U)
|
||||
.addMetadata(DI->getVariable())
|
||||
.addMetadata(DI->getExpression());
|
||||
} else if (unsigned Reg = lookUpRegForValue(V)) {
|
||||
|
@ -677,7 +677,7 @@ MachineInstr *
|
||||
InstrEmitter::EmitDbgValue(SDDbgValue *SD,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap) {
|
||||
MDNode *Var = SD->getVariable();
|
||||
const DIExpression *Expr = SD->getExpression();
|
||||
MDNode *Expr = SD->getExpression();
|
||||
DebugLoc DL = SD->getDebugLoc();
|
||||
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
|
||||
"Expected inlined-at fields to agree");
|
||||
@ -701,11 +701,12 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
|
||||
// EmitTargetCodeForFrameDebugValue is responsible for allocation.
|
||||
auto FrameMI = BuildMI(*MF, DL, TII->get(TargetOpcode::DBG_VALUE))
|
||||
.addFrameIndex(SD->getFrameIx());
|
||||
|
||||
if (SD->isIndirect())
|
||||
Expr = DIExpression::append(Expr, {dwarf::DW_OP_deref});
|
||||
|
||||
FrameMI.addReg(0);
|
||||
// Push [fi + 0] onto the DIExpression stack.
|
||||
FrameMI.addImm(0);
|
||||
else
|
||||
// Push fi onto the DIExpression stack.
|
||||
FrameMI.addReg(0);
|
||||
return FrameMI.addMetadata(Var).addMetadata(Expr);
|
||||
}
|
||||
// Otherwise, we're going to create an instruction here.
|
||||
@ -751,9 +752,9 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
|
||||
|
||||
// Indirect addressing is indicated by an Imm as the second parameter.
|
||||
if (SD->isIndirect())
|
||||
Expr = DIExpression::append(Expr, {dwarf::DW_OP_deref});
|
||||
|
||||
MIB.addReg(0U, RegState::Debug);
|
||||
MIB.addImm(0U);
|
||||
else
|
||||
MIB.addReg(0U, RegState::Debug);
|
||||
|
||||
MIB.addMetadata(Var);
|
||||
MIB.addMetadata(Expr);
|
||||
|
@ -4716,11 +4716,11 @@ SDValue DAGTypeLegalizer::WidenVecOp_VECREDUCE(SDNode *N) {
|
||||
break;
|
||||
case ISD::VECREDUCE_FMAX:
|
||||
NeutralElem = DAG.getConstantFP(
|
||||
std::numeric_limits<double>::infinity(), dl, ElemVT);
|
||||
-std::numeric_limits<double>::infinity(), dl, ElemVT);
|
||||
break;
|
||||
case ISD::VECREDUCE_FMIN:
|
||||
NeutralElem = DAG.getConstantFP(
|
||||
-std::numeric_limits<double>::infinity(), dl, ElemVT);
|
||||
std::numeric_limits<double>::infinity(), dl, ElemVT);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -5622,6 +5622,7 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
const TargetInstrInfo *TII = DAG.getSubtarget().getInstrInfo();
|
||||
|
||||
bool IsIndirect = false;
|
||||
Optional<MachineOperand> Op;
|
||||
// Some arguments' frame index is recorded during argument lowering.
|
||||
int FI = FuncInfo.getArgumentFrameIndex(Arg);
|
||||
@ -5643,6 +5644,7 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
|
||||
}
|
||||
if (Reg) {
|
||||
Op = MachineOperand::CreateReg(Reg, false);
|
||||
IsIndirect = IsDbgDeclare;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5691,7 +5693,7 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
|
||||
}
|
||||
assert(!IsDbgDeclare && "DbgDeclare operand is not in memory?");
|
||||
FuncInfo.ArgDbgValues.push_back(
|
||||
BuildMI(MF, DL, TII->get(TargetOpcode::DBG_VALUE), false,
|
||||
BuildMI(MF, DL, TII->get(TargetOpcode::DBG_VALUE), IsDbgDeclare,
|
||||
RegAndSize.first, Variable, *FragmentExpr));
|
||||
}
|
||||
};
|
||||
@ -5709,6 +5711,7 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
|
||||
}
|
||||
|
||||
Op = MachineOperand::CreateReg(VMI->second, false);
|
||||
IsIndirect = IsDbgDeclare;
|
||||
} else if (ArgRegsAndSizes.size() > 1) {
|
||||
// This was split due to the calling convention, and no virtual register
|
||||
// mapping exists for the value.
|
||||
@ -5722,28 +5725,9 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
|
||||
|
||||
assert(Variable->isValidLocationForIntrinsic(DL) &&
|
||||
"Expected inlined-at fields to agree");
|
||||
|
||||
// If the argument arrives in a stack slot, then what the IR thought was a
|
||||
// normal Value is actually in memory, and we must add a deref to load it.
|
||||
if (Op->isFI()) {
|
||||
int FI = Op->getIndex();
|
||||
unsigned Size = DAG.getMachineFunction().getFrameInfo().getObjectSize(FI);
|
||||
if (Expr->isImplicit()) {
|
||||
SmallVector<uint64_t, 2> Ops = {dwarf::DW_OP_deref_size, Size};
|
||||
Expr = DIExpression::prependOpcodes(Expr, Ops);
|
||||
} else {
|
||||
Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore);
|
||||
}
|
||||
}
|
||||
|
||||
// If this location was specified with a dbg.declare, then it and its
|
||||
// expression calculate the address of the variable. Append a deref to
|
||||
// force it to be a memory location.
|
||||
if (IsDbgDeclare)
|
||||
Expr = DIExpression::append(Expr, {dwarf::DW_OP_deref});
|
||||
|
||||
IsIndirect = (Op->isReg()) ? IsIndirect : true;
|
||||
FuncInfo.ArgDbgValues.push_back(
|
||||
BuildMI(MF, DL, TII->get(TargetOpcode::DBG_VALUE), false,
|
||||
BuildMI(MF, DL, TII->get(TargetOpcode::DBG_VALUE), IsIndirect,
|
||||
*Op, Variable, Expr));
|
||||
|
||||
return true;
|
||||
|
@ -960,7 +960,8 @@ void StackColoring::remapInstructions(DenseMap<int, int> &SlotRemap) {
|
||||
}
|
||||
|
||||
// Remap all instructions to the new stack slots.
|
||||
std::vector<std::vector<MachineMemOperand *>> SSRefs(MFI->getObjectIndexEnd());
|
||||
std::vector<std::vector<MachineMemOperand *>> SSRefs(
|
||||
MFI->getObjectIndexEnd());
|
||||
for (MachineBasicBlock &BB : *MF)
|
||||
for (MachineInstr &I : BB) {
|
||||
// Skip lifetime markers. We'll remove them soon.
|
||||
@ -1074,12 +1075,13 @@ void StackColoring::remapInstructions(DenseMap<int, int> &SlotRemap) {
|
||||
}
|
||||
|
||||
// Rewrite MachineMemOperands that reference old frame indices.
|
||||
for (auto E : enumerate(SSRefs)) {
|
||||
const PseudoSourceValue *NewSV =
|
||||
MF->getPSVManager().getFixedStack(SlotRemap[E.index()]);
|
||||
for (MachineMemOperand *Ref : E.value())
|
||||
Ref->setValue(NewSV);
|
||||
}
|
||||
for (auto E : enumerate(SSRefs))
|
||||
if (!E.value().empty()) {
|
||||
const PseudoSourceValue *NewSV =
|
||||
MF->getPSVManager().getFixedStack(SlotRemap.find(E.index())->second);
|
||||
for (MachineMemOperand *Ref : E.value())
|
||||
Ref->setValue(NewSV);
|
||||
}
|
||||
|
||||
// Update the location of C++ catch objects for the MSVC personality routine.
|
||||
if (WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo())
|
||||
|
@ -847,8 +847,7 @@ bool TypePromotion::TryToPromote(Value *V, unsigned PromotedWidth) {
|
||||
|
||||
// Iterate through, and add to, a tree of operands and users in the use-def.
|
||||
while (!WorkList.empty()) {
|
||||
Value *V = WorkList.back();
|
||||
WorkList.pop_back();
|
||||
Value *V = WorkList.pop_back_val();
|
||||
if (CurrentVisited.count(V))
|
||||
continue;
|
||||
|
||||
@ -917,7 +916,7 @@ bool TypePromotion::TryToPromote(Value *V, unsigned PromotedWidth) {
|
||||
++ToPromote;
|
||||
}
|
||||
|
||||
// DAG optimisations should be able to handle these cases better, especially
|
||||
// DAG optimizations should be able to handle these cases better, especially
|
||||
// for function arguments.
|
||||
if (ToPromote < 2 || (Blocks.size() == 1 && (NonFreeArgs > SafeWrap.size())))
|
||||
return false;
|
||||
@ -941,6 +940,9 @@ bool TypePromotion::runOnFunction(Function &F) {
|
||||
if (!TPC)
|
||||
return false;
|
||||
|
||||
AllVisited.clear();
|
||||
SafeToPromote.clear();
|
||||
SafeWrap.clear();
|
||||
bool MadeChange = false;
|
||||
const DataLayout &DL = F.getParent()->getDataLayout();
|
||||
const TargetMachine &TM = TPC->getTM<TargetMachine>();
|
||||
@ -998,6 +1000,10 @@ bool TypePromotion::runOnFunction(Function &F) {
|
||||
if (MadeChange)
|
||||
LLVM_DEBUG(dbgs() << "After TypePromotion: " << F << "\n");
|
||||
|
||||
AllVisited.clear();
|
||||
SafeToPromote.clear();
|
||||
SafeWrap.clear();
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
|
@ -67,9 +67,11 @@ namespace orc {
|
||||
|
||||
class PartitioningIRMaterializationUnit : public IRMaterializationUnit {
|
||||
public:
|
||||
PartitioningIRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM,
|
||||
VModuleKey K, CompileOnDemandLayer &Parent)
|
||||
: IRMaterializationUnit(ES, std::move(TSM), std::move(K)),
|
||||
PartitioningIRMaterializationUnit(ExecutionSession &ES,
|
||||
const ManglingOptions &MO,
|
||||
ThreadSafeModule TSM, VModuleKey K,
|
||||
CompileOnDemandLayer &Parent)
|
||||
: IRMaterializationUnit(ES, MO, std::move(TSM), std::move(K)),
|
||||
Parent(Parent) {}
|
||||
|
||||
PartitioningIRMaterializationUnit(
|
||||
@ -111,7 +113,8 @@ CompileOnDemandLayer::compileWholeModule(GlobalValueSet Requested) {
|
||||
CompileOnDemandLayer::CompileOnDemandLayer(
|
||||
ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr,
|
||||
IndirectStubsManagerBuilder BuildIndirectStubsManager)
|
||||
: IRLayer(ES), BaseLayer(BaseLayer), LCTMgr(LCTMgr),
|
||||
: IRLayer(ES, BaseLayer.getManglingOptions()), BaseLayer(BaseLayer),
|
||||
LCTMgr(LCTMgr),
|
||||
BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {}
|
||||
|
||||
void CompileOnDemandLayer::setPartitionFunction(PartitionFunction Partition) {
|
||||
@ -136,27 +139,23 @@ void CompileOnDemandLayer::emit(MaterializationResponsibility R,
|
||||
TSM.withModuleDo([&](Module &M) {
|
||||
// First, do some cleanup on the module:
|
||||
cleanUpModule(M);
|
||||
|
||||
MangleAndInterner Mangle(ES, M.getDataLayout());
|
||||
for (auto &GV : M.global_values()) {
|
||||
if (GV.isDeclaration() || GV.hasLocalLinkage() ||
|
||||
GV.hasAppendingLinkage())
|
||||
continue;
|
||||
|
||||
auto Name = Mangle(GV.getName());
|
||||
auto Flags = JITSymbolFlags::fromGlobalValue(GV);
|
||||
if (Flags.isCallable())
|
||||
Callables[Name] = SymbolAliasMapEntry(Name, Flags);
|
||||
else
|
||||
NonCallables[Name] = SymbolAliasMapEntry(Name, Flags);
|
||||
}
|
||||
});
|
||||
|
||||
for (auto &KV : R.getSymbols()) {
|
||||
auto &Name = KV.first;
|
||||
auto &Flags = KV.second;
|
||||
if (Flags.isCallable())
|
||||
Callables[Name] = SymbolAliasMapEntry(Name, Flags);
|
||||
else
|
||||
NonCallables[Name] = SymbolAliasMapEntry(Name, Flags);
|
||||
}
|
||||
|
||||
// Create a partitioning materialization unit and lodge it with the
|
||||
// implementation dylib.
|
||||
if (auto Err = PDR.getImplDylib().define(
|
||||
std::make_unique<PartitioningIRMaterializationUnit>(
|
||||
ES, std::move(TSM), R.getVModuleKey(), *this))) {
|
||||
ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(),
|
||||
*this))) {
|
||||
ES.reportError(std::move(Err));
|
||||
R.failMaterialization();
|
||||
return;
|
||||
@ -316,7 +315,7 @@ void CompileOnDemandLayer::emitPartition(
|
||||
}
|
||||
|
||||
R.replace(std::make_unique<PartitioningIRMaterializationUnit>(
|
||||
ES, std::move(TSM), R.getVModuleKey(), *this));
|
||||
ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(), *this));
|
||||
BaseLayer.emit(std::move(R), std::move(*ExtractedTSM));
|
||||
}
|
||||
|
||||
|
@ -24,11 +24,20 @@
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
IRMaterializationUnit::ManglingOptions
|
||||
irManglingOptionsFromTargetOptions(const TargetOptions &Opts) {
|
||||
IRMaterializationUnit::ManglingOptions MO;
|
||||
|
||||
MO.EmulatedTLS = Opts.EmulatedTLS;
|
||||
|
||||
return MO;
|
||||
}
|
||||
|
||||
/// Compile a Module to an ObjectFile.
|
||||
SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) {
|
||||
Expected<SimpleCompiler::CompileResult> SimpleCompiler::operator()(Module &M) {
|
||||
CompileResult CachedObject = tryToLoadFromObjectCache(M);
|
||||
if (CachedObject)
|
||||
return CachedObject;
|
||||
return std::move(CachedObject);
|
||||
|
||||
SmallVector<char, 0> ObjBufferSV;
|
||||
|
||||
@ -38,7 +47,8 @@ SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) {
|
||||
legacy::PassManager PM;
|
||||
MCContext *Ctx;
|
||||
if (TM.addPassesToEmitMC(PM, Ctx, ObjStream))
|
||||
llvm_unreachable("Target does not support MC emission.");
|
||||
return make_error<StringError>("Target does not support MC emission",
|
||||
inconvertibleErrorCode());
|
||||
PM.run(M);
|
||||
}
|
||||
|
||||
@ -47,14 +57,11 @@ SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) {
|
||||
|
||||
auto Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
|
||||
|
||||
if (Obj) {
|
||||
notifyObjectCompiled(M, *ObjBuffer);
|
||||
return std::move(ObjBuffer);
|
||||
}
|
||||
if (!Obj)
|
||||
return Obj.takeError();
|
||||
|
||||
// TODO: Actually report errors helpfully.
|
||||
consumeError(Obj.takeError());
|
||||
return nullptr;
|
||||
notifyObjectCompiled(M, *ObjBuffer);
|
||||
return std::move(ObjBuffer);
|
||||
}
|
||||
|
||||
SimpleCompiler::CompileResult
|
||||
@ -73,9 +80,11 @@ void SimpleCompiler::notifyObjectCompiled(const Module &M,
|
||||
|
||||
ConcurrentIRCompiler::ConcurrentIRCompiler(JITTargetMachineBuilder JTMB,
|
||||
ObjectCache *ObjCache)
|
||||
: JTMB(std::move(JTMB)), ObjCache(ObjCache) {}
|
||||
: IRCompiler(irManglingOptionsFromTargetOptions(JTMB.getOptions())),
|
||||
JTMB(std::move(JTMB)), ObjCache(ObjCache) {}
|
||||
|
||||
std::unique_ptr<MemoryBuffer> ConcurrentIRCompiler::operator()(Module &M) {
|
||||
Expected<std::unique_ptr<MemoryBuffer>>
|
||||
ConcurrentIRCompiler::operator()(Module &M) {
|
||||
auto TM = cantFail(JTMB.createTargetMachine());
|
||||
SimpleCompiler C(*TM, ObjCache);
|
||||
return C(M);
|
||||
|
@ -468,15 +468,19 @@ Error MaterializationResponsibility::notifyEmitted() {
|
||||
}
|
||||
|
||||
Error MaterializationResponsibility::defineMaterializing(
|
||||
const SymbolFlagsMap &NewSymbolFlags) {
|
||||
// Add the given symbols to this responsibility object.
|
||||
// It's ok if we hit a duplicate here: In that case the new version will be
|
||||
// discarded, and the JITDylib::defineMaterializing method will return a
|
||||
// duplicate symbol error.
|
||||
for (auto &KV : NewSymbolFlags)
|
||||
SymbolFlags.insert(KV);
|
||||
SymbolFlagsMap NewSymbolFlags) {
|
||||
|
||||
return JD.defineMaterializing(NewSymbolFlags);
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "In " << JD.getName() << " defining materializing symbols "
|
||||
<< NewSymbolFlags << "\n";
|
||||
});
|
||||
if (auto AcceptedDefs = JD.defineMaterializing(std::move(NewSymbolFlags))) {
|
||||
// Add all newly accepted symbols to this responsibility object.
|
||||
for (auto &KV : *AcceptedDefs)
|
||||
SymbolFlags.insert(KV);
|
||||
return Error::success();
|
||||
} else
|
||||
return AcceptedDefs.takeError();
|
||||
}
|
||||
|
||||
void MaterializationResponsibility::failMaterialization() {
|
||||
@ -809,31 +813,52 @@ void JITDylib::removeGenerator(DefinitionGenerator &G) {
|
||||
});
|
||||
}
|
||||
|
||||
Error JITDylib::defineMaterializing(const SymbolFlagsMap &SymbolFlags) {
|
||||
return ES.runSessionLocked([&]() -> Error {
|
||||
Expected<SymbolFlagsMap>
|
||||
JITDylib::defineMaterializing(SymbolFlagsMap SymbolFlags) {
|
||||
|
||||
return ES.runSessionLocked([&]() -> Expected<SymbolFlagsMap> {
|
||||
std::vector<SymbolTable::iterator> AddedSyms;
|
||||
std::vector<SymbolFlagsMap::iterator> RejectedWeakDefs;
|
||||
|
||||
for (auto &KV : SymbolFlags) {
|
||||
SymbolTable::iterator EntryItr;
|
||||
bool Added;
|
||||
for (auto SFItr = SymbolFlags.begin(), SFEnd = SymbolFlags.end();
|
||||
SFItr != SFEnd; ++SFItr) {
|
||||
|
||||
std::tie(EntryItr, Added) =
|
||||
Symbols.insert(std::make_pair(KV.first, SymbolTableEntry(KV.second)));
|
||||
auto &Name = SFItr->first;
|
||||
auto &Flags = SFItr->second;
|
||||
|
||||
if (Added) {
|
||||
AddedSyms.push_back(EntryItr);
|
||||
EntryItr->second.setState(SymbolState::Materializing);
|
||||
} else {
|
||||
// Remove any symbols already added.
|
||||
for (auto &SI : AddedSyms)
|
||||
Symbols.erase(SI);
|
||||
auto EntryItr = Symbols.find(Name);
|
||||
|
||||
// FIXME: Return all duplicates.
|
||||
return make_error<DuplicateDefinition>(*KV.first);
|
||||
}
|
||||
// If the entry already exists...
|
||||
if (EntryItr != Symbols.end()) {
|
||||
|
||||
// If this is a strong definition then error out.
|
||||
if (!Flags.isWeak()) {
|
||||
// Remove any symbols already added.
|
||||
for (auto &SI : AddedSyms)
|
||||
Symbols.erase(SI);
|
||||
|
||||
// FIXME: Return all duplicates.
|
||||
return make_error<DuplicateDefinition>(*Name);
|
||||
}
|
||||
|
||||
// Otherwise just make a note to discard this symbol after the loop.
|
||||
RejectedWeakDefs.push_back(SFItr);
|
||||
continue;
|
||||
} else
|
||||
EntryItr =
|
||||
Symbols.insert(std::make_pair(Name, SymbolTableEntry(Flags))).first;
|
||||
|
||||
AddedSyms.push_back(EntryItr);
|
||||
EntryItr->second.setState(SymbolState::Materializing);
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
// Remove any rejected weak definitions from the SymbolFlags map.
|
||||
while (!RejectedWeakDefs.empty()) {
|
||||
SymbolFlags.erase(RejectedWeakDefs.back());
|
||||
RejectedWeakDefs.pop_back();
|
||||
}
|
||||
|
||||
return SymbolFlags;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,14 @@
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
IRCompileLayer::IRCompiler::~IRCompiler() {}
|
||||
|
||||
IRCompileLayer::IRCompileLayer(ExecutionSession &ES, ObjectLayer &BaseLayer,
|
||||
CompileFunction Compile)
|
||||
: IRLayer(ES), BaseLayer(BaseLayer), Compile(std::move(Compile)) {}
|
||||
std::unique_ptr<IRCompiler> Compile)
|
||||
: IRLayer(ES, ManglingOpts), BaseLayer(BaseLayer),
|
||||
Compile(std::move(Compile)) {
|
||||
ManglingOpts = &this->Compile->getManglingOptions();
|
||||
}
|
||||
|
||||
void IRCompileLayer::setNotifyCompiled(NotifyCompiledFunction NotifyCompiled) {
|
||||
std::lock_guard<std::mutex> Lock(IRLayerMutex);
|
||||
@ -24,7 +29,7 @@ void IRCompileLayer::emit(MaterializationResponsibility R,
|
||||
ThreadSafeModule TSM) {
|
||||
assert(TSM && "Module must not be null");
|
||||
|
||||
if (auto Obj = TSM.withModuleDo(Compile)) {
|
||||
if (auto Obj = TSM.withModuleDo(*Compile)) {
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(IRLayerMutex);
|
||||
if (NotifyCompiled)
|
||||
|
@ -12,10 +12,10 @@
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
IRTransformLayer::IRTransformLayer(ExecutionSession &ES,
|
||||
IRLayer &BaseLayer,
|
||||
TransformFunction Transform)
|
||||
: IRLayer(ES), BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
|
||||
IRTransformLayer::IRTransformLayer(ExecutionSession &ES, IRLayer &BaseLayer,
|
||||
TransformFunction Transform)
|
||||
: IRLayer(ES, BaseLayer.getManglingOptions()), BaseLayer(BaseLayer),
|
||||
Transform(std::move(Transform)) {}
|
||||
|
||||
void IRTransformLayer::emit(MaterializationResponsibility R,
|
||||
ThreadSafeModule TSM) {
|
||||
|
@ -96,8 +96,10 @@ LLJIT::createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES) {
|
||||
auto ObjLinkingLayer =
|
||||
std::make_unique<RTDyldObjectLinkingLayer>(ES, std::move(GetMemMgr));
|
||||
|
||||
if (S.JTMB->getTargetTriple().isOSBinFormatCOFF())
|
||||
if (S.JTMB->getTargetTriple().isOSBinFormatCOFF()) {
|
||||
ObjLinkingLayer->setOverrideObjectFlagsWithResponsibilityFlags(true);
|
||||
ObjLinkingLayer->setAutoClaimResponsibilityForObjectSymbols(true);
|
||||
}
|
||||
|
||||
// FIXME: Explicit conversion to std::unique_ptr<ObjectLayer> added to silence
|
||||
// errors from some GCC / libstdc++ bots. Remove this conversion (i.e.
|
||||
@ -105,7 +107,7 @@ LLJIT::createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES) {
|
||||
return std::unique_ptr<ObjectLayer>(std::move(ObjLinkingLayer));
|
||||
}
|
||||
|
||||
Expected<IRCompileLayer::CompileFunction>
|
||||
Expected<std::unique_ptr<IRCompileLayer::IRCompiler>>
|
||||
LLJIT::createCompileFunction(LLJITBuilderState &S,
|
||||
JITTargetMachineBuilder JTMB) {
|
||||
|
||||
@ -116,13 +118,13 @@ LLJIT::createCompileFunction(LLJITBuilderState &S,
|
||||
// Otherwise default to creating a SimpleCompiler, or ConcurrentIRCompiler,
|
||||
// depending on the number of threads requested.
|
||||
if (S.NumCompileThreads > 0)
|
||||
return ConcurrentIRCompiler(std::move(JTMB));
|
||||
return std::make_unique<ConcurrentIRCompiler>(std::move(JTMB));
|
||||
|
||||
auto TM = JTMB.createTargetMachine();
|
||||
if (!TM)
|
||||
return TM.takeError();
|
||||
|
||||
return TMOwningSimpleCompiler(std::move(*TM));
|
||||
return std::make_unique<TMOwningSimpleCompiler>(std::move(*TM));
|
||||
}
|
||||
|
||||
LLJIT::LLJIT(LLJITBuilderState &S, Error &Err)
|
||||
|
@ -7,6 +7,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Layer.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
|
||||
@ -15,15 +16,15 @@
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
IRLayer::IRLayer(ExecutionSession &ES) : ES(ES) {}
|
||||
IRLayer::~IRLayer() {}
|
||||
|
||||
Error IRLayer::add(JITDylib &JD, ThreadSafeModule TSM, VModuleKey K) {
|
||||
return JD.define(std::make_unique<BasicIRLayerMaterializationUnit>(
|
||||
*this, std::move(K), std::move(TSM)));
|
||||
*this, *getManglingOptions(), std::move(TSM), std::move(K)));
|
||||
}
|
||||
|
||||
IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES,
|
||||
const ManglingOptions &MO,
|
||||
ThreadSafeModule TSM, VModuleKey K)
|
||||
: MaterializationUnit(SymbolFlagsMap(), std::move(K)), TSM(std::move(TSM)) {
|
||||
|
||||
@ -32,12 +33,44 @@ IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES,
|
||||
MangleAndInterner Mangle(ES, this->TSM.getModuleUnlocked()->getDataLayout());
|
||||
this->TSM.withModuleDo([&](Module &M) {
|
||||
for (auto &G : M.global_values()) {
|
||||
if (G.hasName() && !G.isDeclaration() && !G.hasLocalLinkage() &&
|
||||
!G.hasAvailableExternallyLinkage() && !G.hasAppendingLinkage()) {
|
||||
auto MangledName = Mangle(G.getName());
|
||||
SymbolFlags[MangledName] = JITSymbolFlags::fromGlobalValue(G);
|
||||
SymbolToDefinition[MangledName] = &G;
|
||||
// Skip globals that don't generate symbols.
|
||||
if (!G.hasName() || G.isDeclaration() || G.hasLocalLinkage() ||
|
||||
G.hasAvailableExternallyLinkage() || G.hasAppendingLinkage())
|
||||
continue;
|
||||
|
||||
// thread locals generate different symbols depending on whether or not
|
||||
// emulated TLS is enabled.
|
||||
if (G.isThreadLocal() && MO.EmulatedTLS) {
|
||||
auto &GV = cast<GlobalVariable>(G);
|
||||
|
||||
auto Flags = JITSymbolFlags::fromGlobalValue(GV);
|
||||
|
||||
auto EmuTLSV = Mangle(("__emutls_v." + GV.getName()).str());
|
||||
SymbolFlags[EmuTLSV] = Flags;
|
||||
SymbolToDefinition[EmuTLSV] = &GV;
|
||||
|
||||
// If this GV has a non-zero initializer we'll need to emit an
|
||||
// __emutls.t symbol too.
|
||||
if (GV.hasInitializer()) {
|
||||
const auto *InitVal = GV.getInitializer();
|
||||
|
||||
// Skip zero-initializers.
|
||||
if (isa<ConstantAggregateZero>(InitVal))
|
||||
continue;
|
||||
const auto *InitIntValue = dyn_cast<ConstantInt>(InitVal);
|
||||
if (InitIntValue && InitIntValue->isZero())
|
||||
continue;
|
||||
|
||||
auto EmuTLST = Mangle(("__emutls_t." + GV.getName()).str());
|
||||
SymbolFlags[EmuTLST] = Flags;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise we just need a normal linker mangling.
|
||||
auto MangledName = Mangle(G.getName());
|
||||
SymbolFlags[MangledName] = JITSymbolFlags::fromGlobalValue(G);
|
||||
SymbolToDefinition[MangledName] = &G;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -72,8 +105,8 @@ void IRMaterializationUnit::discard(const JITDylib &JD,
|
||||
}
|
||||
|
||||
BasicIRLayerMaterializationUnit::BasicIRLayerMaterializationUnit(
|
||||
IRLayer &L, VModuleKey K, ThreadSafeModule TSM)
|
||||
: IRMaterializationUnit(L.getExecutionSession(), std::move(TSM),
|
||||
IRLayer &L, const ManglingOptions &MO, ThreadSafeModule TSM, VModuleKey K)
|
||||
: IRMaterializationUnit(L.getExecutionSession(), MO, std::move(TSM),
|
||||
std::move(K)),
|
||||
L(L), K(std::move(K)) {}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -160,6 +161,39 @@ Error RTDyldObjectLinkingLayer::onObjLoad(
|
||||
std::set<StringRef> &InternalSymbols) {
|
||||
SymbolFlagsMap ExtraSymbolsToClaim;
|
||||
SymbolMap Symbols;
|
||||
|
||||
// Hack to support COFF constant pool comdats introduced during compilation:
|
||||
// (See http://llvm.org/PR40074)
|
||||
if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(&Obj)) {
|
||||
auto &ES = getExecutionSession();
|
||||
|
||||
// For all resolved symbols that are not already in the responsibilty set:
|
||||
// check whether the symbol is in a comdat section and if so mark it as
|
||||
// weak.
|
||||
for (auto &Sym : COFFObj->symbols()) {
|
||||
if (Sym.getFlags() & object::BasicSymbolRef::SF_Undefined)
|
||||
continue;
|
||||
auto Name = Sym.getName();
|
||||
if (!Name)
|
||||
return Name.takeError();
|
||||
auto I = Resolved.find(*Name);
|
||||
|
||||
// Skip unresolved symbols, internal symbols, and symbols that are
|
||||
// already in the responsibility set.
|
||||
if (I == Resolved.end() || InternalSymbols.count(*Name) ||
|
||||
R.getSymbols().count(ES.intern(*Name)))
|
||||
continue;
|
||||
auto Sec = Sym.getSection();
|
||||
if (!Sec)
|
||||
return Sec.takeError();
|
||||
if (*Sec == COFFObj->section_end())
|
||||
continue;
|
||||
auto &COFFSec = *COFFObj->getCOFFSection(**Sec);
|
||||
if (COFFSec.Characteristics & COFF::IMAGE_SCN_LNK_COMDAT)
|
||||
I->second.setFlags(I->second.getFlags() | JITSymbolFlags::Weak);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &KV : Resolved) {
|
||||
// Scan the symbols and add them to the Symbols map for resolution.
|
||||
|
||||
@ -184,10 +218,17 @@ Error RTDyldObjectLinkingLayer::onObjLoad(
|
||||
Symbols[InternedName] = JITEvaluatedSymbol(KV.second.getAddress(), Flags);
|
||||
}
|
||||
|
||||
if (!ExtraSymbolsToClaim.empty())
|
||||
if (!ExtraSymbolsToClaim.empty()) {
|
||||
if (auto Err = R.defineMaterializing(ExtraSymbolsToClaim))
|
||||
return Err;
|
||||
|
||||
// If we claimed responsibility for any weak symbols but were rejected then
|
||||
// we need to remove them from the resolved set.
|
||||
for (auto &KV : ExtraSymbolsToClaim)
|
||||
if (KV.second.isWeak() && !R.getSymbols().count(KV.first))
|
||||
Symbols.erase(KV.first);
|
||||
}
|
||||
|
||||
if (auto Err = R.notifyResolved(Symbols)) {
|
||||
R.failMaterialization();
|
||||
return Err;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user