diff options
Diffstat (limited to 'contrib/llvm/tools')
203 files changed, 6116 insertions, 4436 deletions
diff --git a/contrib/llvm/tools/clang/include/clang-c/Index.h b/contrib/llvm/tools/clang/include/clang-c/Index.h index 9acc9b75bffb..c50ac1b6d248 100644 --- a/contrib/llvm/tools/clang/include/clang-c/Index.h +++ b/contrib/llvm/tools/clang/include/clang-c/Index.h @@ -32,7 +32,7 @@ * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. */ #define CINDEX_VERSION_MAJOR 0 -#define CINDEX_VERSION_MINOR 37 +#define CINDEX_VERSION_MINOR 38 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 10000) \ @@ -81,6 +81,12 @@ extern "C" { typedef void *CXIndex; /** + * \brief An opaque type representing target information for a given translation + * unit. + */ +typedef struct CXTargetInfoImpl *CXTargetInfo; + +/** * \brief A single translation unit, which resides in an index. */ typedef struct CXTranslationUnitImpl *CXTranslationUnit; @@ -1553,6 +1559,36 @@ CINDEX_LINKAGE CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU CINDEX_LINKAGE void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage); /** + * \brief Get target information for this translation unit. + * + * The CXTargetInfo object cannot outlive the CXTranslationUnit object. + */ +CINDEX_LINKAGE CXTargetInfo +clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit); + +/** + * \brief Destroy the CXTargetInfo object. + */ +CINDEX_LINKAGE void +clang_TargetInfo_dispose(CXTargetInfo Info); + +/** + * \brief Get the normalized target triple as a string. + * + * Returns the empty string in case of any error. + */ +CINDEX_LINKAGE CXString +clang_TargetInfo_getTriple(CXTargetInfo Info); + +/** + * \brief Get the pointer width of the target in bits. + * + * Returns -1 in case of error. + */ +CINDEX_LINKAGE int +clang_TargetInfo_getPointerWidth(CXTargetInfo Info); + +/** * @} */ @@ -3975,8 +4011,8 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor); CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C); /** - * \brief Given a cursor pointing to an Objective-C message, returns the CXType - * of the receiver. + * \brief Given a cursor pointing to an Objective-C message or property + * reference, or C++ method call, returns the CXType of the receiver. */ CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C); diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTStructuralEquivalence.h b/contrib/llvm/tools/clang/include/clang/AST/ASTStructuralEquivalence.h new file mode 100644 index 000000000000..770bb5763fbd --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/ASTStructuralEquivalence.h @@ -0,0 +1,101 @@ +//===--- ASTStructuralEquivalence.h - ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the StructuralEquivalenceContext class which checks for +// structural equivalence between types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H +#define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" +#include <deque> + +namespace clang { + +class ASTContext; +class Decl; +class DiagnosticBuilder; +class QualType; +class RecordDecl; +class SourceLocation; + +struct StructuralEquivalenceContext { + /// AST contexts for which we are checking structural equivalence. + ASTContext &FromCtx, &ToCtx; + + /// The set of "tentative" equivalences between two canonical + /// declarations, mapping from a declaration in the first context to the + /// declaration in the second context that we believe to be equivalent. + llvm::DenseMap<Decl *, Decl *> TentativeEquivalences; + + /// Queue of declarations in the first context whose equivalence + /// with a declaration in the second context still needs to be verified. + std::deque<Decl *> DeclsToCheck; + + /// Declaration (from, to) pairs that are known not to be equivalent + /// (which we have already complained about). + llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls; + + /// Whether we're being strict about the spelling of types when + /// unifying two types. + bool StrictTypeSpelling; + + /// Whether warn or error on tag type mismatches. + bool ErrorOnTagTypeMismatch; + + /// Whether to complain about failures. + bool Complain; + + /// \c true if the last diagnostic came from ToCtx. + bool LastDiagFromC2; + + StructuralEquivalenceContext( + ASTContext &FromCtx, ASTContext &ToCtx, + llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls, + bool StrictTypeSpelling = false, bool Complain = true) + : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls), + StrictTypeSpelling(StrictTypeSpelling), Complain(Complain), + LastDiagFromC2(false) {} + + DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID); + DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID); + + /// Determine whether the two declarations are structurally + /// equivalent. + bool IsStructurallyEquivalent(Decl *D1, Decl *D2); + + /// Determine whether the two types are structurally equivalent. + bool IsStructurallyEquivalent(QualType T1, QualType T2); + + /// Find the index of the given anonymous struct/union within its + /// context. + /// + /// \returns Returns the index of this anonymous struct/union in its context, + /// including the next assigned index (if none of them match). Returns an + /// empty option if the context is not a record, i.e.. if the anonymous + /// struct/union is at namespace or block scope. + /// + /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It + /// probably makes more sense in some other common place then here. + static llvm::Optional<unsigned> + findUntaggedStructOrUnionIndex(RecordDecl *Anon); + +private: + /// Finish checking all of the structural equivalences. + /// + /// \returns true if an error occurred, false otherwise. + bool Finish(); +}; +} // namespace clang + +#endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h index c88cb6a8fd1e..15ac11a5a777 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h @@ -616,6 +616,14 @@ public: getAvailability(std::string *Message = nullptr, VersionTuple EnclosingVersion = VersionTuple()) const; + /// \brief Retrieve the version of the target platform in which this + /// declaration was introduced. + /// + /// \returns An empty version tuple if this declaration has no 'introduced' + /// availability attributes, or the version tuple that's specified in the + /// attribute otherwise. + VersionTuple getVersionIntroduced() const; + /// \brief Determine whether this declaration is marked 'deprecated'. /// /// \param Message If non-NULL and the declaration is deprecated, diff --git a/contrib/llvm/tools/clang/include/clang/AST/Type.h b/contrib/llvm/tools/clang/include/clang/AST/Type.h index bd30aad10f27..b1c2503c32e3 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/Type.h +++ b/contrib/llvm/tools/clang/include/clang/AST/Type.h @@ -1396,7 +1396,7 @@ protected: /// Extra information which affects how the function is called, like /// regparm and the calling convention. - unsigned ExtInfo : 10; + unsigned ExtInfo : 11; /// Used only by FunctionProtoType, put here to pack with the /// other bitfields. @@ -2941,19 +2941,23 @@ class FunctionType : public Type { // * AST read and write // * Codegen class ExtInfo { - // Feel free to rearrange or add bits, but if you go over 10, + // Feel free to rearrange or add bits, but if you go over 11, // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. - // | CC |noreturn|produces|regparm| - // |0 .. 4| 5 | 6 | 7 .. 9| + // | CC |noreturn|produces|nocallersavedregs|regparm| + // |0 .. 4| 5 | 6 | 7 |8 .. 10| // // regparm is either 0 (no regparm attribute) or the regparm value+1. enum { CallConvMask = 0x1F }; enum { NoReturnMask = 0x20 }; enum { ProducesResultMask = 0x40 }; - enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask), - RegParmOffset = 7 }; // Assumed to be the last field + enum { NoCallerSavedRegsMask = 0x80 }; + enum { + RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask | + NoCallerSavedRegsMask), + RegParmOffset = 8 + }; // Assumed to be the last field uint16_t Bits; @@ -2964,13 +2968,13 @@ class FunctionType : public Type { public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). - ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, - bool producesResult) { - assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); - Bits = ((unsigned) cc) | - (noReturn ? NoReturnMask : 0) | - (producesResult ? ProducesResultMask : 0) | - (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); + ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, + bool producesResult, bool noCallerSavedRegs) { + assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); + Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | + (producesResult ? ProducesResultMask : 0) | + (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | + (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); } // Constructor with all defaults. Use when for example creating a @@ -2983,6 +2987,7 @@ class FunctionType : public Type { bool getNoReturn() const { return Bits & NoReturnMask; } bool getProducesResult() const { return Bits & ProducesResultMask; } + bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; } bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } unsigned getRegParm() const { unsigned RegParm = Bits >> RegParmOffset; @@ -3016,6 +3021,13 @@ class FunctionType : public Type { return ExtInfo(Bits & ~ProducesResultMask); } + ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const { + if (noCallerSavedRegs) + return ExtInfo(Bits | NoCallerSavedRegsMask); + else + return ExtInfo(Bits & ~NoCallerSavedRegsMask); + } + ExtInfo withRegParm(unsigned RegParm) const { assert(RegParm < 7 && "Invalid regparm value"); return ExtInfo((Bits & ~RegParmMask) | diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Attr.td b/contrib/llvm/tools/clang/include/clang/Basic/Attr.td index 44893fbd036c..04a948a6c46e 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Attr.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/Attr.td @@ -1931,6 +1931,12 @@ def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> { let Documentation = [AnyX86InterruptDocs]; } +def AnyX86NoCallerSavedRegisters : InheritableAttr, + TargetSpecificAttr<TargetAnyX86> { + let Spellings = [GCC<"no_caller_saved_registers">]; + let Documentation = [AnyX86NoCallerSavedRegistersDocs]; +} + def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> { let Spellings = [GNU<"force_align_arg_pointer">]; // Technically, this appertains to a FunctionDecl, but the target-specific diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td b/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td index 71cfe36a8fa4..be2a91515ae8 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td @@ -2657,6 +2657,40 @@ hardware design, touch the red zone. }]; } +def AnyX86NoCallerSavedRegistersDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use this attribute to indicate that the specified function has no +caller-saved registers. That is, all registers are callee-saved except for +registers used for passing parameters to the function or returning parameters +from the function. +The compiler saves and restores any modified registers that were not used for +passing or returning arguments to the function. + +The user can call functions specified with the 'no_caller_saved_registers' +attribute from an interrupt handler without saving and restoring all +call-clobbered registers. + +Note that 'no_caller_saved_registers' attribute is not a calling convention. +In fact, it only overrides the decision of which registers should be saved by +the caller, but not how the parameters are passed from the caller to the callee. + +For example: + + .. code-block:: c + + __attribute__ ((no_caller_saved_registers, fastcall)) + void f (int arg1, int arg2) { + ... + } + + In this case parameters 'arg1' and 'arg2' will be passed in registers. + In this case, on 32-bit x86 targets, the function 'f' will use ECX and EDX as + register parameters. However, it will not assume any scratch registers and + should save and restore any modified registers except for ECX and EDX. + }]; +} + def SwiftCallDocs : Documentation { let Category = DocCatVariable; let Content = [{ diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h index a8e11bcb8927..22cded21c12d 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h @@ -178,12 +178,7 @@ public: private: unsigned char AllExtensionsSilenced; // Used by __extension__ - bool IgnoreAllWarnings; // Ignore all warnings: -w - bool WarningsAsErrors; // Treat warnings like errors. - bool EnableAllWarnings; // Enable all warnings. - bool ErrorsAsFatal; // Treat errors like fatal errors. - bool FatalsAsError; // Treat fatal errors like errors. - bool SuppressSystemWarnings; // Suppress warnings in system headers. + bool SuppressAfterFatalError; // Suppress diagnostics after a fatal error? bool SuppressAllDiagnostics; // Suppress all diagnostics. bool ElideType; // Elide common types of templates. bool PrintTemplateTree; // Print a tree when comparing templates. @@ -194,7 +189,6 @@ private: // 0 -> no limit. unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation // backtrace stack, 0 -> no limit. - diag::Severity ExtBehavior; // Map extensions to warnings or errors? IntrusiveRefCntPtr<DiagnosticIDs> Diags; IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; DiagnosticConsumer *Client; @@ -216,6 +210,19 @@ private: llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap; public: + // "Global" configuration state that can actually vary between modules. + unsigned IgnoreAllWarnings : 1; // Ignore all warnings: -w + unsigned EnableAllWarnings : 1; // Enable all warnings. + unsigned WarningsAsErrors : 1; // Treat warnings like errors. + unsigned ErrorsAsFatal : 1; // Treat errors like fatal errors. + unsigned SuppressSystemWarnings : 1; // Suppress warnings in system headers. + diag::Severity ExtBehavior; // Map extensions to warnings or errors? + + DiagState() + : IgnoreAllWarnings(false), EnableAllWarnings(false), + WarningsAsErrors(false), ErrorsAsFatal(false), + SuppressSystemWarnings(false), ExtBehavior(diag::Severity::Ignored) {} + typedef llvm::DenseMap<unsigned, DiagnosticMapping>::iterator iterator; typedef llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator const_iterator; @@ -493,33 +500,47 @@ public: /// \brief When set to true, any unmapped warnings are ignored. /// /// If this and WarningsAsErrors are both set, then this one wins. - void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } - bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; } + void setIgnoreAllWarnings(bool Val) { + GetCurDiagState()->IgnoreAllWarnings = Val; + } + bool getIgnoreAllWarnings() const { + return GetCurDiagState()->IgnoreAllWarnings; + } /// \brief When set to true, any unmapped ignored warnings are no longer /// ignored. /// /// If this and IgnoreAllWarnings are both set, then that one wins. - void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; } - bool getEnableAllWarnings() const { return EnableAllWarnings; } + void setEnableAllWarnings(bool Val) { + GetCurDiagState()->EnableAllWarnings = Val; + } + bool getEnableAllWarnings() const { + return GetCurDiagState()->EnableAllWarnings; + } /// \brief When set to true, any warnings reported are issued as errors. - void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; } - bool getWarningsAsErrors() const { return WarningsAsErrors; } + void setWarningsAsErrors(bool Val) { + GetCurDiagState()->WarningsAsErrors = Val; + } + bool getWarningsAsErrors() const { + return GetCurDiagState()->WarningsAsErrors; + } /// \brief When set to true, any error reported is made a fatal error. - void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; } - bool getErrorsAsFatal() const { return ErrorsAsFatal; } + void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; } + bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; } - /// \brief When set to true, any fatal error reported is made an error. - /// - /// This setting takes precedence over the setErrorsAsFatal setting above. - void setFatalsAsError(bool Val) { FatalsAsError = Val; } - bool getFatalsAsError() const { return FatalsAsError; } + /// \brief When set to true (the default), suppress further diagnostics after + /// a fatal error. + void setSuppressAfterFatalError(bool Val) { SuppressAfterFatalError = Val; } /// \brief When set to true mask warnings that come from system headers. - void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; } - bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } + void setSuppressSystemWarnings(bool Val) { + GetCurDiagState()->SuppressSystemWarnings = Val; + } + bool getSuppressSystemWarnings() const { + return GetCurDiagState()->SuppressSystemWarnings; + } /// \brief Suppress all diagnostics, to silence the front end when we /// know that we don't want any more diagnostics to be passed along to the @@ -571,11 +592,15 @@ public: } /// \brief Controls whether otherwise-unmapped extension diagnostics are - /// mapped onto ignore/warning/error. + /// mapped onto ignore/warning/error. /// /// This corresponds to the GCC -pedantic and -pedantic-errors option. - void setExtensionHandlingBehavior(diag::Severity H) { ExtBehavior = H; } - diag::Severity getExtensionHandlingBehavior() const { return ExtBehavior; } + void setExtensionHandlingBehavior(diag::Severity H) { + GetCurDiagState()->ExtBehavior = H; + } + diag::Severity getExtensionHandlingBehavior() const { + return GetCurDiagState()->ExtBehavior; + } /// \brief Counter bumped when an __extension__ block is/ encountered. /// diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td index 3980805ef9bc..3833f0f28f05 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -233,7 +233,9 @@ def note_drv_t_option_is_global : Note< "The last /TC or /TP option takes precedence over earlier instances">; def note_drv_address_sanitizer_debug_runtime : Note< "AddressSanitizer doesn't support linking with debug runtime libraries yet">; -def note_drv_use_standard : Note<"use '%0' for '%1' standard">; +def note_drv_use_standard : Note<"use '%0'" + "%select{| or '%3'|, '%3', or '%4'|, '%3', '%4', or '%5'}2 " + "for '%1' standard">; def err_analyzer_config_no_value : Error< "analyzer-config option '%0' has a key but no value">; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td index 4cde1c81fd4d..05e03fab40fa 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td @@ -890,6 +890,7 @@ def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">; def BackendOptimizationFailure : DiagGroup<"pass-failed">; // Instrumentation based profiling warnings. +def ProfileInstrMissing : DiagGroup<"profile-instr-missing">; def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">; def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h index f5f70cb5e7d3..7646e33d2366 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h @@ -122,15 +122,21 @@ public: bool wasUpgradedFromWarning() const { return WasUpgradedFromWarning; } void setUpgradedFromWarning(bool Value) { WasUpgradedFromWarning = Value; } - /// Serialize the bits that aren't based on context. - unsigned serializeBits() const { - return (WasUpgradedFromWarning << 3) | Severity; + /// Serialize this mapping as a raw integer. + unsigned serialize() const { + return (IsUser << 7) | (IsPragma << 6) | (HasNoWarningAsError << 5) | + (HasNoErrorAsFatal << 4) | (WasUpgradedFromWarning << 3) | Severity; } - static diag::Severity deserializeSeverity(unsigned Bits) { - return (diag::Severity)(Bits & 0x7); - } - static bool deserializeUpgradedFromWarning(unsigned Bits) { - return Bits >> 3; + /// Deserialize a mapping. + static DiagnosticMapping deserialize(unsigned Bits) { + DiagnosticMapping Result; + Result.IsUser = (Bits >> 7) & 1; + Result.IsPragma = (Bits >> 6) & 1; + Result.HasNoWarningAsError = (Bits >> 5) & 1; + Result.HasNoErrorAsFatal = (Bits >> 4) & 1; + Result.WasUpgradedFromWarning = (Bits >> 3) & 1; + Result.Severity = Bits & 0x7; + return Result; } }; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td index cf33d5fba3d7..cd284e94303b 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -475,6 +475,8 @@ def warn_pragma_pop_macro_no_push : Warning< def warn_pragma_message : Warning<"%0">, InGroup<PoundPragmaMessage>, DefaultWarnNoWerror; def err_pragma_message : Error<"%0">; +def err_pragma_module_import_expected_module_name : Error< + "expected %select{identifier in|'.' or end of directive after}0 module name">; def warn_pragma_ignored : Warning<"unknown pragma ignored">, InGroup<UnknownPragmas>, DefaultIgnore; def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, @@ -503,7 +505,7 @@ def warn_pragma_diagnostic_invalid_token : InGroup<UnknownPragmas>; def warn_pragma_diagnostic_unknown_warning : ExtWarn<"unknown warning group '%0', ignored">, - InGroup<UnknownPragmas>; + InGroup<UnknownWarningOption>; // - #pragma __debug def warn_pragma_debug_unexpected_command : Warning< "unexpected debug command '%0'">, InGroup<IgnoredPragmas>; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index b5fed1f218b6..6a3a2124a5ff 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1180,6 +1180,10 @@ def err_objc_kindof_nonobject : Error< def err_objc_kindof_wrong_position : Error< "'__kindof' type specifier must precede the declarator">; +def err_objc_method_unsupported_param_ret_type : Error< + "%0 %select{parameter|return}1 type is unsupported; " + "support for vector types for this target is introduced in %2">; + // C++ declarations def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; @@ -2816,9 +2820,9 @@ def warn_cconv_structors : Warning< def err_regparm_mismatch : Error<"function declared with regparm(%0) " "attribute was previously declared " "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">; -def err_returns_retained_mismatch : Error< - "function declared with the ns_returns_retained attribute " - "was previously declared without the ns_returns_retained attribute">; +def err_function_attribute_mismatch : Error< + "function declared with %0 attribute " + "was previously declared without the %0 attribute">; def err_objc_precise_lifetime_bad_type : Error< "objc_precise_lifetime only applies to retainable types; type here is %0">; def warn_objc_precise_lifetime_meaningless : Error< @@ -8041,7 +8045,7 @@ def err_64_bit_builtin_32_bit_tgt : Error< "this builtin is only available on 64-bit targets">; def err_ppc_builtin_only_on_pwr7 : Error< "this builtin is only valid on POWER7 or later CPUs">; -def err_x86_builtin_32_bit_tgt : Error< +def err_x86_builtin_64_only : Error< "this builtin is only available on x86-64 targets">; def err_x86_builtin_invalid_rounding : Error< "invalid rounding argument">; @@ -8931,8 +8935,13 @@ def warn_not_a_doxygen_trailing_member_comment : Warning< let CategoryName = "Instrumentation Issue" in { def warn_profile_data_out_of_date : Warning< "profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1" - " no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">, + " mismatched data that will be ignored">, InGroup<ProfileInstrOutOfDate>; +def warn_profile_data_missing : Warning< + "profile data may be incomplete: of %0 function%s0, %1 %plural{1:has|:have}1" + " no data">, + InGroup<ProfileInstrMissing>, + DefaultIgnore; def warn_profile_data_unprofiled : Warning< "no profile data available for file \"%0\"">, InGroup<ProfileInstrUnprofiled>; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td index 4af4c18ced33..35e2f67e24b6 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -146,7 +146,10 @@ def err_module_odr_violation_mismatch_decl_diff : Error< "method %4 is %select{not static|static}5|" "method %4 is %select{not volatile|volatile}5|" "method %4 is %select{not const|const}5|" - "method %4 is %select{not inline|inline}5}3">; + "method %4 is %select{not inline|inline}5|" + "method %4 that has %5 parameter%s5|" + "method %4 with %ordinal5 parameter of type %6%select{| decayed from %8}7|" + "method %4 with %ordinal5 parameter named %6}3">; def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "%select{" @@ -166,7 +169,10 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "method %2 is %select{not static|static}3|" "method %2 is %select{not volatile|volatile}3|" "method %2 is %select{not const|const}3|" - "method %2 is %select{not inline|inline}3}1">; + "method %2 is %select{not inline|inline}3|" + "method %2 that has %3 parameter%s3|" + "method %2 with %ordinal3 parameter of type %4%select{| decayed from %6}5|" + "method %2 with %ordinal3 parameter named %4}1">; def warn_module_uses_date_time : Warning< "%select{precompiled header|module}0 uses __DATE__ or __TIME__">, diff --git a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def index 6ae34a89fe28..60c8a68cd2e9 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def @@ -266,7 +266,8 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan " LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation") -LANGOPT(AllowEditorPlaceholders, 1, 0, "allow editor placeholders in source") +BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0, + "allow editor placeholders in source") #undef LANGOPT #undef COMPATIBLE_LANGOPT diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h b/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h index 2703f299d217..d1f05124d5e5 100644 --- a/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -461,7 +461,7 @@ class CGFunctionInfo final unsigned EffectiveCallingConvention : 8; /// The clang::CallingConv that this was originally created with. - unsigned ASTCallingConvention : 8; + unsigned ASTCallingConvention : 7; /// Whether this is an instance method. unsigned InstanceMethod : 1; @@ -475,6 +475,9 @@ class CGFunctionInfo final /// Whether this function is returns-retained. unsigned ReturnsRetained : 1; + /// Whether this function saved caller registers. + unsigned NoCallerSavedRegs : 1; + /// How many arguments to pass inreg. unsigned HasRegParm : 1; unsigned RegParm : 3; @@ -560,6 +563,9 @@ public: /// is not always reliable for call sites. bool isReturnsRetained() const { return ReturnsRetained; } + /// Whether this function no longer saves caller registers. + bool isNoCallerSavedRegs() const { return NoCallerSavedRegs; } + /// getASTCallingConvention() - Return the AST-specified calling /// convention. CallingConv getASTCallingConvention() const { @@ -583,10 +589,9 @@ public: unsigned getRegParm() const { return RegParm; } FunctionType::ExtInfo getExtInfo() const { - return FunctionType::ExtInfo(isNoReturn(), - getHasRegParm(), getRegParm(), - getASTCallingConvention(), - isReturnsRetained()); + return FunctionType::ExtInfo(isNoReturn(), getHasRegParm(), getRegParm(), + getASTCallingConvention(), isReturnsRetained(), + isNoCallerSavedRegs()); } CanQualType getReturnType() const { return getArgsBuffer()[0].type; } @@ -623,6 +628,7 @@ public: ID.AddBoolean(ChainCall); ID.AddBoolean(NoReturn); ID.AddBoolean(ReturnsRetained); + ID.AddBoolean(NoCallerSavedRegs); ID.AddBoolean(HasRegParm); ID.AddInteger(RegParm); ID.AddInteger(Required.getOpaqueData()); @@ -648,6 +654,7 @@ public: ID.AddBoolean(ChainCall); ID.AddBoolean(info.getNoReturn()); ID.AddBoolean(info.getProducesResult()); + ID.AddBoolean(info.getNoCallerSavedRegs()); ID.AddBoolean(info.getHasRegParm()); ID.AddInteger(info.getRegParm()); ID.AddInteger(required.getOpaqueData()); diff --git a/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td b/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td index 61902653e210..d0d9c679de7a 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td +++ b/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td @@ -61,6 +61,8 @@ def _SLASH_Brepro_ : CLFlag<"Brepro-">, def _SLASH_C : CLFlag<"C">, HelpText<"Don't discard comments when preprocessing">, Alias<C>; def _SLASH_c : CLFlag<"c">, HelpText<"Compile only">, Alias<c>; +def _SLASH_d1reportAllClassLayout : CLFlag<"d1reportAllClassLayout">, + HelpText<"Dump record layout information">, Alias<fdump_record_layouts>; def _SLASH_D : CLJoinedOrSeparate<"D">, HelpText<"Define macro">, MetaVarName<"<macro[=value]>">, Alias<D>; def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias<E>; diff --git a/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h b/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h index b6ec8b8f06e2..b082e4e0a3df 100644 --- a/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h +++ b/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h @@ -65,7 +65,7 @@ public: bool commit(const Commit &commit); - void applyRewrites(EditsReceiver &receiver); + void applyRewrites(EditsReceiver &receiver, bool adjustRemovals = true); void clearRewrites(); StringRef copyString(StringRef str) { return str.copy(StrAlloc); } diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h index 778b40b15df7..cb4498514955 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h @@ -99,8 +99,6 @@ class GenerateModuleAction : public ASTFrontendAction { CreateOutputFile(CompilerInstance &CI, StringRef InFile) = 0; protected: - bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; - std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; @@ -112,20 +110,11 @@ protected: }; class GenerateModuleFromModuleMapAction : public GenerateModuleAction { - clang::Module *Module = nullptr; - const FileEntry *ModuleMapForUniquing = nullptr; - bool IsSystem = false; - private: bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; std::unique_ptr<raw_pwrite_stream> CreateOutputFile(CompilerInstance &CI, StringRef InFile) override; - -public: - GenerateModuleFromModuleMapAction() {} - GenerateModuleFromModuleMapAction(const FileEntry *ModuleMap, bool IsSystem) - : ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem) {} }; class GenerateModuleInterfaceAction : public GenerateModuleAction { diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h index 4fd0f82a3ad2..36c046891b47 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h @@ -23,6 +23,7 @@ class MemoryBuffer; } namespace clang { +class FileEntry; namespace frontend { enum ActionKind { @@ -62,25 +63,65 @@ namespace frontend { }; } -enum InputKind { - IK_None, - IK_Asm, - IK_C, - IK_CXX, - IK_ObjC, - IK_ObjCXX, - IK_PreprocessedC, - IK_PreprocessedCXX, - IK_PreprocessedObjC, - IK_PreprocessedObjCXX, - IK_OpenCL, - IK_CUDA, - IK_PreprocessedCuda, - IK_RenderScript, - IK_AST, - IK_LLVM_IR -}; +/// The kind of a file that we've been handed as an input. +class InputKind { +private: + unsigned Lang : 4; + unsigned Fmt : 3; + unsigned Preprocessed : 1; + +public: + /// The language for the input, used to select and validate the language + /// standard and possible actions. + enum Language { + Unknown, + + /// Assembly: we accept this only so that we can preprocess it. + Asm, + + /// LLVM IR: we accept this so that we can run the optimizer on it, + /// and compile it to assembly or object code. + LLVM_IR, + + ///@{ Languages that the frontend can parse and compile. + C, + CXX, + ObjC, + ObjCXX, + OpenCL, + CUDA, + RenderScript, + ///@} + }; + + /// The input file format. + enum Format { + Source, + ModuleMap, + Precompiled + }; + + constexpr InputKind(Language L = Unknown, Format F = Source, + bool PP = false) + : Lang(L), Fmt(F), Preprocessed(PP) {} + + Language getLanguage() const { return static_cast<Language>(Lang); } + Format getFormat() const { return static_cast<Format>(Fmt); } + bool isPreprocessed() const { return Preprocessed; } + /// Is the input kind fully-unknown? + bool isUnknown() const { return Lang == Unknown && Fmt == Source; } + + /// Is the language of the input some dialect of Objective-C? + bool isObjectiveC() const { return Lang == ObjC || Lang == ObjCXX; } + + InputKind getPreprocessed() const { + return InputKind(getLanguage(), getFormat(), true); + } + InputKind withFormat(Format F) const { + return InputKind(getLanguage(), F, isPreprocessed()); + } +}; /// \brief An input file for the front end. class FrontendInputFile { @@ -96,7 +137,7 @@ class FrontendInputFile { bool IsSystem; public: - FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) { } + FrontendInputFile() : Buffer(nullptr), Kind(), IsSystem(false) { } FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false) : File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { } FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind, @@ -109,13 +150,7 @@ public: bool isEmpty() const { return File.empty() && Buffer == nullptr; } bool isFile() const { return !isBuffer(); } bool isBuffer() const { return Buffer != nullptr; } - bool isPreprocessed() const { - return Kind == IK_PreprocessedC || - Kind == IK_PreprocessedCXX || - Kind == IK_PreprocessedObjC || - Kind == IK_PreprocessedObjCXX || - Kind == IK_PreprocessedCuda; - } + bool isPreprocessed() const { return Kind.isPreprocessed(); } StringRef getFile() const { assert(isFile()); @@ -224,6 +259,10 @@ public: /// The input files and their types. std::vector<FrontendInputFile> Inputs; + /// When the input is a module map, the original module map file from which + /// that map was inferred, if any (for umbrella modules). + std::string OriginalModuleMap; + /// The output file, if any. std::string OutputFile; @@ -299,10 +338,10 @@ public: {} /// getInputKindForExtension - Return the appropriate input kind for a file - /// extension. For example, "c" would return IK_C. + /// extension. For example, "c" would return InputKind::C. /// - /// \return The input kind for the extension, or IK_None if the extension is - /// not recognized. + /// \return The input kind for the extension, or InputKind::Unknown if the + /// extension is not recognized. static InputKind getInputKindForExtension(StringRef Extension); }; diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h index 5ead90f00721..ec32aa8d161f 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_FRONTEND_LANGSTANDARD_H #include "clang/Basic/LLVM.h" +#include "clang/Frontend/FrontendOptions.h" #include "llvm/ADT/StringRef.h" namespace clang { @@ -19,18 +20,17 @@ namespace frontend { enum LangFeatures { LineComment = (1 << 0), - C89 = (1 << 1), - C99 = (1 << 2), - C11 = (1 << 3), - CPlusPlus = (1 << 4), - CPlusPlus11 = (1 << 5), - CPlusPlus14 = (1 << 6), - CPlusPlus1z = (1 << 7), - Digraphs = (1 << 8), - GNUMode = (1 << 9), - HexFloat = (1 << 10), - ImplicitInt = (1 << 11), - OpenCL = (1 << 12) + C99 = (1 << 1), + C11 = (1 << 2), + CPlusPlus = (1 << 3), + CPlusPlus11 = (1 << 4), + CPlusPlus14 = (1 << 5), + CPlusPlus1z = (1 << 6), + Digraphs = (1 << 7), + GNUMode = (1 << 8), + HexFloat = (1 << 9), + ImplicitInt = (1 << 10), + OpenCL = (1 << 11) }; } @@ -39,7 +39,7 @@ enum LangFeatures { /// standard. struct LangStandard { enum Kind { -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ lang_##id, #include "clang/Frontend/LangStandards.def" lang_unspecified @@ -48,6 +48,7 @@ struct LangStandard { const char *ShortName; const char *Description; unsigned Flags; + InputKind::Language Language; public: /// getName - Get the name of this standard. @@ -56,12 +57,12 @@ public: /// getDescription - Get the description of this standard. const char *getDescription() const { return Description; } + /// Get the language that this standard describes. + InputKind::Language getLanguage() const { return Language; } + /// Language supports '//' comments. bool hasLineComments() const { return Flags & frontend::LineComment; } - /// isC89 - Language is a superset of C89. - bool isC89() const { return Flags & frontend::C89; } - /// isC99 - Language is a superset of C99. bool isC99() const { return Flags & frontend::C99; } diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def index 425ac84bf6ff..1d214fd2a2be 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def +++ b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def @@ -11,10 +11,11 @@ #error "LANGSTANDARD must be defined before including this file" #endif -/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES) +/// LANGSTANDARD(IDENT, NAME, LANG, DESC, FEATURES) /// /// \param IDENT - The name of the standard as a C++ identifier. /// \param NAME - The name of the standard. +/// \param LANG - The InputKind::Language for which this is a standard. /// \param DESC - A short description of the standard. /// \param FEATURES - The standard features as flags, these are enums from the /// clang::frontend namespace, which is assumed to be be available. @@ -23,146 +24,126 @@ /// \param IDENT - The name of the standard as a C++ identifier. /// \param ALIAS - The alias of the standard. +/// LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS) +/// Same as LANGSTANDARD_ALIAS, but for a deprecated alias. + #ifndef LANGSTANDARD_ALIAS #define LANGSTANDARD_ALIAS(IDENT, ALIAS) #endif +#ifndef LANGSTANDARD_ALIAS_DEPR +#define LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS) LANGSTANDARD_ALIAS(IDENT, ALIAS) +#endif + // C89-ish modes. LANGSTANDARD(c89, "c89", - "ISO C 1990", - C89 | ImplicitInt) -LANGSTANDARD(c90, "c90", - "ISO C 1990", - C89 | ImplicitInt) -LANGSTANDARD(iso9899_1990, "iso9899:1990", - "ISO C 1990", - C89 | ImplicitInt) + C, "ISO C 1990", + ImplicitInt) +LANGSTANDARD_ALIAS(c89, "c90") +LANGSTANDARD_ALIAS(c89, "iso9899:1990") LANGSTANDARD(c94, "iso9899:199409", - "ISO C 1990 with amendment 1", - C89 | Digraphs | ImplicitInt) + C, "ISO C 1990 with amendment 1", + Digraphs | ImplicitInt) LANGSTANDARD(gnu89, "gnu89", - "ISO C 1990 with GNU extensions", - LineComment | C89 | Digraphs | GNUMode | ImplicitInt) -LANGSTANDARD(gnu90, "gnu90", - "ISO C 1990 with GNU extensions", - LineComment | C89 | Digraphs | GNUMode | ImplicitInt) + C, "ISO C 1990 with GNU extensions", + LineComment | Digraphs | GNUMode | ImplicitInt) +LANGSTANDARD_ALIAS(gnu89, "gnu90") // C99-ish modes LANGSTANDARD(c99, "c99", - "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(c9x, "c9x", - "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_1999, - "iso9899:1999", "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_199x, - "iso9899:199x", "ISO C 1999", + C, "ISO C 1999", LineComment | C99 | Digraphs | HexFloat) +LANGSTANDARD_ALIAS(c99, "iso9899:1999") +LANGSTANDARD_ALIAS_DEPR(c99, "c9x") +LANGSTANDARD_ALIAS_DEPR(c99, "iso9899:199x") LANGSTANDARD(gnu99, "gnu99", - "ISO C 1999 with GNU extensions", - LineComment | C99 | Digraphs | GNUMode | HexFloat) -LANGSTANDARD(gnu9x, "gnu9x", - "ISO C 1999 with GNU extensions", + C, "ISO C 1999 with GNU extensions", LineComment | C99 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD_ALIAS_DEPR(gnu99, "gnu9x") // C11 modes LANGSTANDARD(c11, "c11", - "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(c1x, "c1x", - "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_2011, - "iso9899:2011", "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_201x, - "iso9899:201x", "ISO C 2011", + C, "ISO C 2011", LineComment | C99 | C11 | Digraphs | HexFloat) +LANGSTANDARD_ALIAS(c11, "iso9899:2011") +LANGSTANDARD_ALIAS_DEPR(c11, "c1x") +LANGSTANDARD_ALIAS_DEPR(c11, "iso9899:201x") LANGSTANDARD(gnu11, "gnu11", - "ISO C 2011 with GNU extensions", - LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) -LANGSTANDARD(gnu1x, "gnu1x", - "ISO C 2011 with GNU extensions", + C, "ISO C 2011 with GNU extensions", LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD_ALIAS_DEPR(gnu11, "gnu1x") // C++ modes LANGSTANDARD(cxx98, "c++98", - "ISO C++ 1998 with amendments", - LineComment | CPlusPlus | Digraphs) -LANGSTANDARD(cxx03, "c++03", - "ISO C++ 1998 with amendments", + CXX, "ISO C++ 1998 with amendments", LineComment | CPlusPlus | Digraphs) +LANGSTANDARD_ALIAS(cxx98, "c++03") + LANGSTANDARD(gnucxx98, "gnu++98", - "ISO C++ 1998 with amendments and GNU extensions", + CXX, "ISO C++ 1998 with amendments and GNU extensions", LineComment | CPlusPlus | Digraphs | GNUMode) +LANGSTANDARD_ALIAS(gnucxx98, "gnu++03") -LANGSTANDARD(cxx0x, "c++0x", - "ISO C++ 2011 with amendments", - LineComment | CPlusPlus | CPlusPlus11 | Digraphs) LANGSTANDARD(cxx11, "c++11", - "ISO C++ 2011 with amendments", + CXX, "ISO C++ 2011 with amendments", LineComment | CPlusPlus | CPlusPlus11 | Digraphs) -LANGSTANDARD(gnucxx0x, "gnu++0x", - "ISO C++ 2011 with amendments and GNU extensions", - LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) -LANGSTANDARD(gnucxx11, "gnu++11", +LANGSTANDARD_ALIAS_DEPR(cxx11, "c++0x") + +LANGSTANDARD(gnucxx11, "gnu++11", CXX, "ISO C++ 2011 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) +LANGSTANDARD_ALIAS_DEPR(gnucxx11, "gnu++0x") -LANGSTANDARD(cxx1y, "c++1y", - "ISO C++ 2014 with amendments", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) LANGSTANDARD(cxx14, "c++14", - "ISO C++ 2014 with amendments", + CXX, "ISO C++ 2014 with amendments", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) -LANGSTANDARD(gnucxx1y, "gnu++1y", - "ISO C++ 2014 with amendments and GNU extensions", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | - GNUMode) +LANGSTANDARD_ALIAS_DEPR(cxx14, "c++1y") + LANGSTANDARD(gnucxx14, "gnu++14", - "ISO C++ 2014 with amendments and GNU extensions", + CXX, "ISO C++ 2014 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | GNUMode) +LANGSTANDARD_ALIAS_DEPR(gnucxx14, "gnu++1y") LANGSTANDARD(cxx1z, "c++1z", - "Working draft for ISO C++ 2017", + CXX, "Working draft for ISO C++ 2017", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | Digraphs | HexFloat) + LANGSTANDARD(gnucxx1z, "gnu++1z", - "Working draft for ISO C++ 2017 with GNU extensions", + CXX, "Working draft for ISO C++ 2017 with GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | Digraphs | HexFloat | GNUMode) // OpenCL -LANGSTANDARD(opencl, "cl", - "OpenCL 1.0", +LANGSTANDARD(opencl10, "cl1.0", + OpenCL, "OpenCL 1.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) +LANGSTANDARD_ALIAS_DEPR(opencl10, "cl") + LANGSTANDARD(opencl11, "cl1.1", - "OpenCL 1.1", + OpenCL, "OpenCL 1.1", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD(opencl12, "cl1.2", - "OpenCL 1.2", + OpenCL, "OpenCL 1.2", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD(opencl20, "cl2.0", - "OpenCL 2.0", + OpenCL, "OpenCL 2.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) -LANGSTANDARD_ALIAS(opencl, "CL") -LANGSTANDARD_ALIAS(opencl11, "CL1.1") -LANGSTANDARD_ALIAS(opencl12, "CL1.2") -LANGSTANDARD_ALIAS(opencl20, "CL2.0") +LANGSTANDARD_ALIAS_DEPR(opencl10, "CL") +LANGSTANDARD_ALIAS_DEPR(opencl11, "CL1.1") +LANGSTANDARD_ALIAS_DEPR(opencl12, "CL1.2") +LANGSTANDARD_ALIAS_DEPR(opencl20, "CL2.0") // CUDA -LANGSTANDARD(cuda, "cuda", - "NVIDIA CUDA(tm)", +LANGSTANDARD(cuda, "cuda", CUDA, "NVIDIA CUDA(tm)", LineComment | CPlusPlus | Digraphs) #undef LANGSTANDARD #undef LANGSTANDARD_ALIAS - +#undef LANGSTANDARD_ALIAS_DEPR diff --git a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h index 51983b9ab5d8..64c6f2a03f2b 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h @@ -375,13 +375,16 @@ public: /// \param SuggestedModule If non-null, and the file found is semantically /// part of a known module, this will be set to the module that should /// be imported instead of preprocessing/parsing the file found. + /// + /// \param IsMapped If non-null, and the search involved header maps, set to + /// true. const FileEntry *LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache = false, bool BuildSystemModule = false); + bool *IsMapped, bool SkipCache = false, bool BuildSystemModule = false); /// \brief Look up a subframework for the specified \#include file. /// diff --git a/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h b/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h index 6cc3b0bb26f2..44b7b2e4a474 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h @@ -126,7 +126,7 @@ public: SourceLocation getDefinitionEndLoc() const { return EndLocation; } /// \brief Get length in characters of the macro definition. - unsigned getDefinitionLength(SourceManager &SM) const { + unsigned getDefinitionLength(const SourceManager &SM) const { if (IsDefinitionLengthCached) return DefinitionLength; return getDefinitionLengthSlow(SM); @@ -285,7 +285,7 @@ public: void dump() const; private: - unsigned getDefinitionLengthSlow(SourceManager &SM) const; + unsigned getDefinitionLengthSlow(const SourceManager &SM) const; void setOwningModuleID(unsigned ID) { assert(isFromASTFile()); diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h b/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h index 2d027f314b5f..81c3bd7d14ec 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h @@ -247,10 +247,14 @@ public: } /// \brief Hook called whenever a macro \#undef is seen. + /// \param MacroNameTok The active Token + /// \param MD A MacroDefinition for the named macro. + /// \param Undef New MacroDirective if the macro was defined, null otherwise. /// /// MD is released immediately following this callback. virtual void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { } /// \brief Hook called whenever the 'defined' operator is seen. @@ -439,15 +443,17 @@ public: Second->MacroExpands(MacroNameTok, MD, Range, Args); } - void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override { + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { First->MacroDefined(MacroNameTok, MD); Second->MacroDefined(MacroNameTok, MD); } void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) override { - First->MacroUndefined(MacroNameTok, MD); - Second->MacroUndefined(MacroNameTok, MD); + const MacroDefinition &MD, + const MacroDirective *Undef) override { + First->MacroUndefined(MacroNameTok, MD, Undef); + Second->MacroUndefined(MacroNameTok, MD, Undef); } void Defined(const Token &MacroNameTok, const MacroDefinition &MD, diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h index 826ba33fbb72..fc2c50700400 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h @@ -488,7 +488,8 @@ namespace clang { void MacroExpands(const Token &Id, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override; void MacroDefined(const Token &Id, const MacroDirective *MD) override; - void MacroUndefined(const Token &Id, const MacroDefinition &MD) override; + void MacroUndefined(const Token &Id, const MacroDefinition &MD, + const MacroDirective *Undef) override; void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h index 3efe914daaee..b1a7325c3426 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h @@ -1263,6 +1263,10 @@ public: CachedTokens[CachedLexPos-1] = Tok; } + /// Enter an annotation token into the token stream. + void EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind, + void *AnnotationVal); + /// Update the current token to represent the provided /// identifier, in order to cache an action performed by typo correction. void TypoCorrectToken(const Token &Tok) { @@ -1602,6 +1606,7 @@ private: *Ident_AbnormalTermination; const char *getCurLexerEndPos(); + void diagnoseMissingHeaderInUmbrellaDir(const Module &Mod); public: void PoisonSEHIdentifiers(bool Poison = true); // Borland @@ -1686,7 +1691,7 @@ public: SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache = false); + bool *IsMapped, bool SkipCache = false); /// \brief Get the DirectoryLookup structure used to find the current /// FileEntry, if CurLexer is non-null and if applicable. @@ -1962,6 +1967,7 @@ public: void HandlePragmaPoison(); void HandlePragmaSystemHeader(Token &SysHeaderTok); void HandlePragmaDependency(Token &DependencyTok); + void HandlePragmaModuleImport(Token &Tok); void HandlePragmaPushMacro(Token &Tok); void HandlePragmaPopMacro(Token &Tok); void HandlePragmaIncludeAlias(Token &Tok); diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h index 0f16cb975b2a..eca383bee2f5 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h @@ -1068,6 +1068,12 @@ public: /// same special member, we should act as if it is not yet declared. llvm::SmallSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared; + /// The function definitions which were renamed as part of typo-correction + /// to match their respective declarations. We want to keep track of them + /// to ensure that we don't emit a "redefinition" error if we encounter a + /// correctly named definition after the renamed definition. + llvm::SmallPtrSet<const NamedDecl *, 4> TypoCorrectedFunctionDefinitions; + void ReadMethodPool(Selector Sel); void updateOutOfDateSelector(Selector Sel); @@ -3117,6 +3123,8 @@ public: const PartialDiagnostic &PrevNote, bool ErrorRecovery = true); + void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F); + void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, ArrayRef<Expr *> Args, AssociatedNamespaceSet &AssociatedNamespaces, @@ -3162,6 +3170,7 @@ public: bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD = nullptr); bool CheckNoReturnAttr(const AttributeList &attr); + bool CheckNoCallerSavedRegsAttr(const AttributeList &attr); bool checkStringLiteralArgumentAttr(const AttributeList &Attr, unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation = nullptr); @@ -10059,9 +10068,7 @@ private: bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinVAStartImpl(CallExpr *TheCall); - bool SemaBuiltinVAStart(CallExpr *TheCall); - bool SemaBuiltinMSVAStart(CallExpr *TheCall); + bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStartARM(CallExpr *Call); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); @@ -10151,7 +10158,6 @@ private: void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); void CheckBoolLikeConversion(Expr *E, SourceLocation CC); - void CheckForIntOverflow(Expr *E); void CheckUnsequencedOperations(Expr *E); /// \brief Perform semantic checks on a completed expression. This will either diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h index 8df2bc331b51..0e80e7bc19ba 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h @@ -17,6 +17,7 @@ namespace clang { extern const char * const CoreFoundationObjectiveC; extern const char * const LogicError; extern const char * const MemoryCoreFoundationObjectiveC; + extern const char * const MemoryError; extern const char * const UnixAPI; } } diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp index 241a7246b621..fcc67da1f774 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp @@ -2189,7 +2189,7 @@ static std::string applyEditsToTemp(const FileEntry *FE, Rewriter rewriter(SM, LangOpts); RewritesReceiver Rec(rewriter); - Editor.applyRewrites(Rec); + Editor.applyRewrites(Rec, /*adjustRemovals=*/false); const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID); SmallString<512> NewText; diff --git a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp index 4626052a8acb..3b526a23edd9 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp @@ -7918,6 +7918,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult()) return QualType(); + if (lbaseInfo.getNoCallerSavedRegs() != rbaseInfo.getNoCallerSavedRegs()) + return QualType(); // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); diff --git a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp index 95492825eb9d..4fb6051d6f58 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTImporter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclVisitor.h" @@ -321,1396 +322,12 @@ namespace clang { }; } -using namespace clang; - -//---------------------------------------------------------------------------- -// Structural Equivalence -//---------------------------------------------------------------------------- - -namespace { - struct StructuralEquivalenceContext { - /// \brief AST contexts for which we are checking structural equivalence. - ASTContext &C1, &C2; - - /// \brief The set of "tentative" equivalences between two canonical - /// declarations, mapping from a declaration in the first context to the - /// declaration in the second context that we believe to be equivalent. - llvm::DenseMap<Decl *, Decl *> TentativeEquivalences; - - /// \brief Queue of declarations in the first context whose equivalence - /// with a declaration in the second context still needs to be verified. - std::deque<Decl *> DeclsToCheck; - - /// \brief Declaration (from, to) pairs that are known not to be equivalent - /// (which we have already complained about). - llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls; - - /// \brief Whether we're being strict about the spelling of types when - /// unifying two types. - bool StrictTypeSpelling; - - /// \brief Whether to complain about failures. - bool Complain; - - /// \brief \c true if the last diagnostic came from C2. - bool LastDiagFromC2; - - StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2, - llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls, - bool StrictTypeSpelling = false, - bool Complain = true) - : C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls), - StrictTypeSpelling(StrictTypeSpelling), Complain(Complain), - LastDiagFromC2(false) {} - - /// \brief Determine whether the two declarations are structurally - /// equivalent. - bool IsStructurallyEquivalent(Decl *D1, Decl *D2); - - /// \brief Determine whether the two types are structurally equivalent. - bool IsStructurallyEquivalent(QualType T1, QualType T2); - - private: - /// \brief Finish checking all of the structural equivalences. - /// - /// \returns true if an error occurred, false otherwise. - bool Finish(); - - public: - DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { - assert(Complain && "Not allowed to complain"); - if (LastDiagFromC2) - C1.getDiagnostics().notePriorDiagnosticFrom(C2.getDiagnostics()); - LastDiagFromC2 = false; - return C1.getDiagnostics().Report(Loc, DiagID); - } - - DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { - assert(Complain && "Not allowed to complain"); - if (!LastDiagFromC2) - C2.getDiagnostics().notePriorDiagnosticFrom(C1.getDiagnostics()); - LastDiagFromC2 = true; - return C2.getDiagnostics().Report(Loc, DiagID); - } - }; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - QualType T1, QualType T2); -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - Decl *D1, Decl *D2); -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - const TemplateArgument &Arg1, - const TemplateArgument &Arg2); - -/// \brief Determine structural equivalence of two expressions. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - Expr *E1, Expr *E2) { - if (!E1 || !E2) - return E1 == E2; - - // FIXME: Actually perform a structural comparison! - return true; -} - -/// \brief Determine whether two identifiers are equivalent. -static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, - const IdentifierInfo *Name2) { - if (!Name1 || !Name2) - return Name1 == Name2; - - return Name1->getName() == Name2->getName(); -} - -/// \brief Determine whether two nested-name-specifiers are equivalent. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2) { - if (NNS1->getKind() != NNS2->getKind()) - return false; - - NestedNameSpecifier *Prefix1 = NNS1->getPrefix(), - *Prefix2 = NNS2->getPrefix(); - if ((bool)Prefix1 != (bool)Prefix2) - return false; - - if (Prefix1) - if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2)) - return false; - - switch (NNS1->getKind()) { - case NestedNameSpecifier::Identifier: - return IsStructurallyEquivalent(NNS1->getAsIdentifier(), - NNS2->getAsIdentifier()); - case NestedNameSpecifier::Namespace: - return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(), - NNS2->getAsNamespace()); - case NestedNameSpecifier::NamespaceAlias: - return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(), - NNS2->getAsNamespaceAlias()); - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: - return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0), - QualType(NNS2->getAsType(), 0)); - case NestedNameSpecifier::Global: - return true; - case NestedNameSpecifier::Super: - return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(), - NNS2->getAsRecordDecl()); - } - return false; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - const TemplateName &N1, - const TemplateName &N2) { - if (N1.getKind() != N2.getKind()) - return false; - switch (N1.getKind()) { - case TemplateName::Template: - return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(), - N2.getAsTemplateDecl()); - - case TemplateName::OverloadedTemplate: { - OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(), - *OS2 = N2.getAsOverloadedTemplate(); - OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(), - E1 = OS1->end(), E2 = OS2->end(); - for (; I1 != E1 && I2 != E2; ++I1, ++I2) - if (!IsStructurallyEquivalent(Context, *I1, *I2)) - return false; - return I1 == E1 && I2 == E2; - } - - case TemplateName::QualifiedTemplate: { - QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(), - *QN2 = N2.getAsQualifiedTemplateName(); - return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) && - IsStructurallyEquivalent(Context, QN1->getQualifier(), - QN2->getQualifier()); - } - - case TemplateName::DependentTemplate: { - DependentTemplateName *DN1 = N1.getAsDependentTemplateName(), - *DN2 = N2.getAsDependentTemplateName(); - if (!IsStructurallyEquivalent(Context, DN1->getQualifier(), - DN2->getQualifier())) - return false; - if (DN1->isIdentifier() && DN2->isIdentifier()) - return IsStructurallyEquivalent(DN1->getIdentifier(), - DN2->getIdentifier()); - else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator()) - return DN1->getOperator() == DN2->getOperator(); - return false; - } - - case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(), - *TS2 = N2.getAsSubstTemplateTemplateParm(); - return IsStructurallyEquivalent(Context, TS1->getParameter(), - TS2->getParameter()) && - IsStructurallyEquivalent(Context, TS1->getReplacement(), - TS2->getReplacement()); - } - case TemplateName::SubstTemplateTemplateParmPack: { - SubstTemplateTemplateParmPackStorage - *P1 = N1.getAsSubstTemplateTemplateParmPack(), - *P2 = N2.getAsSubstTemplateTemplateParmPack(); - return IsStructurallyEquivalent(Context, P1->getArgumentPack(), - P2->getArgumentPack()) && - IsStructurallyEquivalent(Context, P1->getParameterPack(), - P2->getParameterPack()); - } - } - return false; -} - -/// \brief Determine whether two template arguments are equivalent. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - const TemplateArgument &Arg1, - const TemplateArgument &Arg2) { - if (Arg1.getKind() != Arg2.getKind()) - return false; - - switch (Arg1.getKind()) { - case TemplateArgument::Null: - return true; - - case TemplateArgument::Type: - return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); - - case TemplateArgument::Integral: - if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), - Arg2.getIntegralType())) - return false; - - return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral()); - - case TemplateArgument::Declaration: - return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); - - case TemplateArgument::NullPtr: - return true; // FIXME: Is this correct? - - case TemplateArgument::Template: - return IsStructurallyEquivalent(Context, - Arg1.getAsTemplate(), - Arg2.getAsTemplate()); - - case TemplateArgument::TemplateExpansion: - return IsStructurallyEquivalent(Context, - Arg1.getAsTemplateOrTemplatePattern(), - Arg2.getAsTemplateOrTemplatePattern()); - - case TemplateArgument::Expression: - return IsStructurallyEquivalent(Context, - Arg1.getAsExpr(), Arg2.getAsExpr()); - - case TemplateArgument::Pack: - if (Arg1.pack_size() != Arg2.pack_size()) - return false; - - for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I) - if (!IsStructurallyEquivalent(Context, - Arg1.pack_begin()[I], - Arg2.pack_begin()[I])) - return false; - - return true; - } - - llvm_unreachable("Invalid template argument kind"); -} - -/// \brief Determine structural equivalence for the common part of array -/// types. -static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, - const ArrayType *Array1, - const ArrayType *Array2) { - if (!IsStructurallyEquivalent(Context, - Array1->getElementType(), - Array2->getElementType())) - return false; - if (Array1->getSizeModifier() != Array2->getSizeModifier()) - return false; - if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers()) - return false; - - return true; -} - -/// \brief Determine structural equivalence of two types. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - QualType T1, QualType T2) { - if (T1.isNull() || T2.isNull()) - return T1.isNull() && T2.isNull(); - - if (!Context.StrictTypeSpelling) { - // We aren't being strict about token-to-token equivalence of types, - // so map down to the canonical type. - T1 = Context.C1.getCanonicalType(T1); - T2 = Context.C2.getCanonicalType(T2); - } - - if (T1.getQualifiers() != T2.getQualifiers()) - return false; - - Type::TypeClass TC = T1->getTypeClass(); - - if (T1->getTypeClass() != T2->getTypeClass()) { - // Compare function types with prototypes vs. without prototypes as if - // both did not have prototypes. - if (T1->getTypeClass() == Type::FunctionProto && - T2->getTypeClass() == Type::FunctionNoProto) - TC = Type::FunctionNoProto; - else if (T1->getTypeClass() == Type::FunctionNoProto && - T2->getTypeClass() == Type::FunctionProto) - TC = Type::FunctionNoProto; - else - return false; - } - - switch (TC) { - case Type::Builtin: - // FIXME: Deal with Char_S/Char_U. - if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind()) - return false; - break; - - case Type::Complex: - if (!IsStructurallyEquivalent(Context, - cast<ComplexType>(T1)->getElementType(), - cast<ComplexType>(T2)->getElementType())) - return false; - break; - - case Type::Adjusted: - case Type::Decayed: - if (!IsStructurallyEquivalent(Context, - cast<AdjustedType>(T1)->getOriginalType(), - cast<AdjustedType>(T2)->getOriginalType())) - return false; - break; - - case Type::Pointer: - if (!IsStructurallyEquivalent(Context, - cast<PointerType>(T1)->getPointeeType(), - cast<PointerType>(T2)->getPointeeType())) - return false; - break; - - case Type::BlockPointer: - if (!IsStructurallyEquivalent(Context, - cast<BlockPointerType>(T1)->getPointeeType(), - cast<BlockPointerType>(T2)->getPointeeType())) - return false; - break; - - case Type::LValueReference: - case Type::RValueReference: { - const ReferenceType *Ref1 = cast<ReferenceType>(T1); - const ReferenceType *Ref2 = cast<ReferenceType>(T2); - if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue()) - return false; - if (Ref1->isInnerRef() != Ref2->isInnerRef()) - return false; - if (!IsStructurallyEquivalent(Context, - Ref1->getPointeeTypeAsWritten(), - Ref2->getPointeeTypeAsWritten())) - return false; - break; - } - - case Type::MemberPointer: { - const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1); - const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2); - if (!IsStructurallyEquivalent(Context, - MemPtr1->getPointeeType(), - MemPtr2->getPointeeType())) - return false; - if (!IsStructurallyEquivalent(Context, - QualType(MemPtr1->getClass(), 0), - QualType(MemPtr2->getClass(), 0))) - return false; - break; - } - - case Type::ConstantArray: { - const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1); - const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2); - if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize())) - return false; - - if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) - return false; - break; - } - - case Type::IncompleteArray: - if (!IsArrayStructurallyEquivalent(Context, - cast<ArrayType>(T1), - cast<ArrayType>(T2))) - return false; - break; - - case Type::VariableArray: { - const VariableArrayType *Array1 = cast<VariableArrayType>(T1); - const VariableArrayType *Array2 = cast<VariableArrayType>(T2); - if (!IsStructurallyEquivalent(Context, - Array1->getSizeExpr(), Array2->getSizeExpr())) - return false; - - if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) - return false; - - break; - } - - case Type::DependentSizedArray: { - const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1); - const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2); - if (!IsStructurallyEquivalent(Context, - Array1->getSizeExpr(), Array2->getSizeExpr())) - return false; - - if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) - return false; - - break; - } - - case Type::DependentSizedExtVector: { - const DependentSizedExtVectorType *Vec1 - = cast<DependentSizedExtVectorType>(T1); - const DependentSizedExtVectorType *Vec2 - = cast<DependentSizedExtVectorType>(T2); - if (!IsStructurallyEquivalent(Context, - Vec1->getSizeExpr(), Vec2->getSizeExpr())) - return false; - if (!IsStructurallyEquivalent(Context, - Vec1->getElementType(), - Vec2->getElementType())) - return false; - break; - } - - case Type::Vector: - case Type::ExtVector: { - const VectorType *Vec1 = cast<VectorType>(T1); - const VectorType *Vec2 = cast<VectorType>(T2); - if (!IsStructurallyEquivalent(Context, - Vec1->getElementType(), - Vec2->getElementType())) - return false; - if (Vec1->getNumElements() != Vec2->getNumElements()) - return false; - if (Vec1->getVectorKind() != Vec2->getVectorKind()) - return false; - break; - } - - case Type::FunctionProto: { - const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1); - const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2); - if (Proto1->getNumParams() != Proto2->getNumParams()) - return false; - for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I), - Proto2->getParamType(I))) - return false; - } - if (Proto1->isVariadic() != Proto2->isVariadic()) - return false; - if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType()) - return false; - if (Proto1->getExceptionSpecType() == EST_Dynamic) { - if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) - return false; - for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Proto1->getExceptionType(I), - Proto2->getExceptionType(I))) - return false; - } - } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) { - if (!IsStructurallyEquivalent(Context, - Proto1->getNoexceptExpr(), - Proto2->getNoexceptExpr())) - return false; - } - if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) - return false; - - // Fall through to check the bits common with FunctionNoProtoType. - } - - case Type::FunctionNoProto: { - const FunctionType *Function1 = cast<FunctionType>(T1); - const FunctionType *Function2 = cast<FunctionType>(T2); - if (!IsStructurallyEquivalent(Context, Function1->getReturnType(), - Function2->getReturnType())) - return false; - if (Function1->getExtInfo() != Function2->getExtInfo()) - return false; - break; - } - - case Type::UnresolvedUsing: - if (!IsStructurallyEquivalent(Context, - cast<UnresolvedUsingType>(T1)->getDecl(), - cast<UnresolvedUsingType>(T2)->getDecl())) - return false; - - break; - - case Type::Attributed: - if (!IsStructurallyEquivalent(Context, - cast<AttributedType>(T1)->getModifiedType(), - cast<AttributedType>(T2)->getModifiedType())) - return false; - if (!IsStructurallyEquivalent(Context, - cast<AttributedType>(T1)->getEquivalentType(), - cast<AttributedType>(T2)->getEquivalentType())) - return false; - break; - - case Type::Paren: - if (!IsStructurallyEquivalent(Context, - cast<ParenType>(T1)->getInnerType(), - cast<ParenType>(T2)->getInnerType())) - return false; - break; - - case Type::Typedef: - if (!IsStructurallyEquivalent(Context, - cast<TypedefType>(T1)->getDecl(), - cast<TypedefType>(T2)->getDecl())) - return false; - break; - - case Type::TypeOfExpr: - if (!IsStructurallyEquivalent(Context, - cast<TypeOfExprType>(T1)->getUnderlyingExpr(), - cast<TypeOfExprType>(T2)->getUnderlyingExpr())) - return false; - break; - - case Type::TypeOf: - if (!IsStructurallyEquivalent(Context, - cast<TypeOfType>(T1)->getUnderlyingType(), - cast<TypeOfType>(T2)->getUnderlyingType())) - return false; - break; - - case Type::UnaryTransform: - if (!IsStructurallyEquivalent(Context, - cast<UnaryTransformType>(T1)->getUnderlyingType(), - cast<UnaryTransformType>(T1)->getUnderlyingType())) - return false; - break; - - case Type::Decltype: - if (!IsStructurallyEquivalent(Context, - cast<DecltypeType>(T1)->getUnderlyingExpr(), - cast<DecltypeType>(T2)->getUnderlyingExpr())) - return false; - break; - - case Type::Auto: - if (!IsStructurallyEquivalent(Context, - cast<AutoType>(T1)->getDeducedType(), - cast<AutoType>(T2)->getDeducedType())) - return false; - break; - - case Type::DeducedTemplateSpecialization: { - auto *DT1 = cast<DeducedTemplateSpecializationType>(T1); - auto *DT2 = cast<DeducedTemplateSpecializationType>(T2); - if (!IsStructurallyEquivalent(Context, - DT1->getTemplateName(), - DT2->getTemplateName())) - return false; - if (!IsStructurallyEquivalent(Context, - DT1->getDeducedType(), - DT2->getDeducedType())) - return false; - break; - } - - case Type::Record: - case Type::Enum: - if (!IsStructurallyEquivalent(Context, - cast<TagType>(T1)->getDecl(), - cast<TagType>(T2)->getDecl())) - return false; - break; - - case Type::TemplateTypeParm: { - const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1); - const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2); - if (Parm1->getDepth() != Parm2->getDepth()) - return false; - if (Parm1->getIndex() != Parm2->getIndex()) - return false; - if (Parm1->isParameterPack() != Parm2->isParameterPack()) - return false; - - // Names of template type parameters are never significant. - break; - } - - case Type::SubstTemplateTypeParm: { - const SubstTemplateTypeParmType *Subst1 - = cast<SubstTemplateTypeParmType>(T1); - const SubstTemplateTypeParmType *Subst2 - = cast<SubstTemplateTypeParmType>(T2); - if (!IsStructurallyEquivalent(Context, - QualType(Subst1->getReplacedParameter(), 0), - QualType(Subst2->getReplacedParameter(), 0))) - return false; - if (!IsStructurallyEquivalent(Context, - Subst1->getReplacementType(), - Subst2->getReplacementType())) - return false; - break; - } - - case Type::SubstTemplateTypeParmPack: { - const SubstTemplateTypeParmPackType *Subst1 - = cast<SubstTemplateTypeParmPackType>(T1); - const SubstTemplateTypeParmPackType *Subst2 - = cast<SubstTemplateTypeParmPackType>(T2); - if (!IsStructurallyEquivalent(Context, - QualType(Subst1->getReplacedParameter(), 0), - QualType(Subst2->getReplacedParameter(), 0))) - return false; - if (!IsStructurallyEquivalent(Context, - Subst1->getArgumentPack(), - Subst2->getArgumentPack())) - return false; - break; - } - case Type::TemplateSpecialization: { - const TemplateSpecializationType *Spec1 - = cast<TemplateSpecializationType>(T1); - const TemplateSpecializationType *Spec2 - = cast<TemplateSpecializationType>(T2); - if (!IsStructurallyEquivalent(Context, - Spec1->getTemplateName(), - Spec2->getTemplateName())) - return false; - if (Spec1->getNumArgs() != Spec2->getNumArgs()) - return false; - for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Spec1->getArg(I), Spec2->getArg(I))) - return false; - } - break; - } - - case Type::Elaborated: { - const ElaboratedType *Elab1 = cast<ElaboratedType>(T1); - const ElaboratedType *Elab2 = cast<ElaboratedType>(T2); - // CHECKME: what if a keyword is ETK_None or ETK_typename ? - if (Elab1->getKeyword() != Elab2->getKeyword()) - return false; - if (!IsStructurallyEquivalent(Context, - Elab1->getQualifier(), - Elab2->getQualifier())) - return false; - if (!IsStructurallyEquivalent(Context, - Elab1->getNamedType(), - Elab2->getNamedType())) - return false; - break; - } - - case Type::InjectedClassName: { - const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1); - const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2); - if (!IsStructurallyEquivalent(Context, - Inj1->getInjectedSpecializationType(), - Inj2->getInjectedSpecializationType())) - return false; - break; - } - - case Type::DependentName: { - const DependentNameType *Typename1 = cast<DependentNameType>(T1); - const DependentNameType *Typename2 = cast<DependentNameType>(T2); - if (!IsStructurallyEquivalent(Context, - Typename1->getQualifier(), - Typename2->getQualifier())) - return false; - if (!IsStructurallyEquivalent(Typename1->getIdentifier(), - Typename2->getIdentifier())) - return false; - - break; - } - - case Type::DependentTemplateSpecialization: { - const DependentTemplateSpecializationType *Spec1 = - cast<DependentTemplateSpecializationType>(T1); - const DependentTemplateSpecializationType *Spec2 = - cast<DependentTemplateSpecializationType>(T2); - if (!IsStructurallyEquivalent(Context, - Spec1->getQualifier(), - Spec2->getQualifier())) - return false; - if (!IsStructurallyEquivalent(Spec1->getIdentifier(), - Spec2->getIdentifier())) - return false; - if (Spec1->getNumArgs() != Spec2->getNumArgs()) - return false; - for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Spec1->getArg(I), Spec2->getArg(I))) - return false; - } - break; - } - - case Type::PackExpansion: - if (!IsStructurallyEquivalent(Context, - cast<PackExpansionType>(T1)->getPattern(), - cast<PackExpansionType>(T2)->getPattern())) - return false; - break; - - case Type::ObjCInterface: { - const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1); - const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2); - if (!IsStructurallyEquivalent(Context, - Iface1->getDecl(), Iface2->getDecl())) - return false; - break; - } - - case Type::ObjCTypeParam: { - const ObjCTypeParamType *Obj1 = cast<ObjCTypeParamType>(T1); - const ObjCTypeParamType *Obj2 = cast<ObjCTypeParamType>(T2); - if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), - Obj2->getDecl())) - return false; - - if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) - return false; - for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Obj1->getProtocol(I), - Obj2->getProtocol(I))) - return false; - } - break; - } - case Type::ObjCObject: { - const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1); - const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2); - if (!IsStructurallyEquivalent(Context, - Obj1->getBaseType(), - Obj2->getBaseType())) - return false; - if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) - return false; - for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, - Obj1->getProtocol(I), - Obj2->getProtocol(I))) - return false; - } - break; - } - - case Type::ObjCObjectPointer: { - const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1); - const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2); - if (!IsStructurallyEquivalent(Context, - Ptr1->getPointeeType(), - Ptr2->getPointeeType())) - return false; - break; - } - - case Type::Atomic: { - if (!IsStructurallyEquivalent(Context, - cast<AtomicType>(T1)->getValueType(), - cast<AtomicType>(T2)->getValueType())) - return false; - break; - } - - case Type::Pipe: { - if (!IsStructurallyEquivalent(Context, - cast<PipeType>(T1)->getElementType(), - cast<PipeType>(T2)->getElementType())) - return false; - break; - } - - } // end switch - - return true; -} - -/// \brief Determine structural equivalence of two fields. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - FieldDecl *Field1, FieldDecl *Field2) { - RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext()); - - // For anonymous structs/unions, match up the anonymous struct/union type - // declarations directly, so that we don't go off searching for anonymous - // types - if (Field1->isAnonymousStructOrUnion() && - Field2->isAnonymousStructOrUnion()) { - RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl(); - RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl(); - return IsStructurallyEquivalent(Context, D1, D2); - } - - // Check for equivalent field names. - IdentifierInfo *Name1 = Field1->getIdentifier(); - IdentifierInfo *Name2 = Field2->getIdentifier(); - if (!::IsStructurallyEquivalent(Name1, Name2)) - return false; - - if (!IsStructurallyEquivalent(Context, - Field1->getType(), Field2->getType())) { - if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - Context.Diag2(Field2->getLocation(), diag::note_odr_field) - << Field2->getDeclName() << Field2->getType(); - Context.Diag1(Field1->getLocation(), diag::note_odr_field) - << Field1->getDeclName() << Field1->getType(); - } - return false; - } - - if (Field1->isBitField() != Field2->isBitField()) { - if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - if (Field1->isBitField()) { - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() - << Field1->getBitWidthValue(Context.C1); - Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) - << Field2->getDeclName(); - } else { - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() - << Field2->getBitWidthValue(Context.C2); - Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) - << Field1->getDeclName(); - } - } - return false; - } - - if (Field1->isBitField()) { - // Make sure that the bit-fields are the same length. - unsigned Bits1 = Field1->getBitWidthValue(Context.C1); - unsigned Bits2 = Field2->getBitWidthValue(Context.C2); - - if (Bits1 != Bits2) { - if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() << Bits2; - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() << Bits1; - } - return false; - } - } - - return true; -} - -/// \brief Find the index of the given anonymous struct/union within its -/// context. -/// -/// \returns Returns the index of this anonymous struct/union in its context, -/// including the next assigned index (if none of them match). Returns an -/// empty option if the context is not a record, i.e.. if the anonymous -/// struct/union is at namespace or block scope. -static Optional<unsigned> findUntaggedStructOrUnionIndex(RecordDecl *Anon) { - ASTContext &Context = Anon->getASTContext(); - QualType AnonTy = Context.getRecordType(Anon); - - RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext()); - if (!Owner) - return None; - - unsigned Index = 0; - for (const auto *D : Owner->noload_decls()) { - const auto *F = dyn_cast<FieldDecl>(D); - if (!F) - continue; - - if (F->isAnonymousStructOrUnion()) { - if (Context.hasSameType(F->getType(), AnonTy)) - break; - ++Index; - continue; - } - - // If the field looks like this: - // struct { ... } A; - QualType FieldType = F->getType(); - if (const auto *RecType = dyn_cast<RecordType>(FieldType)) { - const RecordDecl *RecDecl = RecType->getDecl(); - if (RecDecl->getDeclContext() == Owner && - !RecDecl->getIdentifier()) { - if (Context.hasSameType(FieldType, AnonTy)) - break; - ++Index; - continue; - } - } - } - - return Index; -} - -/// \brief Determine structural equivalence of two records. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - RecordDecl *D1, RecordDecl *D2) { - if (D1->isUnion() != D2->isUnion()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) - << D1->getDeclName() << (unsigned)D1->getTagKind(); - } - return false; - } - - if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) { - // If both anonymous structs/unions are in a record context, make sure - // they occur in the same location in the context records. - if (Optional<unsigned> Index1 = findUntaggedStructOrUnionIndex(D1)) { - if (Optional<unsigned> Index2 = findUntaggedStructOrUnionIndex(D2)) { - if (*Index1 != *Index2) - return false; - } - } - } - - // If both declarations are class template specializations, we know - // the ODR applies, so check the template and template arguments. - ClassTemplateSpecializationDecl *Spec1 - = dyn_cast<ClassTemplateSpecializationDecl>(D1); - ClassTemplateSpecializationDecl *Spec2 - = dyn_cast<ClassTemplateSpecializationDecl>(D2); - if (Spec1 && Spec2) { - // Check that the specialized templates are the same. - if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(), - Spec2->getSpecializedTemplate())) - return false; - - // Check that the template arguments are the same. - if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size()) - return false; - - for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I) - if (!IsStructurallyEquivalent(Context, - Spec1->getTemplateArgs().get(I), - Spec2->getTemplateArgs().get(I))) - return false; - } - // If one is a class template specialization and the other is not, these - // structures are different. - else if (Spec1 || Spec2) - return false; - - // Compare the definitions of these two records. If either or both are - // incomplete, we assume that they are equivalent. - D1 = D1->getDefinition(); - D2 = D2->getDefinition(); - if (!D1 || !D2) - return true; - - if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) { - if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { - if (D1CXX->getNumBases() != D2CXX->getNumBases()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) - << D2CXX->getNumBases(); - Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) - << D1CXX->getNumBases(); - } - return false; - } - - // Check the base classes. - for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(), - BaseEnd1 = D1CXX->bases_end(), - Base2 = D2CXX->bases_begin(); - Base1 != BaseEnd1; - ++Base1, ++Base2) { - if (!IsStructurallyEquivalent(Context, - Base1->getType(), Base2->getType())) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Base2->getLocStart(), diag::note_odr_base) - << Base2->getType() - << Base2->getSourceRange(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->getType() - << Base1->getSourceRange(); - } - return false; - } - - // Check virtual vs. non-virtual inheritance mismatch. - if (Base1->isVirtual() != Base2->isVirtual()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Base2->getLocStart(), - diag::note_odr_virtual_base) - << Base2->isVirtual() << Base2->getSourceRange(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->isVirtual() - << Base1->getSourceRange(); - } - return false; - } - } - } else if (D1CXX->getNumBases() > 0) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->getType() - << Base1->getSourceRange(); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); - } - return false; - } - } - - // Check the fields for consistency. - RecordDecl::field_iterator Field2 = D2->field_begin(), - Field2End = D2->field_end(); - for (RecordDecl::field_iterator Field1 = D1->field_begin(), - Field1End = D1->field_end(); - Field1 != Field1End; - ++Field1, ++Field2) { - if (Field2 == Field2End) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(Field1->getLocation(), diag::note_odr_field) - << Field1->getDeclName() << Field1->getType(); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); - } - return false; - } - - if (!IsStructurallyEquivalent(Context, *Field1, *Field2)) - return false; - } - - if (Field2 != Field2End) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Field2->getLocation(), diag::note_odr_field) - << Field2->getDeclName() << Field2->getType(); - Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); - } - return false; - } - - return true; -} - -/// \brief Determine structural equivalence of two enums. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - EnumDecl *D1, EnumDecl *D2) { - EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(), - EC2End = D2->enumerator_end(); - for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(), - EC1End = D1->enumerator_end(); - EC1 != EC1End; ++EC1, ++EC2) { - if (EC2 == EC2End) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) - << EC1->getDeclName() - << EC1->getInitVal().toString(10); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); - } - return false; - } - - llvm::APSInt Val1 = EC1->getInitVal(); - llvm::APSInt Val2 = EC2->getInitVal(); - if (!llvm::APSInt::isSameValue(Val1, Val2) || - !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) - << EC2->getDeclName() - << EC2->getInitVal().toString(10); - Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) - << EC1->getDeclName() - << EC1->getInitVal().toString(10); - } - return false; - } - } - - if (EC2 != EC2End) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) - << EC2->getDeclName() - << EC2->getInitVal().toString(10); - Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); - } - return false; - } - - return true; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - TemplateParameterList *Params1, - TemplateParameterList *Params2) { - if (Params1->size() != Params2->size()) { - if (Context.Complain) { - Context.Diag2(Params2->getTemplateLoc(), - diag::err_odr_different_num_template_parameters) - << Params1->size() << Params2->size(); - Context.Diag1(Params1->getTemplateLoc(), - diag::note_odr_template_parameter_list); - } - return false; - } - - for (unsigned I = 0, N = Params1->size(); I != N; ++I) { - if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { - if (Context.Complain) { - Context.Diag2(Params2->getParam(I)->getLocation(), - diag::err_odr_different_template_parameter_kind); - Context.Diag1(Params1->getParam(I)->getLocation(), - diag::note_odr_template_parameter_here); - } - return false; - } - - if (!Context.IsStructurallyEquivalent(Params1->getParam(I), - Params2->getParam(I))) { - - return false; - } - } - - return true; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - TemplateTypeParmDecl *D1, - TemplateTypeParmDecl *D2) { - if (D1->isParameterPack() != D2->isParameterPack()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); - } - return false; - } - - return true; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NonTypeTemplateParmDecl *D1, - NonTypeTemplateParmDecl *D2) { - if (D1->isParameterPack() != D2->isParameterPack()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); - } - return false; - } - - // Check types. - if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), - diag::err_odr_non_type_parameter_type_inconsistent) - << D2->getType() << D1->getType(); - Context.Diag1(D1->getLocation(), diag::note_odr_value_here) - << D1->getType(); - } - return false; - } - - return true; -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - TemplateTemplateParmDecl *D1, - TemplateTemplateParmDecl *D2) { - if (D1->isParameterPack() != D2->isParameterPack()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); - } - return false; - } - - // Check template parameter lists. - return IsStructurallyEquivalent(Context, D1->getTemplateParameters(), - D2->getTemplateParameters()); -} - -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - ClassTemplateDecl *D1, - ClassTemplateDecl *D2) { - // Check template parameters. - if (!IsStructurallyEquivalent(Context, - D1->getTemplateParameters(), - D2->getTemplateParameters())) - return false; - - // Check the templated declaration. - return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(), - D2->getTemplatedDecl()); -} - -/// \brief Determine structural equivalence of two declarations. -static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - Decl *D1, Decl *D2) { - // FIXME: Check for known structural equivalences via a callback of some sort. - - // Check whether we already know that these two declarations are not - // structurally equivalent. - if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(), - D2->getCanonicalDecl()))) - return false; - - // Determine whether we've already produced a tentative equivalence for D1. - Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()]; - if (EquivToD1) - return EquivToD1 == D2->getCanonicalDecl(); - - // Produce a tentative equivalence D1 <-> D2, which will be checked later. - EquivToD1 = D2->getCanonicalDecl(); - Context.DeclsToCheck.push_back(D1->getCanonicalDecl()); - return true; -} - -bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1, - Decl *D2) { - if (!::IsStructurallyEquivalent(*this, D1, D2)) - return false; - - return !Finish(); -} - -bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1, - QualType T2) { - if (!::IsStructurallyEquivalent(*this, T1, T2)) - return false; - - return !Finish(); -} - -bool StructuralEquivalenceContext::Finish() { - while (!DeclsToCheck.empty()) { - // Check the next declaration. - Decl *D1 = DeclsToCheck.front(); - DeclsToCheck.pop_front(); - - Decl *D2 = TentativeEquivalences[D1]; - assert(D2 && "Unrecorded tentative equivalence?"); - - bool Equivalent = true; - - // FIXME: Switch on all declaration kinds. For now, we're just going to - // check the obvious ones. - if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) { - if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) { - // Check for equivalent structure names. - IdentifierInfo *Name1 = Record1->getIdentifier(); - if (!Name1 && Record1->getTypedefNameForAnonDecl()) - Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier(); - IdentifierInfo *Name2 = Record2->getIdentifier(); - if (!Name2 && Record2->getTypedefNameForAnonDecl()) - Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier(); - if (!::IsStructurallyEquivalent(Name1, Name2) || - !::IsStructurallyEquivalent(*this, Record1, Record2)) - Equivalent = false; - } else { - // Record/non-record mismatch. - Equivalent = false; - } - } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) { - if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) { - // Check for equivalent enum names. - IdentifierInfo *Name1 = Enum1->getIdentifier(); - if (!Name1 && Enum1->getTypedefNameForAnonDecl()) - Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier(); - IdentifierInfo *Name2 = Enum2->getIdentifier(); - if (!Name2 && Enum2->getTypedefNameForAnonDecl()) - Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier(); - if (!::IsStructurallyEquivalent(Name1, Name2) || - !::IsStructurallyEquivalent(*this, Enum1, Enum2)) - Equivalent = false; - } else { - // Enum/non-enum mismatch - Equivalent = false; - } - } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) { - if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) { - if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), - Typedef2->getIdentifier()) || - !::IsStructurallyEquivalent(*this, - Typedef1->getUnderlyingType(), - Typedef2->getUnderlyingType())) - Equivalent = false; - } else { - // Typedef/non-typedef mismatch. - Equivalent = false; - } - } else if (ClassTemplateDecl *ClassTemplate1 - = dyn_cast<ClassTemplateDecl>(D1)) { - if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) { - if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(), - ClassTemplate2->getIdentifier()) || - !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2)) - Equivalent = false; - } else { - // Class template/non-class-template mismatch. - Equivalent = false; - } - } else if (TemplateTypeParmDecl *TTP1= dyn_cast<TemplateTypeParmDecl>(D1)) { - if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } else if (NonTypeTemplateParmDecl *NTTP1 - = dyn_cast<NonTypeTemplateParmDecl>(D1)) { - if (NonTypeTemplateParmDecl *NTTP2 - = dyn_cast<NonTypeTemplateParmDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } else if (TemplateTemplateParmDecl *TTP1 - = dyn_cast<TemplateTemplateParmDecl>(D1)) { - if (TemplateTemplateParmDecl *TTP2 - = dyn_cast<TemplateTemplateParmDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } - - if (!Equivalent) { - // Note that these two declarations are not equivalent (and we already - // know about it). - NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(), - D2->getCanonicalDecl())); - return true; - } - // FIXME: Check other declaration kinds! - } - - return false; -} - //---------------------------------------------------------------------------- // Import Types //---------------------------------------------------------------------------- +using namespace clang; + QualType ASTNodeImporter::VisitType(const Type *T) { Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node) << T->getTypeClassName(); @@ -2634,7 +1251,7 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls()); - return Ctx.IsStructurallyEquivalent(From, To); + return Ctx.IsStructurallyEquivalent(From, To); } bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, @@ -2813,10 +1430,10 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { FoundTypedef->getUnderlyingType())) return Importer.Imported(D, FoundTypedef); } - + ConflictingDecls.push_back(FoundDecls[I]); } - + if (!ConflictingDecls.empty()) { Name = Importer.HandleNameConflict(Name, DC, IDNS, ConflictingDecls.data(), @@ -2825,7 +1442,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { return nullptr; } } - + // Import the underlying type of this typedef; QualType T = Importer.Import(D->getUnderlyingType()); if (T.isNull()) @@ -2845,12 +1462,12 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { StartL, Loc, Name.getAsIdentifierInfo(), TInfo); - + ToTypedef->setAccess(D->getAccess()); ToTypedef->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToTypedef); LexicalDC->addDeclInternal(ToTypedef); - + return ToTypedef; } @@ -3024,9 +1641,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { FoundRecord->isAnonymousStructOrUnion()) { // If both anonymous structs/unions are in a record context, make sure // they occur in the same location in the context records. - if (Optional<unsigned> Index1 - = findUntaggedStructOrUnionIndex(D)) { - if (Optional<unsigned> Index2 = + if (Optional<unsigned> Index1 = + StructuralEquivalenceContext::findUntaggedStructOrUnionIndex( + D)) { + if (Optional<unsigned> Index2 = StructuralEquivalenceContext:: findUntaggedStructOrUnionIndex(FoundRecord)) { if (*Index1 != *Index2) continue; @@ -3216,7 +1834,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - + if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) { if (FoundFunction->hasExternalFormalLinkage() && D->hasExternalFormalLinkage()) { @@ -3225,14 +1843,14 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // FIXME: Actually try to merge the body and other attributes. return Importer.Imported(D, FoundFunction); } - + // FIXME: Check for overloading more carefully, e.g., by boosting // Sema::IsOverload out to the AST library. - + // Function overloading is okay in C++. if (Importer.getToContext().getLangOpts().CPlusPlus) continue; - + // Complain about inconsistent function types. Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent) << Name << D->getType() << FoundFunction->getType(); @@ -3241,10 +1859,10 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { << FoundFunction->getType(); } } - + ConflictingDecls.push_back(FoundDecls[I]); } - + if (!ConflictingDecls.empty()) { Name = Importer.HandleNameConflict(Name, DC, IDNS, ConflictingDecls.data(), @@ -3449,12 +2067,12 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) continue; - if (Importer.IsStructurallyEquivalent(D->getType(), + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType())) { Importer.Imported(D, FoundField); return FoundField; } - + Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent) << Name << D->getType() << FoundField->getType(); Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) @@ -3514,7 +2132,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) continue; - if (Importer.IsStructurallyEquivalent(D->getType(), + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), !Name.isEmpty())) { Importer.Imported(D, FoundField); @@ -3638,12 +2256,12 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { if (ToD) return ToD; - // Determine whether we've already imported this ivar + // Determine whether we've already imported this ivar SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) { - if (Importer.IsStructurallyEquivalent(D->getType(), + if (Importer.IsStructurallyEquivalent(D->getType(), FoundIvar->getType())) { Importer.Imported(D, FoundIvar); return FoundIvar; @@ -3702,12 +2320,12 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; - + if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) { // We have found a variable that we may need to merge with. Check it. if (FoundVar->hasExternalFormalLinkage() && D->hasExternalFormalLinkage()) { - if (Importer.IsStructurallyEquivalent(D->getType(), + if (Importer.IsStructurallyEquivalent(D->getType(), FoundVar->getType())) { MergeWithVar = FoundVar; break; @@ -3931,12 +2549,12 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { } // Check parameter types. - for (ObjCMethodDecl::param_iterator P = D->param_begin(), + for (ObjCMethodDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(), FoundP = FoundMethod->param_begin(); P != PEnd; ++P, ++FoundP) { - if (!Importer.IsStructurallyEquivalent((*P)->getType(), + if (!Importer.IsStructurallyEquivalent((*P)->getType(), (*FoundP)->getType())) { - Importer.FromDiag((*P)->getLocation(), + Importer.FromDiag((*P)->getLocation(), diag::err_odr_objc_method_param_type_inconsistent) << D->isInstanceMethod() << Name << (*P)->getType() << (*FoundP)->getType(); @@ -4542,7 +3160,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { if (ObjCPropertyDecl *FoundProp = dyn_cast<ObjCPropertyDecl>(FoundDecls[I])) { // Check property types. - if (!Importer.IsStructurallyEquivalent(D->getType(), + if (!Importer.IsStructurallyEquivalent(D->getType(), FoundProp->getType())) { Importer.ToDiag(Loc, diag::err_odr_objc_property_type_inconsistent) << Name << D->getType() << FoundProp->getType(); @@ -7597,7 +6215,7 @@ bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, = ImportedTypes.find(From.getTypePtr()); if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To)) return true; - + StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls, false, Complain); return Ctx.IsStructurallyEquivalent(From, To); diff --git a/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp b/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp new file mode 100644 index 000000000000..8fe72eac4133 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -0,0 +1,1318 @@ +//===--- ASTStructuralEquivalence.cpp - -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implement StructuralEquivalenceContext class and helper functions +// for layout matching. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTStructuralEquivalence.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/ASTImporter.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/Basic/SourceManager.h" + +namespace { + +using namespace clang; + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgument &Arg1, + const TemplateArgument &Arg2); + +/// Determine structural equivalence of two expressions. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Expr *E1, Expr *E2) { + if (!E1 || !E2) + return E1 == E2; + + // FIXME: Actually perform a structural comparison! + return true; +} + +/// Determine whether two identifiers are equivalent. +static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, + const IdentifierInfo *Name2) { + if (!Name1 || !Name2) + return Name1 == Name2; + + return Name1->getName() == Name2->getName(); +} + +/// Determine whether two nested-name-specifiers are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NestedNameSpecifier *NNS1, + NestedNameSpecifier *NNS2) { + if (NNS1->getKind() != NNS2->getKind()) + return false; + + NestedNameSpecifier *Prefix1 = NNS1->getPrefix(), + *Prefix2 = NNS2->getPrefix(); + if ((bool)Prefix1 != (bool)Prefix2) + return false; + + if (Prefix1) + if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2)) + return false; + + switch (NNS1->getKind()) { + case NestedNameSpecifier::Identifier: + return IsStructurallyEquivalent(NNS1->getAsIdentifier(), + NNS2->getAsIdentifier()); + case NestedNameSpecifier::Namespace: + return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(), + NNS2->getAsNamespace()); + case NestedNameSpecifier::NamespaceAlias: + return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(), + NNS2->getAsNamespaceAlias()); + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0), + QualType(NNS2->getAsType(), 0)); + case NestedNameSpecifier::Global: + return true; + case NestedNameSpecifier::Super: + return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(), + NNS2->getAsRecordDecl()); + } + return false; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateName &N1, + const TemplateName &N2) { + if (N1.getKind() != N2.getKind()) + return false; + switch (N1.getKind()) { + case TemplateName::Template: + return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(), + N2.getAsTemplateDecl()); + + case TemplateName::OverloadedTemplate: { + OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(), + *OS2 = N2.getAsOverloadedTemplate(); + OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(), + E1 = OS1->end(), E2 = OS2->end(); + for (; I1 != E1 && I2 != E2; ++I1, ++I2) + if (!IsStructurallyEquivalent(Context, *I1, *I2)) + return false; + return I1 == E1 && I2 == E2; + } + + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(), + *QN2 = N2.getAsQualifiedTemplateName(); + return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) && + IsStructurallyEquivalent(Context, QN1->getQualifier(), + QN2->getQualifier()); + } + + case TemplateName::DependentTemplate: { + DependentTemplateName *DN1 = N1.getAsDependentTemplateName(), + *DN2 = N2.getAsDependentTemplateName(); + if (!IsStructurallyEquivalent(Context, DN1->getQualifier(), + DN2->getQualifier())) + return false; + if (DN1->isIdentifier() && DN2->isIdentifier()) + return IsStructurallyEquivalent(DN1->getIdentifier(), + DN2->getIdentifier()); + else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator()) + return DN1->getOperator() == DN2->getOperator(); + return false; + } + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(), + *TS2 = N2.getAsSubstTemplateTemplateParm(); + return IsStructurallyEquivalent(Context, TS1->getParameter(), + TS2->getParameter()) && + IsStructurallyEquivalent(Context, TS1->getReplacement(), + TS2->getReplacement()); + } + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage + *P1 = N1.getAsSubstTemplateTemplateParmPack(), + *P2 = N2.getAsSubstTemplateTemplateParmPack(); + return IsStructurallyEquivalent(Context, P1->getArgumentPack(), + P2->getArgumentPack()) && + IsStructurallyEquivalent(Context, P1->getParameterPack(), + P2->getParameterPack()); + } + } + return false; +} + +/// Determine whether two template arguments are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgument &Arg1, + const TemplateArgument &Arg2) { + if (Arg1.getKind() != Arg2.getKind()) + return false; + + switch (Arg1.getKind()) { + case TemplateArgument::Null: + return true; + + case TemplateArgument::Type: + return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); + + case TemplateArgument::Integral: + if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), + Arg2.getIntegralType())) + return false; + + return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), + Arg2.getAsIntegral()); + + case TemplateArgument::Declaration: + return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); + + case TemplateArgument::NullPtr: + return true; // FIXME: Is this correct? + + case TemplateArgument::Template: + return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(), + Arg2.getAsTemplate()); + + case TemplateArgument::TemplateExpansion: + return IsStructurallyEquivalent(Context, + Arg1.getAsTemplateOrTemplatePattern(), + Arg2.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return IsStructurallyEquivalent(Context, Arg1.getAsExpr(), + Arg2.getAsExpr()); + + case TemplateArgument::Pack: + if (Arg1.pack_size() != Arg2.pack_size()) + return false; + + for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I], + Arg2.pack_begin()[I])) + return false; + + return true; + } + + llvm_unreachable("Invalid template argument kind"); +} + +/// Determine structural equivalence for the common part of array +/// types. +static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, + const ArrayType *Array1, + const ArrayType *Array2) { + if (!IsStructurallyEquivalent(Context, Array1->getElementType(), + Array2->getElementType())) + return false; + if (Array1->getSizeModifier() != Array2->getSizeModifier()) + return false; + if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers()) + return false; + + return true; +} + +/// Determine structural equivalence of two types. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2) { + if (T1.isNull() || T2.isNull()) + return T1.isNull() && T2.isNull(); + + if (!Context.StrictTypeSpelling) { + // We aren't being strict about token-to-token equivalence of types, + // so map down to the canonical type. + T1 = Context.FromCtx.getCanonicalType(T1); + T2 = Context.ToCtx.getCanonicalType(T2); + } + + if (T1.getQualifiers() != T2.getQualifiers()) + return false; + + Type::TypeClass TC = T1->getTypeClass(); + + if (T1->getTypeClass() != T2->getTypeClass()) { + // Compare function types with prototypes vs. without prototypes as if + // both did not have prototypes. + if (T1->getTypeClass() == Type::FunctionProto && + T2->getTypeClass() == Type::FunctionNoProto) + TC = Type::FunctionNoProto; + else if (T1->getTypeClass() == Type::FunctionNoProto && + T2->getTypeClass() == Type::FunctionProto) + TC = Type::FunctionNoProto; + else + return false; + } + + switch (TC) { + case Type::Builtin: + // FIXME: Deal with Char_S/Char_U. + if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind()) + return false; + break; + + case Type::Complex: + if (!IsStructurallyEquivalent(Context, + cast<ComplexType>(T1)->getElementType(), + cast<ComplexType>(T2)->getElementType())) + return false; + break; + + case Type::Adjusted: + case Type::Decayed: + if (!IsStructurallyEquivalent(Context, + cast<AdjustedType>(T1)->getOriginalType(), + cast<AdjustedType>(T2)->getOriginalType())) + return false; + break; + + case Type::Pointer: + if (!IsStructurallyEquivalent(Context, + cast<PointerType>(T1)->getPointeeType(), + cast<PointerType>(T2)->getPointeeType())) + return false; + break; + + case Type::BlockPointer: + if (!IsStructurallyEquivalent(Context, + cast<BlockPointerType>(T1)->getPointeeType(), + cast<BlockPointerType>(T2)->getPointeeType())) + return false; + break; + + case Type::LValueReference: + case Type::RValueReference: { + const ReferenceType *Ref1 = cast<ReferenceType>(T1); + const ReferenceType *Ref2 = cast<ReferenceType>(T2); + if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue()) + return false; + if (Ref1->isInnerRef() != Ref2->isInnerRef()) + return false; + if (!IsStructurallyEquivalent(Context, Ref1->getPointeeTypeAsWritten(), + Ref2->getPointeeTypeAsWritten())) + return false; + break; + } + + case Type::MemberPointer: { + const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1); + const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2); + if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(), + MemPtr2->getPointeeType())) + return false; + if (!IsStructurallyEquivalent(Context, QualType(MemPtr1->getClass(), 0), + QualType(MemPtr2->getClass(), 0))) + return false; + break; + } + + case Type::ConstantArray: { + const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1); + const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2); + if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + break; + } + + case Type::IncompleteArray: + if (!IsArrayStructurallyEquivalent(Context, cast<ArrayType>(T1), + cast<ArrayType>(T2))) + return false; + break; + + case Type::VariableArray: { + const VariableArrayType *Array1 = cast<VariableArrayType>(T1); + const VariableArrayType *Array2 = cast<VariableArrayType>(T2); + if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(), + Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedArray: { + const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1); + const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2); + if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(), + Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedExtVector: { + const DependentSizedExtVectorType *Vec1 = + cast<DependentSizedExtVectorType>(T1); + const DependentSizedExtVectorType *Vec2 = + cast<DependentSizedExtVectorType>(T2); + if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(), + Vec2->getSizeExpr())) + return false; + if (!IsStructurallyEquivalent(Context, Vec1->getElementType(), + Vec2->getElementType())) + return false; + break; + } + + case Type::Vector: + case Type::ExtVector: { + const VectorType *Vec1 = cast<VectorType>(T1); + const VectorType *Vec2 = cast<VectorType>(T2); + if (!IsStructurallyEquivalent(Context, Vec1->getElementType(), + Vec2->getElementType())) + return false; + if (Vec1->getNumElements() != Vec2->getNumElements()) + return false; + if (Vec1->getVectorKind() != Vec2->getVectorKind()) + return false; + break; + } + + case Type::FunctionProto: { + const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1); + const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2); + if (Proto1->getNumParams() != Proto2->getNumParams()) + return false; + for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I), + Proto2->getParamType(I))) + return false; + } + if (Proto1->isVariadic() != Proto2->isVariadic()) + return false; + if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType()) + return false; + if (Proto1->getExceptionSpecType() == EST_Dynamic) { + if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + return false; + for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I), + Proto2->getExceptionType(I))) + return false; + } + } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) { + if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(), + Proto2->getNoexceptExpr())) + return false; + } + if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) + return false; + + // Fall through to check the bits common with FunctionNoProtoType. + } + + case Type::FunctionNoProto: { + const FunctionType *Function1 = cast<FunctionType>(T1); + const FunctionType *Function2 = cast<FunctionType>(T2); + if (!IsStructurallyEquivalent(Context, Function1->getReturnType(), + Function2->getReturnType())) + return false; + if (Function1->getExtInfo() != Function2->getExtInfo()) + return false; + break; + } + + case Type::UnresolvedUsing: + if (!IsStructurallyEquivalent(Context, + cast<UnresolvedUsingType>(T1)->getDecl(), + cast<UnresolvedUsingType>(T2)->getDecl())) + return false; + + break; + + case Type::Attributed: + if (!IsStructurallyEquivalent(Context, + cast<AttributedType>(T1)->getModifiedType(), + cast<AttributedType>(T2)->getModifiedType())) + return false; + if (!IsStructurallyEquivalent( + Context, cast<AttributedType>(T1)->getEquivalentType(), + cast<AttributedType>(T2)->getEquivalentType())) + return false; + break; + + case Type::Paren: + if (!IsStructurallyEquivalent(Context, cast<ParenType>(T1)->getInnerType(), + cast<ParenType>(T2)->getInnerType())) + return false; + break; + + case Type::Typedef: + if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(), + cast<TypedefType>(T2)->getDecl())) + return false; + break; + + case Type::TypeOfExpr: + if (!IsStructurallyEquivalent( + Context, cast<TypeOfExprType>(T1)->getUnderlyingExpr(), + cast<TypeOfExprType>(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::TypeOf: + if (!IsStructurallyEquivalent(Context, + cast<TypeOfType>(T1)->getUnderlyingType(), + cast<TypeOfType>(T2)->getUnderlyingType())) + return false; + break; + + case Type::UnaryTransform: + if (!IsStructurallyEquivalent( + Context, cast<UnaryTransformType>(T1)->getUnderlyingType(), + cast<UnaryTransformType>(T1)->getUnderlyingType())) + return false; + break; + + case Type::Decltype: + if (!IsStructurallyEquivalent(Context, + cast<DecltypeType>(T1)->getUnderlyingExpr(), + cast<DecltypeType>(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::Auto: + if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(), + cast<AutoType>(T2)->getDeducedType())) + return false; + break; + + case Type::DeducedTemplateSpecialization: { + auto *DT1 = cast<DeducedTemplateSpecializationType>(T1); + auto *DT2 = cast<DeducedTemplateSpecializationType>(T2); + if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(), + DT2->getTemplateName())) + return false; + if (!IsStructurallyEquivalent(Context, DT1->getDeducedType(), + DT2->getDeducedType())) + return false; + break; + } + + case Type::Record: + case Type::Enum: + if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(), + cast<TagType>(T2)->getDecl())) + return false; + break; + + case Type::TemplateTypeParm: { + const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1); + const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2); + if (Parm1->getDepth() != Parm2->getDepth()) + return false; + if (Parm1->getIndex() != Parm2->getIndex()) + return false; + if (Parm1->isParameterPack() != Parm2->isParameterPack()) + return false; + + // Names of template type parameters are never significant. + break; + } + + case Type::SubstTemplateTypeParm: { + const SubstTemplateTypeParmType *Subst1 = + cast<SubstTemplateTypeParmType>(T1); + const SubstTemplateTypeParmType *Subst2 = + cast<SubstTemplateTypeParmType>(T2); + if (!IsStructurallyEquivalent(Context, + QualType(Subst1->getReplacedParameter(), 0), + QualType(Subst2->getReplacedParameter(), 0))) + return false; + if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(), + Subst2->getReplacementType())) + return false; + break; + } + + case Type::SubstTemplateTypeParmPack: { + const SubstTemplateTypeParmPackType *Subst1 = + cast<SubstTemplateTypeParmPackType>(T1); + const SubstTemplateTypeParmPackType *Subst2 = + cast<SubstTemplateTypeParmPackType>(T2); + if (!IsStructurallyEquivalent(Context, + QualType(Subst1->getReplacedParameter(), 0), + QualType(Subst2->getReplacedParameter(), 0))) + return false; + if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(), + Subst2->getArgumentPack())) + return false; + break; + } + case Type::TemplateSpecialization: { + const TemplateSpecializationType *Spec1 = + cast<TemplateSpecializationType>(T1); + const TemplateSpecializationType *Spec2 = + cast<TemplateSpecializationType>(T2); + if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(), + Spec2->getTemplateName())) + return false; + if (Spec1->getNumArgs() != Spec2->getNumArgs()) + return false; + for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Spec1->getArg(I), + Spec2->getArg(I))) + return false; + } + break; + } + + case Type::Elaborated: { + const ElaboratedType *Elab1 = cast<ElaboratedType>(T1); + const ElaboratedType *Elab2 = cast<ElaboratedType>(T2); + // CHECKME: what if a keyword is ETK_None or ETK_typename ? + if (Elab1->getKeyword() != Elab2->getKeyword()) + return false; + if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(), + Elab2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(), + Elab2->getNamedType())) + return false; + break; + } + + case Type::InjectedClassName: { + const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1); + const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2); + if (!IsStructurallyEquivalent(Context, + Inj1->getInjectedSpecializationType(), + Inj2->getInjectedSpecializationType())) + return false; + break; + } + + case Type::DependentName: { + const DependentNameType *Typename1 = cast<DependentNameType>(T1); + const DependentNameType *Typename2 = cast<DependentNameType>(T2); + if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(), + Typename2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Typename1->getIdentifier(), + Typename2->getIdentifier())) + return false; + + break; + } + + case Type::DependentTemplateSpecialization: { + const DependentTemplateSpecializationType *Spec1 = + cast<DependentTemplateSpecializationType>(T1); + const DependentTemplateSpecializationType *Spec2 = + cast<DependentTemplateSpecializationType>(T2); + if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(), + Spec2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Spec1->getIdentifier(), + Spec2->getIdentifier())) + return false; + if (Spec1->getNumArgs() != Spec2->getNumArgs()) + return false; + for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Spec1->getArg(I), + Spec2->getArg(I))) + return false; + } + break; + } + + case Type::PackExpansion: + if (!IsStructurallyEquivalent(Context, + cast<PackExpansionType>(T1)->getPattern(), + cast<PackExpansionType>(T2)->getPattern())) + return false; + break; + + case Type::ObjCInterface: { + const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1); + const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2); + if (!IsStructurallyEquivalent(Context, Iface1->getDecl(), + Iface2->getDecl())) + return false; + break; + } + + case Type::ObjCTypeParam: { + const ObjCTypeParamType *Obj1 = cast<ObjCTypeParamType>(T1); + const ObjCTypeParamType *Obj2 = cast<ObjCTypeParamType>(T2); + if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl())) + return false; + + if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) + return false; + for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I), + Obj2->getProtocol(I))) + return false; + } + break; + } + case Type::ObjCObject: { + const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1); + const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2); + if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(), + Obj2->getBaseType())) + return false; + if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) + return false; + for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I), + Obj2->getProtocol(I))) + return false; + } + break; + } + + case Type::ObjCObjectPointer: { + const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1); + const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2); + if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(), + Ptr2->getPointeeType())) + return false; + break; + } + + case Type::Atomic: { + if (!IsStructurallyEquivalent(Context, cast<AtomicType>(T1)->getValueType(), + cast<AtomicType>(T2)->getValueType())) + return false; + break; + } + + case Type::Pipe: { + if (!IsStructurallyEquivalent(Context, cast<PipeType>(T1)->getElementType(), + cast<PipeType>(T2)->getElementType())) + return false; + break; + } + + } // end switch + + return true; +} + +/// Determine structural equivalence of two fields. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + FieldDecl *Field1, FieldDecl *Field2) { + RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext()); + + // For anonymous structs/unions, match up the anonymous struct/union type + // declarations directly, so that we don't go off searching for anonymous + // types + if (Field1->isAnonymousStructOrUnion() && + Field2->isAnonymousStructOrUnion()) { + RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl(); + RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl(); + return IsStructurallyEquivalent(Context, D1, D2); + } + + // Check for equivalent field names. + IdentifierInfo *Name1 = Field1->getIdentifier(); + IdentifierInfo *Name2 = Field2->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2)) + return false; + + if (!IsStructurallyEquivalent(Context, Field1->getType(), + Field2->getType())) { + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + } + return false; + } + + if (Field1->isBitField() != Field2->isBitField()) { + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(Owner2); + if (Field1->isBitField()) { + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Field1->getBitWidthValue(Context.FromCtx); + Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) + << Field2->getDeclName(); + } else { + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Field2->getBitWidthValue(Context.ToCtx); + Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) + << Field1->getDeclName(); + } + } + return false; + } + + if (Field1->isBitField()) { + // Make sure that the bit-fields are the same length. + unsigned Bits1 = Field1->getBitWidthValue(Context.FromCtx); + unsigned Bits2 = Field2->getBitWidthValue(Context.ToCtx); + + if (Bits1 != Bits2) { + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), + diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() << Bits2; + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() << Bits1; + } + return false; + } + } + + return true; +} + +/// Determine structural equivalence of two records. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + RecordDecl *D1, RecordDecl *D2) { + if (D1->isUnion() != D2->isUnion()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) + << D1->getDeclName() << (unsigned)D1->getTagKind(); + } + return false; + } + + if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) { + // If both anonymous structs/unions are in a record context, make sure + // they occur in the same location in the context records. + if (Optional<unsigned> Index1 = + StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) { + if (Optional<unsigned> Index2 = + StructuralEquivalenceContext::findUntaggedStructOrUnionIndex( + D2)) { + if (*Index1 != *Index2) + return false; + } + } + } + + // If both declarations are class template specializations, we know + // the ODR applies, so check the template and template arguments. + ClassTemplateSpecializationDecl *Spec1 = + dyn_cast<ClassTemplateSpecializationDecl>(D1); + ClassTemplateSpecializationDecl *Spec2 = + dyn_cast<ClassTemplateSpecializationDecl>(D2); + if (Spec1 && Spec2) { + // Check that the specialized templates are the same. + if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(), + Spec2->getSpecializedTemplate())) + return false; + + // Check that the template arguments are the same. + if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size()) + return false; + + for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs().get(I), + Spec2->getTemplateArgs().get(I))) + return false; + } + // If one is a class template specialization and the other is not, these + // structures are different. + else if (Spec1 || Spec2) + return false; + + // Compare the definitions of these two records. If either or both are + // incomplete, we assume that they are equivalent. + D1 = D1->getDefinition(); + D2 = D2->getDefinition(); + if (!D1 || !D2) + return true; + + if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) { + if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { + if (D1CXX->getNumBases() != D2CXX->getNumBases()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) + << D2CXX->getNumBases(); + Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) + << D1CXX->getNumBases(); + } + return false; + } + + // Check the base classes. + for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(), + BaseEnd1 = D1CXX->bases_end(), + Base2 = D2CXX->bases_begin(); + Base1 != BaseEnd1; ++Base1, ++Base2) { + if (!IsStructurallyEquivalent(Context, Base1->getType(), + Base2->getType())) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(Base2->getLocStart(), diag::note_odr_base) + << Base2->getType() << Base2->getSourceRange(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->getType() << Base1->getSourceRange(); + } + return false; + } + + // Check virtual vs. non-virtual inheritance mismatch. + if (Base1->isVirtual() != Base2->isVirtual()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(Base2->getLocStart(), diag::note_odr_virtual_base) + << Base2->isVirtual() << Base2->getSourceRange(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->isVirtual() << Base1->getSourceRange(); + } + return false; + } + } + } else if (D1CXX->getNumBases() > 0) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->getType() << Base1->getSourceRange(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); + } + return false; + } + } + + // Check the fields for consistency. + RecordDecl::field_iterator Field2 = D2->field_begin(), + Field2End = D2->field_end(); + for (RecordDecl::field_iterator Field1 = D1->field_begin(), + Field1End = D1->field_end(); + Field1 != Field1End; ++Field1, ++Field2) { + if (Field2 == Field2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); + } + return false; + } + + if (!IsStructurallyEquivalent(Context, *Field1, *Field2)) + return false; + } + + if (Field2 != Field2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); + } + return false; + } + + return true; +} + +/// Determine structural equivalence of two enums. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + EnumDecl *D1, EnumDecl *D2) { + EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(), + EC2End = D2->enumerator_end(); + for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(), + EC1End = D1->enumerator_end(); + EC1 != EC1End; ++EC1, ++EC2) { + if (EC2 == EC2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() << EC1->getInitVal().toString(10); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); + } + return false; + } + + llvm::APSInt Val1 = EC1->getInitVal(); + llvm::APSInt Val2 = EC2->getInitVal(); + if (!llvm::APSInt::isSameValue(Val1, Val2) || + !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() << EC2->getInitVal().toString(10); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() << EC1->getInitVal().toString(10); + } + return false; + } + } + + if (EC2 != EC2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() << EC2->getInitVal().toString(10); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); + } + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateParameterList *Params1, + TemplateParameterList *Params2) { + if (Params1->size() != Params2->size()) { + if (Context.Complain) { + Context.Diag2(Params2->getTemplateLoc(), + diag::err_odr_different_num_template_parameters) + << Params1->size() << Params2->size(); + Context.Diag1(Params1->getTemplateLoc(), + diag::note_odr_template_parameter_list); + } + return false; + } + + for (unsigned I = 0, N = Params1->size(); I != N; ++I) { + if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { + if (Context.Complain) { + Context.Diag2(Params2->getParam(I)->getLocation(), + diag::err_odr_different_template_parameter_kind); + Context.Diag1(Params1->getParam(I)->getLocation(), + diag::note_odr_template_parameter_here); + } + return false; + } + + if (!Context.IsStructurallyEquivalent(Params1->getParam(I), + Params2->getParam(I))) { + + return false; + } + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateTypeParmDecl *D1, + TemplateTypeParmDecl *D2) { + if (D1->isParameterPack() != D2->isParameterPack()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NonTypeTemplateParmDecl *D1, + NonTypeTemplateParmDecl *D2) { + if (D1->isParameterPack() != D2->isParameterPack()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } + return false; + } + + // Check types. + if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + diag::err_odr_non_type_parameter_type_inconsistent) + << D2->getType() << D1->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_value_here) + << D1->getType(); + } + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateTemplateParmDecl *D1, + TemplateTemplateParmDecl *D2) { + if (D1->isParameterPack() != D2->isParameterPack()) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } + return false; + } + + // Check template parameter lists. + return IsStructurallyEquivalent(Context, D1->getTemplateParameters(), + D2->getTemplateParameters()); +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ClassTemplateDecl *D1, + ClassTemplateDecl *D2) { + // Check template parameters. + if (!IsStructurallyEquivalent(Context, D1->getTemplateParameters(), + D2->getTemplateParameters())) + return false; + + // Check the templated declaration. + return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(), + D2->getTemplatedDecl()); +} + +/// Determine structural equivalence of two declarations. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2) { + // FIXME: Check for known structural equivalences via a callback of some sort. + + // Check whether we already know that these two declarations are not + // structurally equivalent. + if (Context.NonEquivalentDecls.count( + std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl()))) + return false; + + // Determine whether we've already produced a tentative equivalence for D1. + Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()]; + if (EquivToD1) + return EquivToD1 == D2->getCanonicalDecl(); + + // Produce a tentative equivalence D1 <-> D2, which will be checked later. + EquivToD1 = D2->getCanonicalDecl(); + Context.DeclsToCheck.push_back(D1->getCanonicalDecl()); + return true; +} +} // namespace + +namespace clang { + +DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc, + unsigned DiagID) { + assert(Complain && "Not allowed to complain"); + if (LastDiagFromC2) + FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics()); + LastDiagFromC2 = false; + return FromCtx.getDiagnostics().Report(Loc, DiagID); +} + +DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc, + unsigned DiagID) { + assert(Complain && "Not allowed to complain"); + if (!LastDiagFromC2) + ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics()); + LastDiagFromC2 = true; + return ToCtx.getDiagnostics().Report(Loc, DiagID); +} + +Optional<unsigned> +StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { + ASTContext &Context = Anon->getASTContext(); + QualType AnonTy = Context.getRecordType(Anon); + + RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext()); + if (!Owner) + return None; + + unsigned Index = 0; + for (const auto *D : Owner->noload_decls()) { + const auto *F = dyn_cast<FieldDecl>(D); + if (!F) + continue; + + if (F->isAnonymousStructOrUnion()) { + if (Context.hasSameType(F->getType(), AnonTy)) + break; + ++Index; + continue; + } + + // If the field looks like this: + // struct { ... } A; + QualType FieldType = F->getType(); + if (const auto *RecType = dyn_cast<RecordType>(FieldType)) { + const RecordDecl *RecDecl = RecType->getDecl(); + if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) { + if (Context.hasSameType(FieldType, AnonTy)) + break; + ++Index; + continue; + } + } + } + + return Index; +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1, + Decl *D2) { + if (!::IsStructurallyEquivalent(*this, D1, D2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1, + QualType T2) { + if (!::IsStructurallyEquivalent(*this, T1, T2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::Finish() { + while (!DeclsToCheck.empty()) { + // Check the next declaration. + Decl *D1 = DeclsToCheck.front(); + DeclsToCheck.pop_front(); + + Decl *D2 = TentativeEquivalences[D1]; + assert(D2 && "Unrecorded tentative equivalence?"); + + bool Equivalent = true; + + // FIXME: Switch on all declaration kinds. For now, we're just going to + // check the obvious ones. + if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) { + if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) { + // Check for equivalent structure names. + IdentifierInfo *Name1 = Record1->getIdentifier(); + if (!Name1 && Record1->getTypedefNameForAnonDecl()) + Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Record2->getIdentifier(); + if (!Name2 && Record2->getTypedefNameForAnonDecl()) + Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Record1, Record2)) + Equivalent = false; + } else { + // Record/non-record mismatch. + Equivalent = false; + } + } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) { + if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) { + // Check for equivalent enum names. + IdentifierInfo *Name1 = Enum1->getIdentifier(); + if (!Name1 && Enum1->getTypedefNameForAnonDecl()) + Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Enum2->getIdentifier(); + if (!Name2 && Enum2->getTypedefNameForAnonDecl()) + Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Enum1, Enum2)) + Equivalent = false; + } else { + // Enum/non-enum mismatch + Equivalent = false; + } + } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) { + if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) { + if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), + Typedef2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, Typedef1->getUnderlyingType(), + Typedef2->getUnderlyingType())) + Equivalent = false; + } else { + // Typedef/non-typedef mismatch. + Equivalent = false; + } + } else if (ClassTemplateDecl *ClassTemplate1 = + dyn_cast<ClassTemplateDecl>(D1)) { + if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) { + if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(), + ClassTemplate2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2)) + Equivalent = false; + } else { + // Class template/non-class-template mismatch. + Equivalent = false; + } + } else if (TemplateTypeParmDecl *TTP1 = + dyn_cast<TemplateTypeParmDecl>(D1)) { + if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (NonTypeTemplateParmDecl *NTTP1 = + dyn_cast<NonTypeTemplateParmDecl>(D1)) { + if (NonTypeTemplateParmDecl *NTTP2 = + dyn_cast<NonTypeTemplateParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (TemplateTemplateParmDecl *TTP1 = + dyn_cast<TemplateTemplateParmDecl>(D1)) { + if (TemplateTemplateParmDecl *TTP2 = + dyn_cast<TemplateTemplateParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } + + if (!Equivalent) { + // Note that these two declarations are not equivalent (and we already + // know about it). + NonEquivalentDecls.insert( + std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl())); + return true; + } + // FIXME: Check other declaration kinds! + } + + return false; +} +} // namespace clang diff --git a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp index cda70c5edcd4..5c2c9cbd0180 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp @@ -415,6 +415,19 @@ const Attr *Decl::getDefiningAttr() const { return nullptr; } +StringRef getRealizedPlatform(const AvailabilityAttr *A, + const ASTContext &Context) { + // Check if this is an App Extension "platform", and if so chop off + // the suffix for matching with the actual platform. + StringRef RealizedPlatform = A->getPlatform()->getName(); + if (!Context.getLangOpts().AppExt) + return RealizedPlatform; + size_t suffix = RealizedPlatform.rfind("_app_extension"); + if (suffix != StringRef::npos) + return RealizedPlatform.slice(0, suffix); + return RealizedPlatform; +} + /// \brief Determine the availability of the given declaration based on /// the target platform. /// @@ -434,20 +447,11 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, if (EnclosingVersion.empty()) return AR_Available; - // Check if this is an App Extension "platform", and if so chop off - // the suffix for matching with the actual platform. StringRef ActualPlatform = A->getPlatform()->getName(); - StringRef RealizedPlatform = ActualPlatform; - if (Context.getLangOpts().AppExt) { - size_t suffix = RealizedPlatform.rfind("_app_extension"); - if (suffix != StringRef::npos) - RealizedPlatform = RealizedPlatform.slice(0, suffix); - } - StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); // Match the platform name. - if (RealizedPlatform != TargetPlatform) + if (getRealizedPlatform(A, Context) != TargetPlatform) return AR_Available; StringRef PrettyPlatformName @@ -567,6 +571,20 @@ AvailabilityResult Decl::getAvailability(std::string *Message, return Result; } +VersionTuple Decl::getVersionIntroduced() const { + const ASTContext &Context = getASTContext(); + StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); + for (const auto *A : attrs()) { + if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) { + if (getRealizedPlatform(Availability, Context) != TargetPlatform) + continue; + if (!Availability->getIntroduced().empty()) + return Availability->getIntroduced(); + } + } + return VersionTuple(); +} + bool Decl::canBeWeakImported(bool &IsDefinition) const { IsDefinition = false; diff --git a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp index 2fafa4876758..75bb0cac51b8 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp @@ -4418,8 +4418,14 @@ private: bool HandleConditionalOperator(const ConditionalOperator *E) { bool BoolResult; if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) { - if (Info.checkingPotentialConstantExpression() && Info.noteFailure()) + if (Info.checkingPotentialConstantExpression() && Info.noteFailure()) { CheckPotentialConstantConditional(E); + return false; + } + if (Info.noteFailure()) { + StmtVisitorTy::Visit(E->getTrueExpr()); + StmtVisitorTy::Visit(E->getFalseExpr()); + } return false; } @@ -5240,14 +5246,19 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { if (E->getBase()->getType()->isVectorType()) return Error(E); - if (!evaluatePointer(E->getBase(), Result)) - return false; + bool Success = true; + if (!evaluatePointer(E->getBase(), Result)) { + if (!Info.noteFailure()) + return false; + Success = false; + } APSInt Index; if (!EvaluateInteger(E->getIdx(), Index, Info)) return false; - return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), Index); + return Success && + HandleLValueArrayAdjustment(Info, E, Result, E->getType(), Index); } bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) { @@ -5470,8 +5481,11 @@ public: bool VisitUnaryAddrOf(const UnaryOperator *E); bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return Success(E); } - bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) - { return Success(E); } + bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { + if (Info.noteFailure()) + EvaluateIgnoredValue(Info, E->getSubExpr()); + return Error(E); + } bool VisitAddrLabelExpr(const AddrLabelExpr *E) { return Success(E); } bool VisitCallExpr(const CallExpr *E); @@ -6203,6 +6217,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // the initializer list. ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE; + if (Init->isValueDependent()) { + Success = false; + continue; + } // Temporarily override This, in case there's a CXXDefaultInitExpr in here. ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, @@ -9913,7 +9931,8 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { } static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, - const ASTContext &Ctx, bool &IsConst) { + const ASTContext &Ctx, bool &IsConst, + bool IsCheckingForOverflow) { // Fast-path evaluations of integer literals, since we sometimes see files // containing vast quantities of these. if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(Exp)) { @@ -9934,7 +9953,7 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, // performance problems. Only do so in C++11 for now. if (Exp->isRValue() && (Exp->getType()->isArrayType() || Exp->getType()->isRecordType()) && - !Ctx.getLangOpts().CPlusPlus11) { + !Ctx.getLangOpts().CPlusPlus11 && !IsCheckingForOverflow) { IsConst = false; return true; } @@ -9949,7 +9968,7 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, /// will be applied to the result. bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { bool IsConst; - if (FastEvaluateAsRValue(this, Result, Ctx, IsConst)) + if (FastEvaluateAsRValue(this, Result, Ctx, IsConst, false)) return IsConst; EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); @@ -10074,7 +10093,7 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, void Expr::EvaluateForOverflow(const ASTContext &Ctx) const { bool IsConst; EvalResult EvalResult; - if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) { + if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst, true)) { EvalInfo Info(Ctx, EvalResult, EvalInfo::EM_EvaluateForOverflow); (void)::EvaluateAsRValue(Info, this, EvalResult.Val); } diff --git a/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp b/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp index d72eebbe8e48..83168d0924f6 100644 --- a/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp @@ -169,6 +169,11 @@ public: Inherited::VisitValueDecl(D); } + void VisitParmVarDecl(const ParmVarDecl *D) { + // TODO: Handle default arguments. + Inherited::VisitParmVarDecl(D); + } + void VisitAccessSpecDecl(const AccessSpecDecl *D) { ID.AddInteger(D->getAccess()); Inherited::VisitAccessSpecDecl(D); @@ -202,6 +207,12 @@ public: Hash.AddBoolean(D->isPure()); Hash.AddBoolean(D->isDeletedAsWritten()); + ID.AddInteger(D->param_size()); + + for (auto *Param : D->parameters()) { + Hash.AddSubDecl(Param); + } + Inherited::VisitFunctionDecl(D); } @@ -256,6 +267,11 @@ void ODRHash::AddSubDecl(const Decl *D) { void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) { assert(Record && Record->hasDefinition() && "Expected non-null record to be a definition."); + + if (isa<ClassTemplateSpecializationDecl>(Record)) { + return; + } + AddDecl(Record); // Filter out sub-Decls which will not be processed in order to get an @@ -315,6 +331,14 @@ public: } } + void AddQualType(QualType T) { + Hash.AddQualType(T); + } + + void VisitQualifiers(Qualifiers Quals) { + ID.AddInteger(Quals.getAsOpaqueValue()); + } + void Visit(const Type *T) { ID.AddInteger(T->getTypeClass()); Inherited::Visit(T); @@ -322,11 +346,69 @@ public: void VisitType(const Type *T) {} + void VisitAdjustedType(const AdjustedType *T) { + AddQualType(T->getOriginalType()); + AddQualType(T->getAdjustedType()); + VisitType(T); + } + + void VisitDecayedType(const DecayedType *T) { + AddQualType(T->getDecayedType()); + AddQualType(T->getPointeeType()); + VisitAdjustedType(T); + } + + void VisitArrayType(const ArrayType *T) { + AddQualType(T->getElementType()); + ID.AddInteger(T->getSizeModifier()); + VisitQualifiers(T->getIndexTypeQualifiers()); + VisitType(T); + } + void VisitConstantArrayType(const ConstantArrayType *T) { + T->getSize().Profile(ID); + VisitArrayType(T); + } + + void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { + AddStmt(T->getSizeExpr()); + VisitArrayType(T); + } + + void VisitIncompleteArrayType(const IncompleteArrayType *T) { + VisitArrayType(T); + } + + void VisitVariableArrayType(const VariableArrayType *T) { + AddStmt(T->getSizeExpr()); + VisitArrayType(T); + } + void VisitBuiltinType(const BuiltinType *T) { ID.AddInteger(T->getKind()); VisitType(T); } + void VisitFunctionType(const FunctionType *T) { + AddQualType(T->getReturnType()); + T->getExtInfo().Profile(ID); + Hash.AddBoolean(T->isConst()); + Hash.AddBoolean(T->isVolatile()); + Hash.AddBoolean(T->isRestrict()); + VisitType(T); + } + + void VisitFunctionNoProtoType(const FunctionNoProtoType *T) { + VisitFunctionType(T); + } + + void VisitFunctionProtoType(const FunctionProtoType *T) { + ID.AddInteger(T->getNumParams()); + for (auto ParamType : T->getParamTypes()) + AddQualType(ParamType); + + VisitFunctionType(T); + } + void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); Hash.AddQualType(T->getDecl()->getUnderlyingType()); diff --git a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp index 5268a2901ad9..2be14ab62123 100644 --- a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp @@ -750,6 +750,8 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, if (Info.getRegParm()) OS << " __attribute__((regparm (" << Info.getRegParm() << ")))"; + if (Info.getNoCallerSavedRegs()) + OS << "__attribute__((no_caller_saved_registers))"; if (unsigned quals = T->getTypeQuals()) { OS << ' '; diff --git a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp index 350d5477751c..6bdef78c074f 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp @@ -67,18 +67,12 @@ DiagnosticsEngine::DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> diags, ArgToStringCookie = nullptr; AllExtensionsSilenced = 0; - IgnoreAllWarnings = false; - WarningsAsErrors = false; - EnableAllWarnings = false; - ErrorsAsFatal = false; - FatalsAsError = false; - SuppressSystemWarnings = false; + SuppressAfterFatalError = true; SuppressAllDiagnostics = false; ElideType = true; PrintTemplateTree = false; ShowColors = false; ShowOverloads = Ovl_All; - ExtBehavior = diag::Severity::Ignored; ErrorLimit = 0; TemplateBacktraceLimit = 0; @@ -343,8 +337,8 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group, return setSeverityForGroup(diag::Flavor::WarningOrError, Group, diag::Severity::Fatal); - // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and - // potentially downgrade anything already mapped to be an error. + // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit, + // and potentially downgrade anything already mapped to be a fatal error. // Get the diagnostics in this group. SmallVector<diag::kind, 8> GroupDiags; diff --git a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp index e0580af45b50..2852b40026c2 100644 --- a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp @@ -420,7 +420,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, Result = Mapping.getSeverity(); // Upgrade ignored diagnostics if -Weverything is enabled. - if (Diag.EnableAllWarnings && Result == diag::Severity::Ignored && + if (State->EnableAllWarnings && Result == diag::Severity::Ignored && !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK) Result = diag::Severity::Warning; @@ -435,7 +435,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, // For extension diagnostics that haven't been explicitly mapped, check if we // should upgrade the diagnostic. if (IsExtensionDiag && !Mapping.isUser()) - Result = std::max(Result, Diag.ExtBehavior); + Result = std::max(Result, State->ExtBehavior); // At this point, ignored errors can no longer be upgraded. if (Result == diag::Severity::Ignored) @@ -443,28 +443,24 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, // Honor -w, which is lower in priority than pedantic-errors, but higher than // -Werror. - if (Result == diag::Severity::Warning && Diag.IgnoreAllWarnings) + // FIXME: Under GCC, this also suppresses warnings that have been mapped to + // errors by -W flags and #pragma diagnostic. + if (Result == diag::Severity::Warning && State->IgnoreAllWarnings) return diag::Severity::Ignored; // If -Werror is enabled, map warnings to errors unless explicitly disabled. if (Result == diag::Severity::Warning) { - if (Diag.WarningsAsErrors && !Mapping.hasNoWarningAsError()) + if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError()) Result = diag::Severity::Error; } // If -Wfatal-errors is enabled, map errors to fatal unless explicity // disabled. if (Result == diag::Severity::Error) { - if (Diag.ErrorsAsFatal && !Mapping.hasNoErrorAsFatal()) + if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal()) Result = diag::Severity::Fatal; } - // If explicitly requested, map fatal errors to errors. - if (Result == diag::Severity::Fatal) { - if (Diag.FatalsAsError) - Result = diag::Severity::Error; - } - // Custom diagnostics always are emitted in system headers. bool ShowInSystemHeader = !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader; @@ -472,7 +468,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, // If we are in a system header, we ignore it. We look at the diagnostic class // because we also want to ignore extensions and warnings in -Werror and // -pedantic-errors modes, which *map* warnings/extensions to errors. - if (Diag.SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() && + if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() && Diag.getSourceManager().isInSystemHeader( Diag.getSourceManager().getExpansionLoc(Loc))) return diag::Severity::Ignored; @@ -632,7 +628,7 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const { // If a fatal error has already been emitted, silence all subsequent // diagnostics. - if (Diag.FatalErrorOccurred) { + if (Diag.FatalErrorOccurred && Diag.SuppressAfterFatalError) { if (DiagLevel >= DiagnosticIDs::Error && Diag.Client->IncludeInDiagnosticCounts()) { ++Diag.NumErrors; diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp index d7f1793e377c..78b03b1c314a 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp @@ -117,6 +117,7 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, VersionTuple &PlatformMinVersion) { Builder.defineMacro("__APPLE_CC__", "6000"); Builder.defineMacro("__APPLE__"); + Builder.defineMacro("__STDC_NO_THREADS__"); Builder.defineMacro("OBJC_NEW_PROPERTIES"); // AddressSanitizer doesn't play well with source fortification, which is on // by default on Darwin. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp index 85788b427208..03883805199f 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp @@ -35,7 +35,6 @@ #include "llvm/LTO/LTOBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/Object/ModuleSummaryIndexObjectFile.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp index 1a57b3e6608d..791a57e61f53 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp @@ -619,7 +619,13 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { // Block captures count as local values and have imprecise semantics. // They also can't be arrays, so need to worry about that. - if (dtorKind == QualType::DK_objc_strong_lifetime) { + // + // For const-qualified captures, emit clang.arc.use to ensure the captured + // object doesn't get released while we are still depending on its validity + // within the block. + if (VT.isConstQualified() && VT.getObjCLifetime() == Qualifiers::OCL_Strong) + destroyer = CodeGenFunction::emitARCIntrinsicUse; + else if (dtorKind == QualType::DK_objc_strong_lifetime) { destroyer = CodeGenFunction::destroyARCStrongImprecise; } else { destroyer = CGF.getDestroyer(dtorKind); @@ -866,6 +872,12 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { } else if (type->isReferenceType()) { Builder.CreateStore(src.getPointer(), blockField); + // If type is const-qualified, copy the value into the block field. + } else if (type.isConstQualified() && + type.getObjCLifetime() == Qualifiers::OCL_Strong) { + llvm::Value *value = Builder.CreateLoad(src, "captured"); + Builder.CreateStore(value, blockField); + // If this is an ARC __strong block-pointer variable, don't do a // block copy. // diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp index 26235257b19d..c677d9887acc 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp @@ -788,6 +788,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, FI->ChainCall = chainCall; FI->NoReturn = info.getNoReturn(); FI->ReturnsRetained = info.getProducesResult(); + FI->NoCallerSavedRegs = info.getNoCallerSavedRegs(); FI->Required = required; FI->HasRegParm = info.getHasRegParm(); FI->RegParm = info.getRegParm(); @@ -1755,9 +1756,7 @@ void CodeGenModule::AddDefaultFnAttrs(llvm::Function &F) { ConstructDefaultFnAttrList(F.getName(), F.hasFnAttribute(llvm::Attribute::OptimizeNone), /* AttrOnCallsite = */ false, FuncAttrs); - llvm::AttributeList AS = llvm::AttributeList::get( - getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs); - F.addAttributes(llvm::AttributeList::FunctionIndex, AS); + F.addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs); } void CodeGenModule::ConstructAttributeList( @@ -1816,6 +1815,8 @@ void CodeGenModule::ConstructAttributeList( RetAttrs.addAttribute(llvm::Attribute::NoAlias); if (TargetDecl->hasAttr<ReturnsNonNullAttr>()) RetAttrs.addAttribute(llvm::Attribute::NonNull); + if (TargetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>()) + FuncAttrs.addAttribute("no_caller_saved_registers"); HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>(); if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp index dd32a44393c6..3e5434660567 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp @@ -4034,11 +4034,9 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) { if (I != NameSpaceCache.end()) return cast<llvm::DINamespace>(I->second); - unsigned LineNo = getLineNumber(NSDecl->getLocation()); - llvm::DIFile *FileD = getOrCreateFile(NSDecl->getLocation()); llvm::DIScope *Context = getDeclContextDescriptor(NSDecl); - llvm::DINamespace *NS = DBuilder.createNameSpace( - Context, NSDecl->getName(), FileD, LineNo, NSDecl->isInline()); + llvm::DINamespace *NS = + DBuilder.createNameSpace(Context, NSDecl->getName(), NSDecl->isInline()); NameSpaceCache[NSDecl].reset(NS); return NS; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp index f61d60a63a6a..ff766e6b3b9c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp @@ -571,9 +571,10 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, FinishFunction(); } -void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn, - const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> > - &DtorsAndObjects) { +void CodeGenFunction::GenerateCXXGlobalDtorsFunc( + llvm::Function *Fn, + const std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>> + &DtorsAndObjects) { { auto NL = ApplyDebugLocation::CreateEmpty(*this); StartFunction(GlobalDecl(), getContext().VoidTy, Fn, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp index d0aacf65428f..863b4380da47 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp @@ -4065,6 +4065,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { RValue RV = EmitAnyExpr(E->getRHS()); LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); + if (RV.isScalar()) + EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc()); EmitStoreThroughLValue(RV, LV); return LV; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp index a64303831171..70b741651fd1 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp @@ -51,6 +51,64 @@ struct BinOpInfo { BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform FPOptions FPFeatures; const Expr *E; // Entire expr, for error unsupported. May not be binop. + + /// Check if the binop can result in integer overflow. + bool mayHaveIntegerOverflow() const { + // Without constant input, we can't rule out overflow. + const auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS); + const auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS); + if (!LHSCI || !RHSCI) + return true; + + // Assume overflow is possible, unless we can prove otherwise. + bool Overflow = true; + const auto &LHSAP = LHSCI->getValue(); + const auto &RHSAP = RHSCI->getValue(); + if (Opcode == BO_Add) { + if (Ty->hasSignedIntegerRepresentation()) + (void)LHSAP.sadd_ov(RHSAP, Overflow); + else + (void)LHSAP.uadd_ov(RHSAP, Overflow); + } else if (Opcode == BO_Sub) { + if (Ty->hasSignedIntegerRepresentation()) + (void)LHSAP.ssub_ov(RHSAP, Overflow); + else + (void)LHSAP.usub_ov(RHSAP, Overflow); + } else if (Opcode == BO_Mul) { + if (Ty->hasSignedIntegerRepresentation()) + (void)LHSAP.smul_ov(RHSAP, Overflow); + else + (void)LHSAP.umul_ov(RHSAP, Overflow); + } else if (Opcode == BO_Div || Opcode == BO_Rem) { + if (Ty->hasSignedIntegerRepresentation() && !RHSCI->isZero()) + (void)LHSAP.sdiv_ov(RHSAP, Overflow); + else + return false; + } + return Overflow; + } + + /// Check if the binop computes a division or a remainder. + bool isDivisionLikeOperation() const { + return Opcode == BO_Div || Opcode == BO_Rem || Opcode == BO_DivAssign || + Opcode == BO_RemAssign; + } + + /// Check if the binop can result in an integer division by zero. + bool mayHaveIntegerDivisionByZero() const { + if (isDivisionLikeOperation()) + if (auto *CI = dyn_cast<llvm::ConstantInt>(RHS)) + return CI->isZero(); + return true; + } + + /// Check if the binop can result in a float division by zero. + bool mayHaveFloatDivisionByZero() const { + if (isDivisionLikeOperation()) + if (auto *CFP = dyn_cast<llvm::ConstantFP>(RHS)) + return CFP->isZero(); + return true; + } }; static bool MustVisitNullValue(const Expr *E) { @@ -85,9 +143,17 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) { assert((isa<UnaryOperator>(Op.E) || isa<BinaryOperator>(Op.E)) && "Expected a unary or binary operator"); + // If the binop has constant inputs and we can prove there is no overflow, + // we can elide the overflow check. + if (!Op.mayHaveIntegerOverflow()) + return true; + + // If a unary op has a widened operand, the op cannot overflow. if (const auto *UO = dyn_cast<UnaryOperator>(Op.E)) return IsWidenedIntegerOp(Ctx, UO->getSubExpr()); + // We usually don't need overflow checks for binops with widened operands. + // Multiplication with promoted unsigned operands is a special case. const auto *BO = cast<BinaryOperator>(Op.E); auto OptionalLHSTy = getUnwidenedIntegerType(Ctx, BO->getLHS()); if (!OptionalLHSTy) @@ -100,14 +166,14 @@ static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) { QualType LHSTy = *OptionalLHSTy; QualType RHSTy = *OptionalRHSTy; - // We usually don't need overflow checks for binary operations with widened - // operands. Multiplication with promoted unsigned operands is a special case. + // This is the simple case: binops without unsigned multiplication, and with + // widened operands. No overflow check is needed here. if ((Op.Opcode != BO_Mul && Op.Opcode != BO_MulAssign) || !LHSTy->isUnsignedIntegerType() || !RHSTy->isUnsignedIntegerType()) return true; - // The overflow check can be skipped if either one of the unpromoted types - // are less than half the size of the promoted type. + // For unsigned multiplication the overflow check can be elided if either one + // of the unpromoted types are less than half the size of the promoted type. unsigned PromotedSize = Ctx.getTypeSize(Op.E->getType()); return (2 * Ctx.getTypeSize(LHSTy)) < PromotedSize || (2 * Ctx.getTypeSize(RHSTy)) < PromotedSize; @@ -2377,7 +2443,8 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( const auto *BO = cast<BinaryOperator>(Ops.E); if (CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) && Ops.Ty->hasSignedIntegerRepresentation() && - !IsWidenedIntegerOp(CGF.getContext(), BO->getLHS())) { + !IsWidenedIntegerOp(CGF.getContext(), BO->getLHS()) && + Ops.mayHaveIntegerOverflow()) { llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType()); llvm::Value *IntMin = @@ -2400,11 +2467,13 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { CodeGenFunction::SanitizerScope SanScope(&CGF); if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) && - Ops.Ty->isIntegerType()) { + Ops.Ty->isIntegerType() && + (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) { llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true); } else if (CGF.SanOpts.has(SanitizerKind::FloatDivideByZero) && - Ops.Ty->isRealFloatingType()) { + Ops.Ty->isRealFloatingType() && + Ops.mayHaveFloatDivisionByZero()) { llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); llvm::Value *NonZero = Builder.CreateFCmpUNE(Ops.RHS, Zero); EmitBinOpCheck(std::make_pair(NonZero, SanitizerKind::FloatDivideByZero), @@ -2439,7 +2508,8 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { // Rem in C can't be a floating point type: C99 6.5.5p2. if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) && - Ops.Ty->isIntegerType()) { + Ops.Ty->isIntegerType() && + (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) { CodeGenFunction::SanitizerScope SanScope(&CGF); llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp index 76e7df861f74..f4fbab3c2b83 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp @@ -2415,6 +2415,12 @@ void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF, CGF.EmitARCDestroyWeak(addr); } +void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr, + QualType type) { + llvm::Value *value = CGF.Builder.CreateLoad(addr); + CGF.EmitARCIntrinsicUse(value); +} + namespace { struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup { llvm::Value *Token; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp index 9f6ccb4b5d26..821629c50d4a 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp @@ -663,7 +663,7 @@ class CGObjCGNUstep : public CGObjCGNU { } // The lookup function is guaranteed not to capture the receiver pointer. - LookupFn->setDoesNotCapture(1); + LookupFn->addParamAttr(0, llvm::Attribute::NoCapture); llvm::Value *args[] = { EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy), diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp index 43b347ce353f..70d24b791334 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp @@ -886,7 +886,7 @@ protected: /// Cached reference to the class for constant strings. This value has type /// int * but is actually an Obj-C class pointer. - llvm::WeakVH ConstantStringClassRef; + llvm::WeakTrackingVH ConstantStringClassRef; /// \brief The LLVM type corresponding to NSConstantString. llvm::StructType *NSConstantStringType = nullptr; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp index f738dd0750fa..19b6cbab66c9 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -1675,7 +1675,7 @@ static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF, CodeGenFunction::JumpDest LoopExit) { CGF.EmitOMPLoopBody(S, LoopExit); CGF.EmitStopPoint(&S); -}; +} void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { @@ -2093,7 +2093,7 @@ emitDistributeParallelForDispatchBounds(CodeGenFunction &CGF, llvm::Value *UBVal = CGF.EmitLoadOfScalar(UB, /*Volatile=*/false, IteratorTy, SourceLocation()); return {LBVal, UBVal}; -}; +} static void emitDistributeParallelForDistributeInnerBoundParams( CodeGenFunction &CGF, const OMPExecutableDirective &S, @@ -2110,7 +2110,7 @@ static void emitDistributeParallelForDistributeInnerBoundParams( auto UBCast = CGF.Builder.CreateIntCast( CGF.Builder.CreateLoad(UB.getAddress()), CGF.SizeTy, /*isSigned=*/false); CapturedVars.push_back(UBCast); -}; +} static void emitInnerParallelForWhenCombined(CodeGenFunction &CGF, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp index b864069dc645..f57cbe86c413 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp @@ -944,7 +944,7 @@ std::unique_ptr<llvm::Module> CodeGenAction::loadModule(MemoryBufferRef MBRef) { void CodeGenAction::ExecuteAction() { // If this is an IR file, we have to treat it specially. - if (getCurrentFileKind() == IK_LLVM_IR) { + if (getCurrentFileKind().getLanguage() == InputKind::LLVM_IR) { BackendAction BA = static_cast<BackendAction>(Act); CompilerInstance &CI = getCompilerInstance(); std::unique_ptr<raw_pwrite_stream> OS = diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h index 1ded824ba5b0..b69640894f11 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h @@ -3369,6 +3369,7 @@ public: static Destroyer destroyARCStrongImprecise; static Destroyer destroyARCStrongPrecise; static Destroyer destroyARCWeak; + static Destroyer emitARCIntrinsicUse; void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr); llvm::Value *EmitObjCAutoreleasePoolPush(); @@ -3470,9 +3471,10 @@ public: /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global /// variables. - void GenerateCXXGlobalDtorsFunc(llvm::Function *Fn, - const std::vector<std::pair<llvm::WeakVH, - llvm::Constant*> > &DtorsAndObjects); + void GenerateCXXGlobalDtorsFunc( + llvm::Function *Fn, + const std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>> + &DtorsAndObjects); void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp index 25d32f19d0e5..ff26d80fe2b6 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp @@ -369,9 +369,13 @@ void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags, if (MainFile.empty()) MainFile = "<stdin>"; Diags.Report(diag::warn_profile_data_unprofiled) << MainFile; - } else - Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Missing - << Mismatched; + } else { + if (Mismatched > 0) + Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Mismatched; + + if (Missing > 0) + Diags.Report(diag::warn_profile_data_missing) << Visited << Missing; + } } void CodeGenModule::Release() { @@ -888,10 +892,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) B.addAttribute(llvm::Attribute::NoInline); - F->addAttributes( - llvm::AttributeList::FunctionIndex, - llvm::AttributeList::get(F->getContext(), - llvm::AttributeList::FunctionIndex, B)); + F->addAttributes(llvm::AttributeList::FunctionIndex, B); return; } @@ -957,9 +958,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, B.addAttribute(llvm::Attribute::MinSize); } - F->addAttributes(llvm::AttributeList::FunctionIndex, - llvm::AttributeList::get( - F->getContext(), llvm::AttributeList::FunctionIndex, B)); + F->addAttributes(llvm::AttributeList::FunctionIndex, B); unsigned alignment = D->getMaxAlignment() / Context.getCharWidth(); if (alignment) @@ -1150,7 +1149,7 @@ void CodeGenModule::addCompilerUsedGlobal(llvm::GlobalValue *GV) { } static void emitUsed(CodeGenModule &CGM, StringRef Name, - std::vector<llvm::WeakVH> &List) { + std::vector<llvm::WeakTrackingVH> &List) { // Don't create llvm.used if there is no need. if (List.empty()) return; @@ -1324,13 +1323,10 @@ void CodeGenModule::EmitDeferred() { // Grab the list of decls to emit. If EmitGlobalDefinition schedules more // work, it will not interfere with this. - std::vector<DeferredGlobal> CurDeclsToEmit; + std::vector<GlobalDecl> CurDeclsToEmit; CurDeclsToEmit.swap(DeferredDeclsToEmit); - for (DeferredGlobal &G : CurDeclsToEmit) { - GlobalDecl D = G.GD; - G.GV = nullptr; - + for (GlobalDecl &D : CurDeclsToEmit) { // We should call GetAddrOfGlobal with IsForDefinition set to true in order // to get GlobalValue with exactly the type we need, not something that // might had been created for another decl with the same mangled name but @@ -1707,13 +1703,13 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { } StringRef MangledName = getMangledName(GD); - if (llvm::GlobalValue *GV = GetGlobalValue(MangledName)) { + if (GetGlobalValue(MangledName) != nullptr) { // The value has already been used and should therefore be emitted. - addDeferredDeclToEmit(GV, GD); + addDeferredDeclToEmit(GD); } else if (MustBeEmitted(Global)) { // The value must be emitted, but cannot be emitted eagerly. assert(!MayBeEmittedEagerly(Global)); - addDeferredDeclToEmit(/*GV=*/nullptr, GD); + addDeferredDeclToEmit(GD); } else { // Otherwise, remember that we saw a deferred decl with this name. The // first use of the mangled name will cause it to move into @@ -2028,9 +2024,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk); if (ExtraAttrs.hasAttributes(llvm::AttributeList::FunctionIndex)) { llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex); - F->addAttributes(llvm::AttributeList::FunctionIndex, - llvm::AttributeList::get( - VMContext, llvm::AttributeList::FunctionIndex, B)); + F->addAttributes(llvm::AttributeList::FunctionIndex, B); } if (!DontDefer) { @@ -2040,7 +2034,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( if (D && isa<CXXDestructorDecl>(D) && getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D), GD.getDtorType())) - addDeferredDeclToEmit(F, GD); + addDeferredDeclToEmit(GD); // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end @@ -2050,7 +2044,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( // Move the potentially referenced deferred decl to the // DeferredDeclsToEmit list, and remove it from DeferredDecls (since we // don't need it anymore). - addDeferredDeclToEmit(F, DDI->second); + addDeferredDeclToEmit(DDI->second); DeferredDecls.erase(DDI); // Otherwise, there are cases we have to worry about where we're @@ -2070,7 +2064,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( FD = FD->getPreviousDecl()) { if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) { if (FD->doesThisDeclarationHaveABody()) { - addDeferredDeclToEmit(F, GD.getWithDecl(FD)); + addDeferredDeclToEmit(GD.getWithDecl(FD)); break; } } @@ -2298,7 +2292,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the DeferredDeclsToEmit // list, and remove it from DeferredDecls (since we don't need it anymore). - addDeferredDeclToEmit(GV, DDI->second); + addDeferredDeclToEmit(DDI->second); DeferredDecls.erase(DDI); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h index c4985ba41db1..e38337814ebc 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h @@ -315,14 +315,9 @@ private: /// This is a list of deferred decls which we have seen that *are* actually /// referenced. These get code generated when the module is done. - struct DeferredGlobal { - DeferredGlobal(llvm::GlobalValue *GV, GlobalDecl GD) : GV(GV), GD(GD) {} - llvm::TrackingVH<llvm::GlobalValue> GV; - GlobalDecl GD; - }; - std::vector<DeferredGlobal> DeferredDeclsToEmit; - void addDeferredDeclToEmit(llvm::GlobalValue *GV, GlobalDecl GD) { - DeferredDeclsToEmit.emplace_back(GV, GD); + std::vector<GlobalDecl> DeferredDeclsToEmit; + void addDeferredDeclToEmit(GlobalDecl GD) { + DeferredDeclsToEmit.emplace_back(GD); } /// List of alias we have emitted. Used to make sure that what they point to @@ -349,8 +344,8 @@ private: /// List of global values which are required to be present in the object file; /// bitcast to i8*. This is used for forcing visibility of symbols which may /// otherwise be optimized out. - std::vector<llvm::WeakVH> LLVMUsed; - std::vector<llvm::WeakVH> LLVMCompilerUsed; + std::vector<llvm::WeakTrackingVH> LLVMUsed; + std::vector<llvm::WeakTrackingVH> LLVMCompilerUsed; /// Store the list of global constructors and their respective priorities to /// be emitted when the translation unit is complete. @@ -421,7 +416,7 @@ private: SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits; /// Global destructor functions and arguments that need to run on termination. - std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors; + std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>> CXXGlobalDtors; /// \brief The complete set of modules that has been imported. llvm::SetVector<clang::Module *> ImportedModules; @@ -438,7 +433,7 @@ private: /// Cached reference to the class for constant strings. This value has type /// int * but is actually an Obj-C class pointer. - llvm::WeakVH CFConstantStringClassRef; + llvm::WeakTrackingVH CFConstantStringClassRef; /// \brief The type used to describe the state of a fast enumeration in /// Objective-C's for..in loop. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp b/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp index acea5c1143cf..6a31dfe53d64 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp @@ -198,7 +198,8 @@ void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok, } void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(), diff --git a/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h b/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h index 06217f9c5883..e117f96f47df 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h @@ -110,8 +110,8 @@ public: /// Hook called whenever a macro \#undef is seen. /// /// MD is released immediately following this callback. - void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) override; + void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, + const MacroDirective *Undef) override; }; } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp index 94c3880ea26e..ecd81d84b1fa 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp @@ -1901,10 +1901,7 @@ void X86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D, // Now add the 'alignstack' attribute with a value of 16. llvm::AttrBuilder B; B.addStackAlignmentAttr(16); - Fn->addAttributes( - llvm::AttributeList::FunctionIndex, - llvm::AttributeList::get(CGM.getLLVMContext(), - llvm::AttributeList::FunctionIndex, B)); + Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); } if (FD->hasAttr<AnyX86InterruptAttr>()) { llvm::Function *Fn = cast<llvm::Function>(GV); @@ -5449,10 +5446,7 @@ public: // the backend to perform a realignment as part of the function prologue. llvm::AttrBuilder B; B.addStackAlignmentAttr(8); - Fn->addAttributes( - llvm::AttributeList::FunctionIndex, - llvm::AttributeList::get(CGM.getLLVMContext(), - llvm::AttributeList::FunctionIndex, B)); + Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); } }; diff --git a/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp index 7a4d055159ec..8b85680f10b1 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Job.cpp @@ -49,7 +49,7 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum, // arguments. Therefore, we need to skip the flag and the next argument. bool ShouldSkip = llvm::StringSwitch<bool>(Flag) .Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true) - .Cases("-o", "-coverage-file", "-dependency-file", true) + .Cases("-o", "-dependency-file", true) .Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true) .Cases("-dwarf-debug-flags", "-ivfsoverlay", true) .Default(false); diff --git a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp index c9561367a3a8..4dd4929c9148 100644 --- a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp @@ -511,7 +511,6 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, << "-fsanitize-coverage=edge"; // Basic block tracing and 8-bit counters require some type of coverage // enabled. - int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge; if (CoverageFeatures & CoverageTraceBB) D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=trace-bb" @@ -520,9 +519,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=8bit-counters" << "-fsanitize-coverage=trace-pc-guard"; + + int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; + if ((CoverageFeatures & InsertionPointTypes) && + !(CoverageFeatures &(CoverageTracePC | CoverageTracePCGuard))) { + D.Diag(clang::diag::warn_drv_deprecated_arg) + << "-fsanitize-coverage=[func|bb|edge]" + << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; + } + // trace-pc w/o func/bb/edge implies edge. if ((CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard)) && - !(CoverageFeatures & CoverageTypes)) + !(CoverageFeatures & InsertionPointTypes)) CoverageFeatures |= CoverageEdge; if (AllAddedKinds & Address) { diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp index 6e1e4ccf44f0..555847aeeb23 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp @@ -2773,12 +2773,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -gsplit-dwarf should turn on -g and enable the backend dwarf // splitting and extraction. // FIXME: Currently only works on Linux. - if (getToolChain().getTriple().isOSLinux() && SplitDwarfArg) { + if (getToolChain().getTriple().isOSLinux()) { if (!splitDwarfInlining) CmdArgs.push_back("-fno-split-dwarf-inlining"); - if (DebugInfoKind == codegenoptions::NoDebugInfo) - DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-enable-split-dwarf"); + if (SplitDwarfArg) { + if (DebugInfoKind == codegenoptions::NoDebugInfo) + DebugInfoKind = codegenoptions::LimitedDebugInfo; + CmdArgs.push_back("-enable-split-dwarf"); + } } // After we've dealt with all combinations of things that could diff --git a/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp b/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp index 5292a58a9ccd..1a7a68cffb62 100644 --- a/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp +++ b/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp @@ -363,13 +363,14 @@ static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts, static void applyRewrite(EditsReceiver &receiver, StringRef text, FileOffset offs, unsigned len, - const SourceManager &SM, const LangOptions &LangOpts) { + const SourceManager &SM, const LangOptions &LangOpts, + bool shouldAdjustRemovals) { assert(offs.getFID().isValid()); SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID()); Loc = Loc.getLocWithOffset(offs.getOffset()); assert(Loc.isFileID()); - if (text.empty()) + if (text.empty() && shouldAdjustRemovals) adjustRemoval(SM, LangOpts, Loc, offs, len, text); CharSourceRange range = CharSourceRange::getCharRange(Loc, @@ -387,7 +388,8 @@ static void applyRewrite(EditsReceiver &receiver, receiver.insert(Loc, text); } -void EditedSource::applyRewrites(EditsReceiver &receiver) { +void EditedSource::applyRewrites(EditsReceiver &receiver, + bool shouldAdjustRemovals) { SmallString<128> StrVec; FileOffset CurOffs, CurEnd; unsigned CurLen; @@ -414,14 +416,16 @@ void EditedSource::applyRewrites(EditsReceiver &receiver) { continue; } - applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts); + applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts, + shouldAdjustRemovals); CurOffs = offs; StrVec = act.Text; CurLen = act.RemoveLen; CurEnd = CurOffs.getWithOffset(CurLen); } - applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts); + applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts, + shouldAdjustRemovals); } void EditedSource::clearRewrites() { diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp index 5be68ad5c6b8..2d788b52dfda 100644 --- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp +++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp @@ -1040,13 +1040,15 @@ void UnwrappedLineParser::parseStructuralElement() { return; } - // Parse function literal unless 'function' is the first token in a line - // in which case this should be treated as a free-standing function. + // Function declarations (as opposed to function expressions) are parsed + // on their own unwrapped line by continuing this loop. Function + // expressions (functions that are not on their own line) must not create + // a new unwrapped line, so they are special cased below. + size_t TokenCount = Line->Tokens.size(); if (Style.Language == FormatStyle::LK_JavaScript && - (FormatTok->is(Keywords.kw_function) || - FormatTok->startsSequence(Keywords.kw_async, - Keywords.kw_function)) && - Line->Tokens.size() > 0) { + FormatTok->is(Keywords.kw_function) && + (TokenCount > 1 || (TokenCount == 1 && !Line->Tokens.front().Tok->is( + Keywords.kw_async)))) { tryToParseJSFunction(); break; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp index 2acdc6494f85..32ee9d3e9961 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp @@ -1076,9 +1076,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps, assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && "IR inputs not support here!"); // Configure the various subsystems. @@ -1552,9 +1554,11 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && "IR inputs not support here!"); // Clear out old caches and data. @@ -1810,10 +1814,12 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && - "IR inputs not supported here!"); + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && + "IR inputs not support here!"); // Configure the various subsystems. AST->TheSema.reset(); @@ -2399,11 +2405,12 @@ void ASTUnit::CodeComplete( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && "IR inputs not support here!"); - // Use the source and file managers that we were given. Clang->setFileManager(&FileMgr); diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp index 8b4b16920668..a7b5fa7dfd29 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -858,7 +858,8 @@ bool CompilerInstance::InitializeSourceManager( /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr, - /*SuggestedModule=*/nullptr, /*SkipCache=*/true); + /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, + /*SkipCache=*/true); // Also add the header to /showIncludes output. if (File) DepOpts.ShowIncludesPretendHeader = File->getName(); @@ -1015,14 +1016,14 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { /// \brief Determine the appropriate source input kind based on language /// options. -static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) { +static InputKind::Language getLanguageFromOptions(const LangOptions &LangOpts) { if (LangOpts.OpenCL) - return IK_OpenCL; + return InputKind::OpenCL; if (LangOpts.CUDA) - return IK_CUDA; + return InputKind::CUDA; if (LangOpts.ObjC1) - return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC; - return LangOpts.CPlusPlus? IK_CXX : IK_C; + return LangOpts.CPlusPlus ? InputKind::ObjCXX : InputKind::ObjC; + return LangOpts.CPlusPlus ? InputKind::CXX : InputKind::C; } /// \brief Compile a module file for the given module, using the options @@ -1079,10 +1080,13 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, FrontendOpts.DisableFree = false; FrontendOpts.GenerateGlobalModuleIndex = false; FrontendOpts.BuildingImplicitModule = true; + FrontendOpts.OriginalModuleMap = + ModMap.getModuleMapFileForUniquing(Module)->getName(); // Force implicitly-built modules to hash the content of the module file. HSOpts.ModulesHashContent = true; FrontendOpts.Inputs.clear(); - InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts()); + InputKind IK(getLanguageFromOptions(*Invocation->getLangOpts()), + InputKind::ModuleMap); // Don't free the remapped file buffers; they are owned by our caller. PPOpts.RetainRemappedFileBuffers = true; @@ -1127,11 +1131,12 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, if (const FileEntry *ModuleMapFile = ModMap.getContainingModuleMapFile(Module)) { // Use the module map where this module resides. - FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK); + FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK, + +Module->IsSystem); } else { SmallString<128> FakeModuleMapFile(Module->Directory->getName()); llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map"); - FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK); + FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK, +Module->IsSystem); llvm::raw_string_ostream OS(InferredModuleMapContent); Module->print(OS); @@ -1144,11 +1149,6 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer)); } - // Construct a module-generating action. Passing through the module map is - // safe because the FileManager is shared between the compiler instances. - GenerateModuleFromModuleMapAction CreateModuleAction( - ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem); - ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build) << Module->Name << ModuleFileName; @@ -1157,8 +1157,12 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, // thread so that we get a stack large enough. const unsigned ThreadStackSize = 8 << 20; llvm::CrashRecoveryContext CRC; - CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); }, - ThreadStackSize); + CRC.RunSafelyOnThread( + [&]() { + GenerateModuleFromModuleMapAction Action; + Instance.ExecuteAction(Action); + }, + ThreadStackSize); ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build_done) diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index 8cdb8298ee9e..d3ebf48315e2 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -81,7 +81,7 @@ using namespace llvm::opt; static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { unsigned DefaultOpt = 0; - if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable)) + if (IK.getLanguage() == InputKind::OpenCL && !Args.hasArg(OPT_cl_opt_disable)) DefaultOpt = 2; if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { @@ -652,7 +652,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.EmitSummaryIndex = A && A->containsValue("thin"); Opts.LTOUnit = Args.hasFlag(OPT_flto_unit, OPT_fno_lto_unit, false); if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) { - if (IK != IK_LLVM_IR) + if (IK.getLanguage() != InputKind::LLVM_IR) Diags.Report(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-x ir"; Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ); @@ -1347,42 +1347,54 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, << "ARC migration" << "ObjC migration"; } - InputKind DashX = IK_None; + InputKind DashX(InputKind::Unknown); if (const Arg *A = Args.getLastArg(OPT_x)) { - DashX = llvm::StringSwitch<InputKind>(A->getValue()) - .Case("c", IK_C) - .Case("cl", IK_OpenCL) - .Case("cuda", IK_CUDA) - .Case("c++", IK_CXX) - .Case("objective-c", IK_ObjC) - .Case("objective-c++", IK_ObjCXX) - .Case("cpp-output", IK_PreprocessedC) - .Case("assembler-with-cpp", IK_Asm) - .Case("c++-cpp-output", IK_PreprocessedCXX) - .Case("cuda-cpp-output", IK_PreprocessedCuda) - .Case("objective-c-cpp-output", IK_PreprocessedObjC) - .Case("objc-cpp-output", IK_PreprocessedObjC) - .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX) - .Case("objc++-cpp-output", IK_PreprocessedObjCXX) - .Case("c-header", IK_C) - .Case("cl-header", IK_OpenCL) - .Case("objective-c-header", IK_ObjC) - .Case("c++-header", IK_CXX) - .Case("objective-c++-header", IK_ObjCXX) - .Cases("ast", "pcm", IK_AST) - .Case("ir", IK_LLVM_IR) - .Case("renderscript", IK_RenderScript) - .Default(IK_None); - if (DashX == IK_None) + StringRef XValue = A->getValue(); + + // Parse suffixes: '<lang>(-header|[-module-map][-cpp-output])'. + // FIXME: Supporting '<lang>-header-cpp-output' would be useful. + bool Preprocessed = XValue.consume_back("-cpp-output"); + bool ModuleMap = XValue.consume_back("-module-map"); + IsHeaderFile = + !Preprocessed && !ModuleMap && XValue.consume_back("-header"); + + // Principal languages. + DashX = llvm::StringSwitch<InputKind>(XValue) + .Case("c", InputKind::C) + .Case("cl", InputKind::OpenCL) + .Case("cuda", InputKind::CUDA) + .Case("c++", InputKind::CXX) + .Case("objective-c", InputKind::ObjC) + .Case("objective-c++", InputKind::ObjCXX) + .Case("renderscript", InputKind::RenderScript) + .Default(InputKind::Unknown); + + // "objc[++]-cpp-output" is an acceptable synonym for + // "objective-c[++]-cpp-output". + if (DashX.isUnknown() && Preprocessed && !IsHeaderFile && !ModuleMap) + DashX = llvm::StringSwitch<InputKind>(XValue) + .Case("objc", InputKind::ObjC) + .Case("objc++", InputKind::ObjCXX) + .Default(InputKind::Unknown); + + // Some special cases cannot be combined with suffixes. + if (DashX.isUnknown() && !Preprocessed && !ModuleMap && !IsHeaderFile) + DashX = llvm::StringSwitch<InputKind>(XValue) + .Case("cpp-output", InputKind(InputKind::C).getPreprocessed()) + .Case("assembler-with-cpp", InputKind::Asm) + .Cases("ast", "pcm", + InputKind(InputKind::Unknown, InputKind::Precompiled)) + .Case("ir", InputKind::LLVM_IR) + .Default(InputKind::Unknown); + + if (DashX.isUnknown()) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); - IsHeaderFile = llvm::StringSwitch<bool>(A->getValue()) - .Case("c-header", true) - .Case("cl-header", true) - .Case("objective-c-header", true) - .Case("c++-header", true) - .Case("objective-c++-header", true) - .Default(false); + + if (Preprocessed) + DashX = DashX.getPreprocessed(); + if (ModuleMap) + DashX = DashX.withFormat(InputKind::ModuleMap); } // '-' is the default input if none is given. @@ -1392,13 +1404,22 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Inputs.push_back("-"); for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { InputKind IK = DashX; - if (IK == IK_None) { + if (IK.isUnknown()) { IK = FrontendOptions::getInputKindForExtension( StringRef(Inputs[i]).rsplit('.').second); + // FIXME: Warn on this? + if (IK.isUnknown()) + IK = InputKind::C; // FIXME: Remove this hack. if (i == 0) DashX = IK; } + + // The -emit-module action implicitly takes a module map. + if (Opts.ProgramAction == frontend::GenerateModule && + IK.getFormat() == InputKind::Source) + IK = IK.withFormat(InputKind::ModuleMap); + Opts.Inputs.emplace_back(std::move(Inputs[i]), IK); } @@ -1564,53 +1585,48 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, // Set some properties which depend solely on the input kind; it would be nice // to move these to the language standard, and have the driver resolve the // input kind + language standard. - if (IK == IK_Asm) { + // + // FIXME: Perhaps a better model would be for a single source file to have + // multiple language standards (C / C++ std, ObjC std, OpenCL std, OpenMP std) + // simultaneously active? + if (IK.getLanguage() == InputKind::Asm) { Opts.AsmPreprocessor = 1; - } else if (IK == IK_ObjC || - IK == IK_ObjCXX || - IK == IK_PreprocessedObjC || - IK == IK_PreprocessedObjCXX) { + } else if (IK.isObjectiveC()) { Opts.ObjC1 = Opts.ObjC2 = 1; } if (LangStd == LangStandard::lang_unspecified) { // Based on the base language, pick one. - switch (IK) { - case IK_None: - case IK_AST: - case IK_LLVM_IR: + switch (IK.getLanguage()) { + case InputKind::Unknown: + case InputKind::LLVM_IR: llvm_unreachable("Invalid input kind!"); - case IK_OpenCL: - LangStd = LangStandard::lang_opencl; + case InputKind::OpenCL: + LangStd = LangStandard::lang_opencl10; break; - case IK_CUDA: - case IK_PreprocessedCuda: + case InputKind::CUDA: LangStd = LangStandard::lang_cuda; break; - case IK_Asm: - case IK_C: - case IK_PreprocessedC: + case InputKind::Asm: + case InputKind::C: // The PS4 uses C99 as the default C standard. if (T.isPS4()) LangStd = LangStandard::lang_gnu99; else LangStd = LangStandard::lang_gnu11; break; - case IK_ObjC: - case IK_PreprocessedObjC: + case InputKind::ObjC: LangStd = LangStandard::lang_gnu11; break; - case IK_CXX: - case IK_PreprocessedCXX: - case IK_ObjCXX: - case IK_PreprocessedObjCXX: + case InputKind::CXX: + case InputKind::ObjCXX: // The PS4 uses C++11 as the default C++ standard. if (T.isPS4()) LangStd = LangStandard::lang_gnucxx11; else LangStd = LangStandard::lang_gnucxx98; break; - case IK_RenderScript: + case InputKind::RenderScript: LangStd = LangStandard::lang_c99; break; } @@ -1626,13 +1642,13 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.CPlusPlus1z = Std.isCPlusPlus1z(); Opts.Digraphs = Std.hasDigraphs(); Opts.GNUMode = Std.isGNUMode(); - Opts.GNUInline = Std.isC89(); + Opts.GNUInline = !Opts.C99 && !Opts.CPlusPlus; Opts.HexFloats = Std.hasHexFloats(); Opts.ImplicitInt = Std.hasImplicitInt(); // Set OpenCL Version. - Opts.OpenCL = Std.isOpenCL() || IK == IK_OpenCL; - if (LangStd == LangStandard::lang_opencl) + Opts.OpenCL = Std.isOpenCL(); + if (LangStd == LangStandard::lang_opencl10) Opts.OpenCLVersion = 100; else if (LangStd == LangStandard::lang_opencl11) Opts.OpenCLVersion = 110; @@ -1655,13 +1671,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, } } - Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda || - LangStd == LangStandard::lang_cuda; + Opts.CUDA = IK.getLanguage() == InputKind::CUDA; if (Opts.CUDA) // Set default FP_CONTRACT to FAST. Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); - Opts.RenderScript = IK == IK_RenderScript; + Opts.RenderScript = IK.getLanguage() == InputKind::RenderScript; if (Opts.RenderScript) { Opts.NativeHalfType = 1; Opts.NativeHalfArgsAndReturns = 1; @@ -1705,58 +1720,65 @@ static Visibility parseVisibility(Arg *arg, ArgList &args, /// Check if input file kind and language standard are compatible. static bool IsInputCompatibleWithStandard(InputKind IK, const LangStandard &S) { - switch (IK) { - case IK_C: - case IK_ObjC: - case IK_PreprocessedC: - case IK_PreprocessedObjC: - if (S.isC89() || S.isC99()) - return true; - break; - case IK_CXX: - case IK_ObjCXX: - case IK_PreprocessedCXX: - case IK_PreprocessedObjCXX: - if (S.isCPlusPlus()) - return true; - break; - case IK_OpenCL: - if (S.isOpenCL()) - return true; - break; - case IK_CUDA: - case IK_PreprocessedCuda: - if (S.isCPlusPlus()) - return true; - break; - default: - // For other inputs, accept (and ignore) all -std= values. + switch (IK.getLanguage()) { + case InputKind::Unknown: + case InputKind::LLVM_IR: + llvm_unreachable("should not parse language flags for this input"); + + case InputKind::C: + case InputKind::ObjC: + case InputKind::RenderScript: + return S.getLanguage() == InputKind::C; + + case InputKind::OpenCL: + return S.getLanguage() == InputKind::OpenCL; + + case InputKind::CXX: + case InputKind::ObjCXX: + return S.getLanguage() == InputKind::CXX; + + case InputKind::CUDA: + // FIXME: What -std= values should be permitted for CUDA compilations? + return S.getLanguage() == InputKind::CUDA || + S.getLanguage() == InputKind::CXX; + + case InputKind::Asm: + // Accept (and ignore) all -std= values. + // FIXME: The -std= value is not ignored; it affects the tokenization + // and preprocessing rules if we're preprocessing this asm input. return true; } - return false; + + llvm_unreachable("unexpected input language"); } /// Get language name for given input kind. static const StringRef GetInputKindName(InputKind IK) { - switch (IK) { - case IK_C: - case IK_ObjC: - case IK_PreprocessedC: - case IK_PreprocessedObjC: - return "C/ObjC"; - case IK_CXX: - case IK_ObjCXX: - case IK_PreprocessedCXX: - case IK_PreprocessedObjCXX: - return "C++/ObjC++"; - case IK_OpenCL: + switch (IK.getLanguage()) { + case InputKind::C: + return "C"; + case InputKind::ObjC: + return "Objective-C"; + case InputKind::CXX: + return "C++"; + case InputKind::ObjCXX: + return "Objective-C++"; + case InputKind::OpenCL: return "OpenCL"; - case IK_CUDA: - case IK_PreprocessedCuda: + case InputKind::CUDA: return "CUDA"; - default: - llvm_unreachable("Cannot decide on name for InputKind!"); + case InputKind::RenderScript: + return "RenderScript"; + + case InputKind::Asm: + return "Asm"; + case InputKind::LLVM_IR: + return "LLVM IR"; + + case InputKind::Unknown: + break; } + llvm_unreachable("unknown input language"); } static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, @@ -1767,7 +1789,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, LangStandard::Kind LangStd = LangStandard::lang_unspecified; if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue()) -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ .Case(name, LangStandard::lang_##id) #define LANGSTANDARD_ALIAS(id, alias) \ .Case(alias, LangStandard::lang_##id) @@ -1783,8 +1805,20 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, const LangStandard &Std = LangStandard::getLangStandardForKind( static_cast<LangStandard::Kind>(KindValue)); if (IsInputCompatibleWithStandard(IK, Std)) { - Diags.Report(diag::note_drv_use_standard) - << Std.getName() << Std.getDescription(); + auto Diag = Diags.Report(diag::note_drv_use_standard); + Diag << Std.getName() << Std.getDescription(); + unsigned NumAliases = 0; +#define LANGSTANDARD(id, name, lang, desc, features) +#define LANGSTANDARD_ALIAS(id, alias) \ + if (KindValue == LangStandard::lang_##id) ++NumAliases; +#define LANGSTANDARD_ALIAS_DEPR(id, alias) +#include "clang/Frontend/LangStandards.def" + Diag << NumAliases; +#define LANGSTANDARD(id, name, lang, desc, features) +#define LANGSTANDARD_ALIAS(id, alias) \ + if (KindValue == LangStandard::lang_##id) Diag << alias; +#define LANGSTANDARD_ALIAS_DEPR(id, alias) +#include "clang/Frontend/LangStandards.def" } } } else { @@ -1803,7 +1837,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { LangStandard::Kind OpenCLLangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue()) - .Cases("cl", "CL", LangStandard::lang_opencl) + .Cases("cl", "CL", LangStandard::lang_opencl10) .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11) .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12) .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20) @@ -2533,7 +2567,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Res.getTargetOpts()); ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Res.getFileSystemOpts().WorkingDir); - if (DashX == IK_AST || DashX == IK_LLVM_IR) { + if (DashX.getFormat() == InputKind::Precompiled || + DashX.getLanguage() == InputKind::LLVM_IR) { // ObjCAAutoRefCount and Sanitize LangOpts are used to setup the // PassManager in BackendUtil.cpp. They need to be initializd no matter // what the input type is. @@ -2547,8 +2582,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Diags, LangOpts.Sanitize); } else { // Other LangOpts are only initialzed when the input is not AST or LLVM IR. + // FIXME: Should we really be calling this for an InputKind::Asm input? ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(), - Res.getPreprocessorOpts(), Diags); + Res.getPreprocessorOpts(), Diags); if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC) LangOpts.ObjCExceptions = 1; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp index 0dd07d9f817b..d26b6937b851 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -224,6 +224,231 @@ static bool ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile) return true; } +static SmallVectorImpl<char> & +operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) { + Includes.append(RHS.begin(), RHS.end()); + return Includes; +} + +static void addHeaderInclude(StringRef HeaderName, + SmallVectorImpl<char> &Includes, + const LangOptions &LangOpts, + bool IsExternC) { + if (IsExternC && LangOpts.CPlusPlus) + Includes += "extern \"C\" {\n"; + if (LangOpts.ObjC1) + Includes += "#import \""; + else + Includes += "#include \""; + + Includes += HeaderName; + + Includes += "\"\n"; + if (IsExternC && LangOpts.CPlusPlus) + Includes += "}\n"; +} + +/// \brief Collect the set of header includes needed to construct the given +/// module and update the TopHeaders file set of the module. +/// +/// \param Module The module we're collecting includes from. +/// +/// \param Includes Will be augmented with the set of \#includes or \#imports +/// needed to load all of the named headers. +static std::error_code +collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, + ModuleMap &ModMap, clang::Module *Module, + SmallVectorImpl<char> &Includes) { + // Don't collect any headers for unavailable modules. + if (!Module->isAvailable()) + return std::error_code(); + + // Add includes for each of these headers. + for (auto HK : {Module::HK_Normal, Module::HK_Private}) { + for (Module::Header &H : Module->Headers[HK]) { + Module->addTopHeader(H.Entry); + // Use the path as specified in the module map file. We'll look for this + // file relative to the module build directory (the directory containing + // the module map file) so this will find the same file that we found + // while parsing the module map. + addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC); + } + } + // Note that Module->PrivateHeaders will not be a TopHeader. + + if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) { + Module->addTopHeader(UmbrellaHeader.Entry); + if (Module->Parent) + // Include the umbrella header for submodules. + addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts, + Module->IsExternC); + } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) { + // Add all of the headers we find in this subdirectory. + std::error_code EC; + SmallString<128> DirNative; + llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); + + vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); + for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; + Dir != End && !EC; Dir.increment(EC)) { + // Check whether this entry has an extension typically associated with + // headers. + if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName())) + .Cases(".h", ".H", ".hh", ".hpp", true) + .Default(false)) + continue; + + const FileEntry *Header = FileMgr.getFile(Dir->getName()); + // FIXME: This shouldn't happen unless there is a file system race. Is + // that worth diagnosing? + if (!Header) + continue; + + // If this header is marked 'unavailable' in this module, don't include + // it. + if (ModMap.isHeaderUnavailableInModule(Header, Module)) + continue; + + // Compute the relative path from the directory to this file. + SmallVector<StringRef, 16> Components; + auto PathIt = llvm::sys::path::rbegin(Dir->getName()); + for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) + Components.push_back(*PathIt); + SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten); + for (auto It = Components.rbegin(), End = Components.rend(); It != End; + ++It) + llvm::sys::path::append(RelativeHeader, *It); + + // Include this header as part of the umbrella directory. + Module->addTopHeader(Header); + addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC); + } + + if (EC) + return EC; + } + + // Recurse into submodules. + for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), + SubEnd = Module->submodule_end(); + Sub != SubEnd; ++Sub) + if (std::error_code Err = collectModuleHeaderIncludes( + LangOpts, FileMgr, ModMap, *Sub, Includes)) + return Err; + + return std::error_code(); +} + +/// Parse a module map and compute the corresponding real input buffer that +/// should be used to build the module described by that module map and the +/// current module name. +static std::unique_ptr<llvm::MemoryBuffer> +getInputBufferForModuleMap(CompilerInstance &CI, StringRef Filename, + bool IsSystem) { + // Find the module map file. + const FileEntry *ModuleMap = + CI.getFileManager().getFile(Filename, /*openFile*/true); + if (!ModuleMap) { + CI.getDiagnostics().Report(diag::err_module_map_not_found) + << Filename; + return nullptr; + } + + // Find the module map file from which it was generated, if different. + const FileEntry *OriginalModuleMap = ModuleMap; + StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap; + if (!OriginalModuleMapName.empty()) { + OriginalModuleMap = CI.getFileManager().getFile(OriginalModuleMapName, + /*openFile*/ true); + if (!OriginalModuleMap) { + CI.getDiagnostics().Report(diag::err_module_map_not_found) + << OriginalModuleMapName; + return nullptr; + } + } + + // Parse the module map file. + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); + if (HS.loadModuleMapFile(ModuleMap, IsSystem)) + return nullptr; + + if (CI.getLangOpts().CurrentModule.empty()) { + CI.getDiagnostics().Report(diag::err_missing_module_name); + + // FIXME: Eventually, we could consider asking whether there was just + // a single module described in the module map, and use that as a + // default. Then it would be fairly trivial to just "compile" a module + // map with a single module (the common case). + return nullptr; + } + + // If we're being run from the command-line, the module build stack will not + // have been filled in yet, so complete it now in order to allow us to detect + // module cycles. + SourceManager &SourceMgr = CI.getSourceManager(); + if (SourceMgr.getModuleBuildStack().empty()) + SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule, + FullSourceLoc(SourceLocation(), SourceMgr)); + + // Dig out the module definition. + Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule, + /*AllowSearch=*/false); + if (!M) { + CI.getDiagnostics().Report(diag::err_missing_module) + << CI.getLangOpts().CurrentModule << Filename; + + return nullptr; + } + + // Check whether we can build this module at all. + clang::Module::Requirement Requirement; + clang::Module::UnresolvedHeaderDirective MissingHeader; + if (!M->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement, + MissingHeader)) { + if (MissingHeader.FileNameLoc.isValid()) { + CI.getDiagnostics().Report(MissingHeader.FileNameLoc, + diag::err_module_header_missing) + << MissingHeader.IsUmbrella << MissingHeader.FileName; + } else { + CI.getDiagnostics().Report(diag::err_module_unavailable) + << M->getFullModuleName() << Requirement.second << Requirement.first; + } + + return nullptr; + } + + if (OriginalModuleMap != ModuleMap) { + M->IsInferred = true; + HS.getModuleMap().setInferredModuleAllowedBy(M, OriginalModuleMap); + } + + FileManager &FileMgr = CI.getFileManager(); + + // Collect the set of #includes we need to build the module. + SmallString<256> HeaderContents; + std::error_code Err = std::error_code(); + if (Module::Header UmbrellaHeader = M->getUmbrellaHeader()) + addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents, + CI.getLangOpts(), M->IsExternC); + Err = collectModuleHeaderIncludes( + CI.getLangOpts(), FileMgr, + CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), M, + HeaderContents); + + if (Err) { + CI.getDiagnostics().Report(diag::err_module_cannot_create_includes) + << M->getFullModuleName() << Err.message(); + return nullptr; + } + + // Inform the preprocessor that includes from within the input buffer should + // be resolved relative to the build directory of the module map file. + CI.getPreprocessor().setMainFileDir(M->Directory); + + return llvm::MemoryBuffer::getMemBufferCopy( + HeaderContents, Module::getModuleInputBufferName()); +} + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &Input) { assert(!Instance && "Already processing a source file!"); @@ -232,13 +457,15 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, setCompilerInstance(&CI); StringRef InputFile = Input.getFile(); + FrontendInputFile FileToProcess = Input; bool HasBegunSourceFile = false; if (!BeginInvocation(CI)) goto failure; // AST files follow a very different path, since they share objects via the // AST unit. - if (Input.getKind() == IK_AST) { + if (Input.getKind().getFormat() == InputKind::Precompiled) { + // FIXME: We should not be asserting on bad command-line arguments. assert(!usesPreprocessorOnly() && "Attempt to pass AST file to preprocessor only action!"); assert(hasASTFileSupport() && @@ -296,8 +523,19 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!CI.hasSourceManager()) CI.createSourceManager(CI.getFileManager()); + // Set up embedding for any specified files. Do this before we load any + // source files, including the primary module map for the compilation. + for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) { + if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true)) + CI.getSourceManager().setFileIsTransient(FE); + else + CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F; + } + if (CI.getFrontendOpts().ModulesEmbedAllFiles) + CI.getSourceManager().setAllFilesAreTransient(true); + // IR files bypass the rest of initialization. - if (Input.getKind() == IK_LLVM_IR) { + if (Input.getKind().getLanguage() == InputKind::LLVM_IR) { assert(hasIRSupport() && "This action does not have IR file support!"); @@ -359,13 +597,34 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, &CI.getPreprocessor()); HasBegunSourceFile = true; + // For module map files, we first parse the module map and synthesize a + // "<module-includes>" buffer before more conventional processing. + if (Input.getKind().getFormat() == InputKind::ModuleMap) { + CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); + + auto Buffer = getInputBufferForModuleMap(CI, InputFile, Input.isSystem()); + if (!Buffer) + goto failure; + + Module *CurrentModule = + CI.getPreprocessor().getHeaderSearchInfo().lookupModule( + CI.getLangOpts().CurrentModule, + /*AllowSearch=*/false); + assert(CurrentModule && "no module info for current module"); + + // The input that we end up processing is the generated buffer, not the + // module map file itself. + FileToProcess = FrontendInputFile( + Buffer.release(), Input.getKind().withFormat(InputKind::Source), + CurrentModule->IsSystem); + } + // Initialize the action. if (!BeginSourceFileAction(CI, InputFile)) goto failure; - // Initialize the main file entry. It is important that this occurs after - // BeginSourceFileAction, which may change CurrentInput during module builds. - if (!CI.InitializeSourceManager(CurrentInput)) + // Initialize the main file entry. + if (!CI.InitializeSourceManager(FileToProcess)) goto failure; // Create the AST context and consumer unless this is a preprocessor only @@ -497,6 +756,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (HasBegunSourceFile) CI.getDiagnosticClient().EndSourceFile(); CI.clearOutputFiles(/*EraseFiles=*/true); + CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); setCurrentInput(FrontendInputFile()); setCompilerInstance(nullptr); return false; @@ -579,6 +839,7 @@ void FrontendAction::EndSourceFile() { setCompilerInstance(nullptr); setCurrentInput(FrontendInputFile()); + CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); } bool FrontendAction::shouldEraseOutputFiles() { diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp index e818038b1354..dd7c12f60f0e 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp @@ -164,242 +164,9 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } -bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, - StringRef Filename) { - // Set up embedding for any specified files. Do this before we load any - // source files, including the primary module map for the compilation. - for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) { - if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true)) - CI.getSourceManager().setFileIsTransient(FE); - else - CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F; - } - if (CI.getFrontendOpts().ModulesEmbedAllFiles) - CI.getSourceManager().setAllFilesAreTransient(true); - - return true; -} - - -static SmallVectorImpl<char> & -operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) { - Includes.append(RHS.begin(), RHS.end()); - return Includes; -} - -static void addHeaderInclude(StringRef HeaderName, - SmallVectorImpl<char> &Includes, - const LangOptions &LangOpts, - bool IsExternC) { - if (IsExternC && LangOpts.CPlusPlus) - Includes += "extern \"C\" {\n"; - if (LangOpts.ObjC1) - Includes += "#import \""; - else - Includes += "#include \""; - - Includes += HeaderName; - - Includes += "\"\n"; - if (IsExternC && LangOpts.CPlusPlus) - Includes += "}\n"; -} - -/// \brief Collect the set of header includes needed to construct the given -/// module and update the TopHeaders file set of the module. -/// -/// \param Module The module we're collecting includes from. -/// -/// \param Includes Will be augmented with the set of \#includes or \#imports -/// needed to load all of the named headers. -static std::error_code -collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, - ModuleMap &ModMap, clang::Module *Module, - SmallVectorImpl<char> &Includes) { - // Don't collect any headers for unavailable modules. - if (!Module->isAvailable()) - return std::error_code(); - - // Add includes for each of these headers. - for (auto HK : {Module::HK_Normal, Module::HK_Private}) { - for (Module::Header &H : Module->Headers[HK]) { - Module->addTopHeader(H.Entry); - // Use the path as specified in the module map file. We'll look for this - // file relative to the module build directory (the directory containing - // the module map file) so this will find the same file that we found - // while parsing the module map. - addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC); - } - } - // Note that Module->PrivateHeaders will not be a TopHeader. - - if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) { - Module->addTopHeader(UmbrellaHeader.Entry); - if (Module->Parent) - // Include the umbrella header for submodules. - addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts, - Module->IsExternC); - } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) { - // Add all of the headers we find in this subdirectory. - std::error_code EC; - SmallString<128> DirNative; - llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); - - vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); - for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; - Dir != End && !EC; Dir.increment(EC)) { - // Check whether this entry has an extension typically associated with - // headers. - if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName())) - .Cases(".h", ".H", ".hh", ".hpp", true) - .Default(false)) - continue; - - const FileEntry *Header = FileMgr.getFile(Dir->getName()); - // FIXME: This shouldn't happen unless there is a file system race. Is - // that worth diagnosing? - if (!Header) - continue; - - // If this header is marked 'unavailable' in this module, don't include - // it. - if (ModMap.isHeaderUnavailableInModule(Header, Module)) - continue; - - // Compute the relative path from the directory to this file. - SmallVector<StringRef, 16> Components; - auto PathIt = llvm::sys::path::rbegin(Dir->getName()); - for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt) - Components.push_back(*PathIt); - SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten); - for (auto It = Components.rbegin(), End = Components.rend(); It != End; - ++It) - llvm::sys::path::append(RelativeHeader, *It); - - // Include this header as part of the umbrella directory. - Module->addTopHeader(Header); - addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC); - } - - if (EC) - return EC; - } - - // Recurse into submodules. - for (clang::Module::submodule_iterator Sub = Module->submodule_begin(), - SubEnd = Module->submodule_end(); - Sub != SubEnd; ++Sub) - if (std::error_code Err = collectModuleHeaderIncludes( - LangOpts, FileMgr, ModMap, *Sub, Includes)) - return Err; - - return std::error_code(); -} - bool GenerateModuleFromModuleMapAction::BeginSourceFileAction( CompilerInstance &CI, StringRef Filename) { - CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); - - if (!GenerateModuleAction::BeginSourceFileAction(CI, Filename)) - return false; - - // Find the module map file. - const FileEntry *ModuleMap = - CI.getFileManager().getFile(Filename, /*openFile*/true); - if (!ModuleMap) { - CI.getDiagnostics().Report(diag::err_module_map_not_found) - << Filename; - return false; - } - - // Parse the module map file. - HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); - if (HS.loadModuleMapFile(ModuleMap, IsSystem)) - return false; - - if (CI.getLangOpts().CurrentModule.empty()) { - CI.getDiagnostics().Report(diag::err_missing_module_name); - - // FIXME: Eventually, we could consider asking whether there was just - // a single module described in the module map, and use that as a - // default. Then it would be fairly trivial to just "compile" a module - // map with a single module (the common case). - return false; - } - - // If we're being run from the command-line, the module build stack will not - // have been filled in yet, so complete it now in order to allow us to detect - // module cycles. - SourceManager &SourceMgr = CI.getSourceManager(); - if (SourceMgr.getModuleBuildStack().empty()) - SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule, - FullSourceLoc(SourceLocation(), SourceMgr)); - - // Dig out the module definition. - Module = HS.lookupModule(CI.getLangOpts().CurrentModule, - /*AllowSearch=*/false); - if (!Module) { - CI.getDiagnostics().Report(diag::err_missing_module) - << CI.getLangOpts().CurrentModule << Filename; - - return false; - } - - // Check whether we can build this module at all. - clang::Module::Requirement Requirement; - clang::Module::UnresolvedHeaderDirective MissingHeader; - if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement, - MissingHeader)) { - if (MissingHeader.FileNameLoc.isValid()) { - CI.getDiagnostics().Report(MissingHeader.FileNameLoc, - diag::err_module_header_missing) - << MissingHeader.IsUmbrella << MissingHeader.FileName; - } else { - CI.getDiagnostics().Report(diag::err_module_unavailable) - << Module->getFullModuleName() - << Requirement.second << Requirement.first; - } - - return false; - } - - if (ModuleMapForUniquing && ModuleMapForUniquing != ModuleMap) { - Module->IsInferred = true; - HS.getModuleMap().setInferredModuleAllowedBy(Module, ModuleMapForUniquing); - } else { - ModuleMapForUniquing = ModuleMap; - } - - FileManager &FileMgr = CI.getFileManager(); - - // Collect the set of #includes we need to build the module. - SmallString<256> HeaderContents; - std::error_code Err = std::error_code(); - if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) - addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents, - CI.getLangOpts(), Module->IsExternC); - Err = collectModuleHeaderIncludes( - CI.getLangOpts(), FileMgr, - CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module, - HeaderContents); - - if (Err) { - CI.getDiagnostics().Report(diag::err_module_cannot_create_includes) - << Module->getFullModuleName() << Err.message(); - return false; - } - - // Inform the preprocessor that includes from within the input buffer should - // be resolved relative to the build directory of the module map file. - CI.getPreprocessor().setMainFileDir(Module->Directory); - - std::unique_ptr<llvm::MemoryBuffer> InputBuffer = - llvm::MemoryBuffer::getMemBufferCopy(HeaderContents, - Module::getModuleInputBufferName()); - // Ownership of InputBuffer will be transferred to the SourceManager. - setCurrentInput(FrontendInputFile(InputBuffer.release(), getCurrentFileKind(), - Module->IsSystem)); - return true; + return GenerateModuleAction::BeginSourceFileAction(CI, Filename); } std::unique_ptr<raw_pwrite_stream> @@ -408,10 +175,13 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, // If no output file was provided, figure out where this module would go // in the module cache. if (CI.getFrontendOpts().OutputFile.empty()) { + StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap; + if (ModuleMapFile.empty()) + ModuleMapFile = InFile; + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); CI.getFrontendOpts().OutputFile = - HS.getModuleFileName(CI.getLangOpts().CurrentModule, - ModuleMapForUniquing->getName(), + HS.getModuleFileName(CI.getLangOpts().CurrentModule, ModuleMapFile, /*UsePrebuiltPath=*/false); } @@ -777,29 +547,27 @@ void PrintPreprocessedAction::ExecuteAction() { } void PrintPreambleAction::ExecuteAction() { - switch (getCurrentFileKind()) { - case IK_C: - case IK_CXX: - case IK_ObjC: - case IK_ObjCXX: - case IK_OpenCL: - case IK_CUDA: + switch (getCurrentFileKind().getLanguage()) { + case InputKind::C: + case InputKind::CXX: + case InputKind::ObjC: + case InputKind::ObjCXX: + case InputKind::OpenCL: + case InputKind::CUDA: break; - case IK_None: - case IK_Asm: - case IK_PreprocessedC: - case IK_PreprocessedCuda: - case IK_PreprocessedCXX: - case IK_PreprocessedObjC: - case IK_PreprocessedObjCXX: - case IK_AST: - case IK_LLVM_IR: - case IK_RenderScript: + case InputKind::Unknown: + case InputKind::Asm: + case InputKind::LLVM_IR: + case InputKind::RenderScript: // We can't do anything with these. return; } + // We don't expect to find any #include directives in a preprocessed input. + if (getCurrentFileKind().isPreprocessed()) + return; + CompilerInstance &CI = getCompilerInstance(); auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile()); if (Buffer) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp index 6a82084aff1b..dca434588fb1 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp @@ -13,22 +13,22 @@ using namespace clang; InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) { return llvm::StringSwitch<InputKind>(Extension) - .Cases("ast", "pcm", IK_AST) - .Case("c", IK_C) - .Cases("S", "s", IK_Asm) - .Case("i", IK_PreprocessedC) - .Case("ii", IK_PreprocessedCXX) - .Case("cui", IK_PreprocessedCuda) - .Case("m", IK_ObjC) - .Case("mi", IK_PreprocessedObjC) - .Cases("mm", "M", IK_ObjCXX) - .Case("mii", IK_PreprocessedObjCXX) - .Cases("C", "cc", "cp", IK_CXX) - .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX) - .Case("cppm", IK_CXX) - .Case("iim", IK_PreprocessedCXX) - .Case("cl", IK_OpenCL) - .Case("cu", IK_CUDA) - .Cases("ll", "bc", IK_LLVM_IR) - .Default(IK_C); + .Cases("ast", "pcm", InputKind(InputKind::Unknown, InputKind::Precompiled)) + .Case("c", InputKind::C) + .Cases("S", "s", InputKind::Asm) + .Case("i", InputKind(InputKind::C).getPreprocessed()) + .Case("ii", InputKind(InputKind::CXX).getPreprocessed()) + .Case("cui", InputKind(InputKind::CUDA).getPreprocessed()) + .Case("m", InputKind::ObjC) + .Case("mi", InputKind(InputKind::ObjC).getPreprocessed()) + .Cases("mm", "M", InputKind::ObjCXX) + .Case("mii", InputKind(InputKind::ObjCXX).getPreprocessed()) + .Cases("C", "cc", "cp", InputKind::CXX) + .Cases("cpp", "CPP", "c++", "cxx", "hpp", InputKind::CXX) + .Case("cppm", InputKind::CXX) + .Case("iim", InputKind(InputKind::CXX).getPreprocessed()) + .Case("cl", InputKind::OpenCL) + .Case("cu", InputKind::CUDA) + .Cases("ll", "bc", InputKind::LLVM_IR) + .Default(InputKind::Unknown); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp index 0dd04e8a8fff..9257dcae84cd 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp @@ -1041,6 +1041,8 @@ void clang::InitializePreprocessor( // Install things like __POWERPC__, __GNUC__, etc into the macro table. if (InitOpts.UsePredefines) { + // FIXME: This will create multiple definitions for most of the predefined + // macros. This is not the right way to handle this. if (LangOpts.CUDA && PP.getAuxTargetInfo()) InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts, Builder); diff --git a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp index f133327f4298..47023e58fa0b 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp @@ -13,15 +13,15 @@ using namespace clang; using namespace clang::frontend; -#define LANGSTANDARD(id, name, desc, features) \ - static const LangStandard Lang_##id = { name, desc, features }; +#define LANGSTANDARD(id, name, lang, desc, features) \ +static const LangStandard Lang_##id = { name, desc, features, InputKind::lang }; #include "clang/Frontend/LangStandards.def" const LangStandard &LangStandard::getLangStandardForKind(Kind K) { switch (K) { case lang_unspecified: llvm::report_fatal_error("getLangStandardForKind() on unspecified kind"); -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ case lang_##id: return Lang_##id; #include "clang/Frontend/LangStandards.def" } @@ -30,7 +30,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) { const LangStandard *LangStandard::getLangStandardForName(StringRef Name) { Kind K = llvm::StringSwitch<Kind>(Name) -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ .Case(name, lang_##id) #include "clang/Frontend/LangStandards.def" .Default(lang_unspecified); diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp index d48b952ef203..ffedf3cac847 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -172,7 +172,8 @@ public: /// MacroUndefined - This hook is called whenever a macro #undef is seen. void MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) override; + const MacroDefinition &MD, + const MacroDirective *Undef) override; }; } // end anonymous namespace @@ -323,43 +324,50 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc, StringRef SearchPath, StringRef RelativePath, const Module *Imported) { - if (Imported) { - // When preprocessing, turn implicit imports into @imports. - // FIXME: This is a stop-gap until a more comprehensive "preprocessing with - // modules" solution is introduced. + // In -dI mode, dump #include directives prior to dumping their content or + // interpretation. + if (DumpIncludeDirectives) { startNewLineIfNeeded(); MoveToLine(HashLoc); - if (PP.getLangOpts().ObjC2) { - OS << "@import " << Imported->getFullModuleName() << ";" - << " /* clang -E: implicit import for \"" << File->getName() - << "\" */"; - } else { - const std::string TokenText = PP.getSpelling(IncludeTok); - assert(!TokenText.empty()); - OS << "#" << TokenText << " " - << (IsAngled ? '<' : '"') - << FileName - << (IsAngled ? '>' : '"') - << " /* clang -E: implicit import for module " - << Imported->getFullModuleName() << " */"; - } - // Since we want a newline after the @import, but not a #<line>, start a new - // line immediately. - EmittedTokensOnThisLine = true; + const std::string TokenText = PP.getSpelling(IncludeTok); + assert(!TokenText.empty()); + OS << "#" << TokenText << " " + << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') + << " /* clang -E -dI */"; + setEmittedDirectiveOnThisLine(); startNewLineIfNeeded(); - } else { - // Not a module import; it's a more vanilla inclusion of some file using one - // of: #include, #import, #include_next, #include_macros. - if (DumpIncludeDirectives) { + } + + // When preprocessing, turn implicit imports into module import pragmas. + if (Imported) { + switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { + case tok::pp_include: + case tok::pp_import: + case tok::pp_include_next: startNewLineIfNeeded(); MoveToLine(HashLoc); - const std::string TokenText = PP.getSpelling(IncludeTok); - assert(!TokenText.empty()); - OS << "#" << TokenText << " " + OS << "#pragma clang module import " << Imported->getFullModuleName() + << " /* clang -E: implicit import for " + << "#" << PP.getSpelling(IncludeTok) << " " << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') - << " /* clang -E -dI */"; - setEmittedDirectiveOnThisLine(); + << " */"; + // Since we want a newline after the pragma, but not a #<line>, start a + // new line immediately. + EmittedTokensOnThisLine = true; startNewLineIfNeeded(); + break; + + case tok::pp___include_macros: + // #__include_macros has no effect on a user of a preprocessed source + // file; the only effect is on preprocessing. + // + // FIXME: That's not *quite* true: it causes the module in question to + // be loaded, which can affect downstream diagnostics. + break; + + default: + llvm_unreachable("unknown include directive kind"); + break; } } } @@ -389,7 +397,8 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, } void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { // Only print out macro definitions in -dD mode. if (!DumpDefines) return; @@ -773,26 +782,33 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, // Expand macros in pragmas with -fms-extensions. The assumption is that // the majority of pragmas in such a file will be Microsoft pragmas. - PP.AddPragmaHandler(new UnknownPragmaHandler( - "#pragma", Callbacks, + // Remember the handlers we will add so that we can remove them later. + std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler( + new UnknownPragmaHandler( + "#pragma", Callbacks, + /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + + std::unique_ptr<UnknownPragmaHandler> GCCHandler(new UnknownPragmaHandler( + "#pragma GCC", Callbacks, /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); - PP.AddPragmaHandler( - "GCC", new UnknownPragmaHandler( - "#pragma GCC", Callbacks, - /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); - PP.AddPragmaHandler( - "clang", new UnknownPragmaHandler( - "#pragma clang", Callbacks, - /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + + std::unique_ptr<UnknownPragmaHandler> ClangHandler(new UnknownPragmaHandler( + "#pragma clang", Callbacks, + /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt)); + + PP.AddPragmaHandler(MicrosoftExtHandler.get()); + PP.AddPragmaHandler("GCC", GCCHandler.get()); + PP.AddPragmaHandler("clang", ClangHandler.get()); // The tokens after pragma omp need to be expanded. // // OpenMP [2.1, Directive format] // Preprocessing tokens following the #pragma omp are subject to macro // replacement. - PP.AddPragmaHandler("omp", - new UnknownPragmaHandler("#pragma omp", Callbacks, - /*RequireTokenExpansion=*/true)); + std::unique_ptr<UnknownPragmaHandler> OpenMPHandler( + new UnknownPragmaHandler("#pragma omp", Callbacks, + /*RequireTokenExpansion=*/true)); + PP.AddPragmaHandler("omp", OpenMPHandler.get()); PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks)); @@ -820,4 +836,11 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS, // Read all the preprocessed tokens, printing them out to the stream. PrintPreprocessedTokens(PP, Tok, Callbacks, *OS); *OS << '\n'; + + // Remove the handlers we just added to leave the preprocessor in a sane state + // so that it can be reused (for example by a clang::Parser instance). + PP.RemovePragmaHandler(MicrosoftExtHandler.get()); + PP.RemovePragmaHandler("GCC", GCCHandler.get()); + PP.RemovePragmaHandler("clang", ClangHandler.get()); + PP.RemovePragmaHandler("omp", OpenMPHandler.get()); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp index d953da2e4fd2..ee61f76d029d 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -52,7 +52,7 @@ class InclusionRewriter : public PPCallbacks { public: InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers, bool UseLineDirectives); - bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType); + void Process(FileID FileId, SrcMgr::CharacteristicKind FileType); void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) { PredefinesBuffer = Buf; } @@ -132,7 +132,7 @@ void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line, } void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) { - OS << "@import " << Mod->getFullModuleName() << ";" + OS << "#pragma clang module import " << Mod->getFullModuleName() << " /* clang -frewrite-includes: implicit import */" << MainEOL; } @@ -392,7 +392,7 @@ bool InclusionRewriter::HandleHasInclude( // FIXME: Why don't we call PP.LookupFile here? const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr, - nullptr, nullptr, nullptr, false); + nullptr, nullptr, nullptr, nullptr); FileExists = File != nullptr; return true; @@ -400,9 +400,8 @@ bool InclusionRewriter::HandleHasInclude( /// Use a raw lexer to analyze \p FileId, incrementally copying parts of it /// and including content of included files recursively. -bool InclusionRewriter::Process(FileID FileId, - SrcMgr::CharacteristicKind FileType) -{ +void InclusionRewriter::Process(FileID FileId, + SrcMgr::CharacteristicKind FileType) { bool Invalid; const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); assert(!Invalid && "Attempting to process invalid inclusion"); @@ -419,7 +418,7 @@ bool InclusionRewriter::Process(FileID FileId, WriteLineInfo(FileName, 1, FileType, " 1"); if (SM.getFileIDSize(FileId) == 0) - return false; + return; // The next byte to be copied from the source file, which may be non-zero if // the lexer handled a BOM. @@ -450,19 +449,14 @@ bool InclusionRewriter::Process(FileID FileId, WriteLineInfo(FileName, Line - 1, FileType, ""); StringRef LineInfoExtra; SourceLocation Loc = HashToken.getLocation(); - if (const Module *Mod = PP.getLangOpts().ObjC2 - ? FindModuleAtLocation(Loc) - : nullptr) + if (const Module *Mod = FindModuleAtLocation(Loc)) WriteImplicitModuleImport(Mod); else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { - // include and recursively process the file - if (Process(Inc->Id, Inc->FileType)) { - // and set lineinfo back to this file, if the nested one was - // actually included - // `2' indicates returning to a file (after having included - // another file. - LineInfoExtra = " 2"; - } + // Include and recursively process the file. + Process(Inc->Id, Inc->FileType); + // Add line marker to indicate we're returning from an included + // file. + LineInfoExtra = " 2"; } // fix up lineinfo (since commented out directive changed line // numbers) for inclusions that were skipped due to header guards @@ -571,7 +565,6 @@ bool InclusionRewriter::Process(FileID FileId, OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL, Line, /*EnsureNewline=*/true); - return true; } /// InclusionRewriterInInput - Implement -frewrite-includes mode. diff --git a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index ae16ea177ffe..427d15ed703a 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -400,7 +400,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, const DirectoryLookup *CurDir; const FileEntry *FE = PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir, - nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr); if (!FE) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_file) << Filename << KindStr; diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h index d8535f765889..b556d04efbb7 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h @@ -528,6 +528,116 @@ _mm512_mask2int(__mmask16 __a) return (int)__a; } +/// \brief Constructs a 512-bit floating-point vector of [8 x double] from a +/// 128-bit floating-point vector of [2 x double]. The lower 128 bits +/// contain the value of the source vector. The upper 384 bits are set +/// to zero. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [2 x double]. +/// \returns A 512-bit floating-point vector of [8 x double]. The lower 128 bits +/// contain the value of the parameter. The upper 384 bits are set to zero. +static __inline __m512d __DEFAULT_FN_ATTRS +_mm512_zextpd128_pd512(__m128d __a) +{ + return __builtin_shufflevector((__v2df)__a, (__v2df)_mm_setzero_pd(), 0, 1, 2, 3, 2, 3, 2, 3); +} + +/// \brief Constructs a 512-bit floating-point vector of [8 x double] from a +/// 256-bit floating-point vector of [4 x double]. The lower 256 bits +/// contain the value of the source vector. The upper 256 bits are set +/// to zero. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 256-bit vector of [4 x double]. +/// \returns A 512-bit floating-point vector of [8 x double]. The lower 256 bits +/// contain the value of the parameter. The upper 256 bits are set to zero. +static __inline __m512d __DEFAULT_FN_ATTRS +_mm512_zextpd256_pd512(__m256d __a) +{ + return __builtin_shufflevector((__v4df)__a, (__v4df)_mm256_setzero_pd(), 0, 1, 2, 3, 4, 5, 6, 7); +} + +/// \brief Constructs a 512-bit floating-point vector of [16 x float] from a +/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain +/// the value of the source vector. The upper 384 bits are set to zero. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [4 x float]. +/// \returns A 512-bit floating-point vector of [16 x float]. The lower 128 bits +/// contain the value of the parameter. The upper 384 bits are set to zero. +static __inline __m512 __DEFAULT_FN_ATTRS +_mm512_zextps128_ps512(__m128 __a) +{ + return __builtin_shufflevector((__v4sf)__a, (__v4sf)_mm_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7); +} + +/// \brief Constructs a 512-bit floating-point vector of [16 x float] from a +/// 256-bit floating-point vector of [8 x float]. The lower 256 bits contain +/// the value of the source vector. The upper 256 bits are set to zero. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 256-bit vector of [8 x float]. +/// \returns A 512-bit floating-point vector of [16 x float]. The lower 256 bits +/// contain the value of the parameter. The upper 256 bits are set to zero. +static __inline __m512 __DEFAULT_FN_ATTRS +_mm512_zextps256_ps512(__m256 __a) +{ + return __builtin_shufflevector((__v8sf)__a, (__v8sf)_mm256_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); +} + +/// \brief Constructs a 512-bit integer vector from a 128-bit integer vector. +/// The lower 128 bits contain the value of the source vector. The upper +/// 384 bits are set to zero. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit integer vector. +/// \returns A 512-bit integer vector. The lower 128 bits contain the value of +/// the parameter. The upper 384 bits are set to zero. +static __inline __m512i __DEFAULT_FN_ATTRS +_mm512_zextsi128_si512(__m128i __a) +{ + return __builtin_shufflevector((__v2di)__a, (__v2di)_mm_setzero_si128(), 0, 1, 2, 3, 2, 3, 2, 3); +} + +/// \brief Constructs a 512-bit integer vector from a 256-bit integer vector. +/// The lower 256 bits contain the value of the source vector. The upper +/// 256 bits are set to zero. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 256-bit integer vector. +/// \returns A 512-bit integer vector. The lower 256 bits contain the value of +/// the parameter. The upper 256 bits are set to zero. +static __inline __m512i __DEFAULT_FN_ATTRS +_mm512_zextsi256_si512(__m256i __a) +{ + return __builtin_shufflevector((__v4di)__a, (__v4di)_mm256_setzero_si256(), 0, 1, 2, 3, 4, 5, 6, 7); +} + /* Bitwise operators */ static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_and_epi32(__m512i __a, __m512i __b) diff --git a/contrib/llvm/tools/clang/lib/Headers/avxintrin.h b/contrib/llvm/tools/clang/lib/Headers/avxintrin.h index 5381878a5da3..cdb7aa4fb626 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avxintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avxintrin.h @@ -4523,6 +4523,61 @@ _mm256_castsi128_si256(__m128i __a) return __builtin_shufflevector((__v2di)__a, (__v2di)__a, 0, 1, -1, -1); } +/// \brief Constructs a 256-bit floating-point vector of [4 x double] from a +/// 128-bit floating-point vector of [2 x double]. The lower 128 bits +/// contain the value of the source vector. The upper 128 bits are set +/// to zero. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [2 x double]. +/// \returns A 256-bit floating-point vector of [4 x double]. The lower 128 bits +/// contain the value of the parameter. The upper 128 bits are set to zero. +static __inline __m256d __DEFAULT_FN_ATTRS +_mm256_zextpd128_pd256(__m128d __a) +{ + return __builtin_shufflevector((__v2df)__a, (__v2df)_mm_setzero_pd(), 0, 1, 2, 3); +} + +/// \brief Constructs a 256-bit floating-point vector of [8 x float] from a +/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain +/// the value of the source vector. The upper 128 bits are set to zero. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [4 x float]. +/// \returns A 256-bit floating-point vector of [8 x float]. The lower 128 bits +/// contain the value of the parameter. The upper 128 bits are set to zero. +static __inline __m256 __DEFAULT_FN_ATTRS +_mm256_zextps128_ps256(__m128 __a) +{ + return __builtin_shufflevector((__v4sf)__a, (__v4sf)_mm_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7); +} + +/// \brief Constructs a 256-bit integer vector from a 128-bit integer vector. +/// The lower 128 bits contain the value of the source vector. The upper +/// 128 bits are set to zero. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit integer vector. +/// \returns A 256-bit integer vector. The lower 128 bits contain the value of +/// the parameter. The upper 128 bits are set to zero. +static __inline __m256i __DEFAULT_FN_ATTRS +_mm256_zextsi128_si256(__m128i __a) +{ + return __builtin_shufflevector((__v2di)__a, (__v2di)_mm_setzero_si128(), 0, 1, 2, 3); +} + /* Vector insert. We use macros rather than inlines because we only want to accept diff --git a/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h b/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h index 488eb2dbd3d4..e590cf8bc1ae 100644 --- a/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h @@ -28,107 +28,17 @@ #ifndef __BMIINTRIN_H #define __BMIINTRIN_H -/// \brief Counts the number of trailing zero bits in the operand. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned short _tzcnt_u16(unsigned short a); -/// \endcode -/// -/// This intrinsic corresponds to the <c> TZCNT </c> instruction. -/// -/// \param a -/// An unsigned 16-bit integer whose trailing zeros are to be counted. -/// \returns An unsigned 16-bit integer containing the number of trailing zero -/// bits in the operand. #define _tzcnt_u16(a) (__tzcnt_u16((a))) -/// \brief Performs a bitwise AND of the second operand with the one's -/// complement of the first operand. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned int _andn_u32(unsigned int a, unsigned int b); -/// \endcode -/// -/// This intrinsic corresponds to the <c> ANDN </c> instruction. -/// -/// \param a -/// An unsigned integer containing one of the operands. -/// \param b -/// An unsigned integer containing one of the operands. -/// \returns An unsigned integer containing the bitwise AND of the second -/// operand with the one's complement of the first operand. #define _andn_u32(a, b) (__andn_u32((a), (b))) /* _bextr_u32 != __bextr_u32 */ -/// \brief Clears all bits in the source except for the least significant bit -/// containing a value of 1 and returns the result. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned int _blsi_u32(unsigned int a); -/// \endcode -/// -/// This intrinsic corresponds to the <c> BLSI </c> instruction. -/// -/// \param a -/// An unsigned integer whose bits are to be cleared. -/// \returns An unsigned integer containing the result of clearing the bits from -/// the source operand. #define _blsi_u32(a) (__blsi_u32((a))) -/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and -/// including the least siginificant bit that is set to 1 in the source -/// operand and returns the result. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned int _blsmsk_u32(unsigned int a); -/// \endcode -/// -/// This intrinsic corresponds to the <c> BLSMSK </c> instruction. -/// -/// \param a -/// An unsigned integer used to create the mask. -/// \returns An unsigned integer containing the newly created mask. #define _blsmsk_u32(a) (__blsmsk_u32((a))) -/// \brief Clears the least siginificant bit that is set to 1 in the source -/// operand and returns the result. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned int _blsr_u32(unsigned int a); -/// \endcode -/// -/// This intrinsic corresponds to the <c> BLSR </c> instruction. -/// -/// \param a -/// An unsigned integer containing the operand to be cleared. -/// \returns An unsigned integer containing the result of clearing the source -/// operand. #define _blsr_u32(a) (__blsr_u32((a))) -/// \brief Counts the number of trailing zero bits in the operand. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned int _tzcnt_u32(unsigned int a); -/// \endcode -/// -/// This intrinsic corresponds to the <c> TZCNT </c> instruction. -/// -/// \param a -/// An unsigned 32-bit integer whose trailing zeros are to be counted. -/// \returns An unsigned 32-bit integer containing the number of trailing zero -/// bits in the operand. #define _tzcnt_u32(a) (__tzcnt_u32((a))) /* Define the default attributes for the functions in this file. */ @@ -305,91 +215,15 @@ _mm_tzcnt_32(unsigned int __X) #ifdef __x86_64__ -/// \brief Performs a bitwise AND of the second operand with the one's -/// complement of the first operand. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned long long _andn_u64 (unsigned long long a, unsigned long long b); -/// \endcode -/// -/// This intrinsic corresponds to the <c> ANDN </c> instruction. -/// -/// \param a -/// An unsigned 64-bit integer containing one of the operands. -/// \param b -/// An unsigned 64-bit integer containing one of the operands. -/// \returns An unsigned 64-bit integer containing the bitwise AND of the second -/// operand with the one's complement of the first operand. #define _andn_u64(a, b) (__andn_u64((a), (b))) /* _bextr_u64 != __bextr_u64 */ -/// \brief Clears all bits in the source except for the least significant bit -/// containing a value of 1 and returns the result. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned long long _blsi_u64(unsigned long long a); -/// \endcode -/// -/// This intrinsic corresponds to the <c> BLSI </c> instruction. -/// -/// \param a -/// An unsigned 64-bit integer whose bits are to be cleared. -/// \returns An unsigned 64-bit integer containing the result of clearing the -/// bits from the source operand. #define _blsi_u64(a) (__blsi_u64((a))) -/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and -/// including the least siginificant bit that is set to 1 in the source -/// operand and returns the result. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned long long _blsmsk_u64(unsigned long long a); -/// \endcode -/// -/// This intrinsic corresponds to the <c> BLSMSK </c> instruction. -/// -/// \param a -/// An unsigned 64-bit integer used to create the mask. -/// \returns A unsigned 64-bit integer containing the newly created mask. #define _blsmsk_u64(a) (__blsmsk_u64((a))) -/// \brief Clears the least siginificant bit that is set to 1 in the source -/// operand and returns the result. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned long long _blsr_u64(unsigned long long a); -/// \endcode -/// -/// This intrinsic corresponds to the <c> BLSR </c> instruction. -/// -/// \param a -/// An unsigned 64-bit integer containing the operand to be cleared. -/// \returns An unsigned 64-bit integer containing the result of clearing the -/// source operand. #define _blsr_u64(a) (__blsr_u64((a))) -/// \brief Counts the number of trailing zero bits in the operand. -/// -/// \headerfile <x86intrin.h> -/// -/// \code -/// unsigned long long _tzcnt_u64(unsigned long long a); -/// \endcode -/// -/// This intrinsic corresponds to the <c> TZCNT </c> instruction. -/// -/// \param a -/// An unsigned 64-bit integer whose trailing zeros are to be counted. -/// \returns An unsigned 64-bit integer containing the number of trailing zero -/// bits in the operand. #define _tzcnt_u64(a) (__tzcnt_u64((a))) /// \brief Performs a bitwise AND of the second operand with the one's diff --git a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h index 0dfa6a9fbc1f..13b0db22ec44 100644 --- a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h @@ -1750,6 +1750,24 @@ _mm_set1_pd(double __w) return (__m128d){ __w, __w }; } +/// \brief Constructs a 128-bit floating-point vector of [2 x double], with each +/// of the two double-precision floating-point vector elements set to the +/// specified double-precision floating-point value. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the <c> VMOVDDUP / MOVLHPS </c> instruction. +/// +/// \param __w +/// A double-precision floating-point value used to initialize each vector +/// element of the result. +/// \returns An initialized 128-bit floating-point vector of [2 x double]. +static __inline__ __m128d __DEFAULT_FN_ATTRS +_mm_set_pd1(double __w) +{ + return _mm_set1_pd(__w); +} + /// \brief Constructs a 128-bit floating-point vector of [2 x double] /// initialized with the specified double-precision floating-point values. /// diff --git a/contrib/llvm/tools/clang/lib/Headers/stdint.h b/contrib/llvm/tools/clang/lib/Headers/stdint.h index 3f2fcbc57023..c48815314b51 100644 --- a/contrib/llvm/tools/clang/lib/Headers/stdint.h +++ b/contrib/llvm/tools/clang/lib/Headers/stdint.h @@ -255,19 +255,16 @@ typedef __uint_least8_t uint_fast8_t; */ #define __stdint_join3(a,b,c) a ## b ## c -#define __intn_t(n) __stdint_join3( int, n, _t) -#define __uintn_t(n) __stdint_join3(uint, n, _t) - #ifndef _INTPTR_T #ifndef __intptr_t_defined -typedef __intn_t(__INTPTR_WIDTH__) intptr_t; +typedef __INTPTR_TYPE__ intptr_t; #define __intptr_t_defined #define _INTPTR_T #endif #endif #ifndef _UINTPTR_T -typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t; +typedef __UINTPTR_TYPE__ uintptr_t; #define _UINTPTR_T #endif @@ -659,12 +656,12 @@ typedef __UINTMAX_TYPE__ uintmax_t; /* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */ /* C99 7.18.3 Limits of other integer types. */ -#define INTPTR_MIN __INTN_MIN(__INTPTR_WIDTH__) -#define INTPTR_MAX __INTN_MAX(__INTPTR_WIDTH__) -#define UINTPTR_MAX __UINTN_MAX(__INTPTR_WIDTH__) -#define PTRDIFF_MIN __INTN_MIN(__PTRDIFF_WIDTH__) -#define PTRDIFF_MAX __INTN_MAX(__PTRDIFF_WIDTH__) -#define SIZE_MAX __UINTN_MAX(__SIZE_WIDTH__) +#define INTPTR_MIN (-__INTPTR_MAX__-1) +#define INTPTR_MAX __INTPTR_MAX__ +#define UINTPTR_MAX __UINTPTR_MAX__ +#define PTRDIFF_MIN (-__PTRDIFF_MAX__-1) +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#define SIZE_MAX __SIZE_MAX__ /* ISO9899:2011 7.20 (C11 Annex K): Define RSIZE_MAX if __STDC_WANT_LIB_EXT1__ * is enabled. */ @@ -673,9 +670,9 @@ typedef __UINTMAX_TYPE__ uintmax_t; #endif /* C99 7.18.2.5 Limits of greatest-width integer types. */ -#define INTMAX_MIN __INTN_MIN(__INTMAX_WIDTH__) -#define INTMAX_MAX __INTN_MAX(__INTMAX_WIDTH__) -#define UINTMAX_MAX __UINTN_MAX(__INTMAX_WIDTH__) +#define INTMAX_MIN (-__INTMAX_MAX__-1) +#define INTMAX_MAX __INTMAX_MAX__ +#define UINTMAX_MAX __UINTMAX_MAX__ /* C99 7.18.3 Limits of other integer types. */ #define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__) @@ -700,8 +697,8 @@ typedef __UINTMAX_TYPE__ uintmax_t; #endif /* 7.18.4.2 Macros for greatest-width integer constants. */ -#define INTMAX_C(v) __INTN_C(__INTMAX_WIDTH__, v) -#define UINTMAX_C(v) __UINTN_C(__INTMAX_WIDTH__, v) +#define INTMAX_C(v) __int_c(v, __INTMAX_C_SUFFIX__) +#define UINTMAX_C(v) __int_c(v, __UINTMAX_C_SUFFIX__) #endif /* __STDC_HOSTED__ */ #endif /* __CLANG_STDINT_H */ diff --git a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp index c1eed1684cbd..e8b2f1052d73 100644 --- a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp @@ -481,17 +481,17 @@ public: return true; assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); + SymbolRoleSet AccessorMethodRoles = + SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) - IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {}, - Container); + IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) - IndexCtx.handleDecl(MD, Loc, SymbolRoleSet(SymbolRole::Implicit), {}, - Container); + IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { if (IvarD->getSynthesize()) { diff --git a/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp b/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp index ed469f677a34..044edf715fc2 100644 --- a/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp +++ b/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp @@ -811,7 +811,13 @@ void USRGenerator::VisitType(QualType T) { T = InjT->getInjectedSpecializationType(); continue; } - + if (const auto *VT = T->getAs<VectorType>()) { + Out << (T->isExtVectorType() ? ']' : '['); + Out << VT->getNumElements(); + T = VT->getElementType(); + continue; + } + // Unhandled type. Out << ' '; break; diff --git a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp index 4ee38719289b..bd425a07c33a 100644 --- a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp @@ -624,7 +624,10 @@ const FileEntry *HeaderSearch::LookupFile( ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache, bool BuildSystemModule) { + bool *IsMapped, bool SkipCache, bool BuildSystemModule) { + if (IsMapped) + *IsMapped = false; + if (SuggestedModule) *SuggestedModule = ModuleMap::KnownHeader(); @@ -754,8 +757,11 @@ const FileEntry *HeaderSearch::LookupFile( if (!SkipCache && CacheLookup.StartIdx == i+1) { // Skip querying potentially lots of directories for this lookup. i = CacheLookup.HitIdx; - if (CacheLookup.MappedName) + if (CacheLookup.MappedName) { Filename = CacheLookup.MappedName; + if (IsMapped) + *IsMapped = true; + } } else { // Otherwise, this is the first query, or the previous query didn't match // our search start. We will fill in our found location below, so prime the @@ -776,6 +782,8 @@ const FileEntry *HeaderSearch::LookupFile( if (HasBeenMapped) { CacheLookup.MappedName = copyString(Filename, LookupFileCache.getAllocator()); + if (IsMapped) + *IsMapped = true; } if (!FE) continue; @@ -839,7 +847,7 @@ const FileEntry *HeaderSearch::LookupFile( const FileEntry *FE = LookupFile(ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir, Includers.front(), SearchPath, RelativePath, - RequestingModule, SuggestedModule); + RequestingModule, SuggestedModule, IsMapped); if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) { if (SuggestedModule) diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp index 924613dcb840..bec434085e3a 100644 --- a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp @@ -33,7 +33,7 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) UsedForHeaderGuard(false) { } -unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const { +unsigned MacroInfo::getDefinitionLengthSlow(const SourceManager &SM) const { assert(!IsDefinitionLengthCached); IsDefinitionLengthCached = true; diff --git a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp index 8a56ddf23699..4826e399afda 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp @@ -752,16 +752,11 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc, } const FileEntry *Preprocessor::LookupFile( - SourceLocation FilenameLoc, - StringRef Filename, - bool isAngled, - const DirectoryLookup *FromDir, - const FileEntry *FromFile, - const DirectoryLookup *&CurDir, - SmallVectorImpl<char> *SearchPath, + SourceLocation FilenameLoc, StringRef Filename, bool isAngled, + const DirectoryLookup *FromDir, const FileEntry *FromFile, + const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, - ModuleMap::KnownHeader *SuggestedModule, - bool SkipCache) { + ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool SkipCache) { Module *RequestingModule = getModuleForLocation(FilenameLoc); bool RequestingModuleIsModuleInterface = !SourceMgr.isInMainFile(FilenameLoc); @@ -819,7 +814,7 @@ const FileEntry *Preprocessor::LookupFile( while (const FileEntry *FE = HeaderInfo.LookupFile( Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir, Includers, SearchPath, RelativePath, RequestingModule, - SuggestedModule, SkipCache)) { + SuggestedModule, /*IsMapped=*/nullptr, SkipCache)) { // Keep looking as if this file did a #include_next. TmpFromDir = TmpCurDir; ++TmpFromDir; @@ -835,7 +830,7 @@ const FileEntry *Preprocessor::LookupFile( // Do a standard file entry lookup. const FileEntry *FE = HeaderInfo.LookupFile( Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath, - RelativePath, RequestingModule, SuggestedModule, SkipCache, + RelativePath, RequestingModule, SuggestedModule, IsMapped, SkipCache, BuildSystemModule); if (FE) { if (SuggestedModule && !LangOpts.AsmPreprocessor) @@ -1593,18 +1588,18 @@ bool Preprocessor::ConcatenateIncludeName(SmallString<128> &FilenameBuffer, } /// \brief Push a token onto the token stream containing an annotation. -static void EnterAnnotationToken(Preprocessor &PP, - SourceLocation Begin, SourceLocation End, - tok::TokenKind Kind, void *AnnotationVal) { +void Preprocessor::EnterAnnotationToken(SourceRange Range, + tok::TokenKind Kind, + void *AnnotationVal) { // FIXME: Produce this as the current token directly, rather than // allocating a new token for it. auto Tok = llvm::make_unique<Token[]>(1); Tok[0].startToken(); Tok[0].setKind(Kind); - Tok[0].setLocation(Begin); - Tok[0].setAnnotationEndLoc(End); + Tok[0].setLocation(Range.getBegin()); + Tok[0].setAnnotationEndLoc(Range.getEnd()); Tok[0].setAnnotationValue(AnnotationVal); - PP.EnterTokenStream(std::move(Tok), 1, true); + EnterTokenStream(std::move(Tok), 1, true); } /// \brief Produce a diagnostic informing the user that a #include or similar @@ -1783,6 +1778,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, } // Search include directories. + bool IsMapped = false; const DirectoryLookup *CurDir; SmallString<1024> SearchPath; SmallString<1024> RelativePath; @@ -1801,7 +1797,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled, LookupFrom, LookupFromFile, CurDir, Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr, - &SuggestedModule); + &SuggestedModule, &IsMapped); if (!File) { if (Callbacks) { @@ -1818,7 +1814,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled, LookupFrom, LookupFromFile, CurDir, nullptr, nullptr, - &SuggestedModule, /*SkipCache*/ true); + &SuggestedModule, &IsMapped, /*SkipCache*/ true); } } } @@ -1833,8 +1829,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, false, LookupFrom, LookupFromFile, CurDir, Callbacks ? &SearchPath : nullptr, - Callbacks ? &RelativePath : nullptr, - &SuggestedModule); + Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped); if (File) { SourceRange Range(FilenameTok.getLocation(), CharEnd); Diag(FilenameTok, diag::err_pp_file_not_found_not_fatal) << @@ -1964,7 +1959,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // Issue a diagnostic if the name of the file on disk has a different case // than the one we're about to open. const bool CheckIncludePathPortability = - File && !File->tryGetRealPathName().empty(); + !IsMapped && File && !File->tryGetRealPathName().empty(); if (CheckIncludePathPortability) { StringRef Name = LangOpts.MSVCCompat ? NormalizedPath.str() : Filename; @@ -2026,7 +2021,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, if (IncludeTok.getIdentifierInfo()->getPPKeywordID() != tok::pp___include_macros) - EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_include, M); + EnterAnnotationToken(SourceRange(HashLoc, End), + tok::annot_module_include, M); } return; } @@ -2064,7 +2060,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // submodule. // FIXME: There's no point doing this if we're handling a #__include_macros // directive. - EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_begin, M); + EnterAnnotationToken(SourceRange(HashLoc, End), tok::annot_module_begin, M); } } @@ -2592,25 +2588,26 @@ void Preprocessor::HandleUndefDirective() { // Okay, we have a valid identifier to undef. auto *II = MacroNameTok.getIdentifierInfo(); auto MD = getMacroDefinition(II); + UndefMacroDirective *Undef = nullptr; + + // If the macro is not defined, this is a noop undef. + if (const MacroInfo *MI = MD.getMacroInfo()) { + if (!MI->isUsed() && MI->isWarnIfUnused()) + Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used); + + if (MI->isWarnIfUnused()) + WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); + + Undef = AllocateUndefMacroDirective(MacroNameTok.getLocation()); + } // If the callbacks want to know, tell them about the macro #undef. // Note: no matter if the macro was defined or not. if (Callbacks) - Callbacks->MacroUndefined(MacroNameTok, MD); - - // If the macro is not defined, this is a noop undef, just return. - const MacroInfo *MI = MD.getMacroInfo(); - if (!MI) - return; - - if (!MI->isUsed() && MI->isWarnIfUnused()) - Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used); - - if (MI->isWarnIfUnused()) - WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); + Callbacks->MacroUndefined(MacroNameTok, MD, Undef); - appendMacroDirective(MacroNameTok.getIdentifierInfo(), - AllocateUndefMacroDirective(MacroNameTok.getLocation())); + if (Undef) + appendMacroDirective(II, Undef); } //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp index cf0c953b61f8..fcc49b387034 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp @@ -287,6 +287,48 @@ const char *Preprocessor::getCurLexerEndPos() { return EndPos; } +static void collectAllSubModulesWithUmbrellaHeader( + const Module &Mod, SmallVectorImpl<const Module *> &SubMods) { + if (Mod.getUmbrellaHeader()) + SubMods.push_back(&Mod); + for (auto *M : Mod.submodules()) + collectAllSubModulesWithUmbrellaHeader(*M, SubMods); +} + +void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) { + assert(Mod.getUmbrellaHeader() && "Module must use umbrella header"); + SourceLocation StartLoc = + SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); + if (getDiagnostics().isIgnored(diag::warn_uncovered_module_header, StartLoc)) + return; + + ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap(); + const DirectoryEntry *Dir = Mod.getUmbrellaDir().Entry; + vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); + std::error_code EC; + for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End; + Entry != End && !EC; Entry.increment(EC)) { + using llvm::StringSwitch; + + // Check whether this entry has an extension typically associated with + // headers. + if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName())) + .Cases(".h", ".H", ".hh", ".hpp", true) + .Default(false)) + continue; + + if (const FileEntry *Header = getFileManager().getFile(Entry->getName())) + if (!getSourceManager().hasFileInfo(Header)) { + if (!ModMap.isHeaderInUnavailableModule(Header)) { + // Find the relative path that would access this header. + SmallString<128> RelativePath; + computeRelativePath(FileMgr, Dir, Header, RelativePath); + Diag(StartLoc, diag::warn_uncovered_module_header) + << Mod.getFullModuleName() << RelativePath; + } + } + } +} /// HandleEndOfFile - This callback is invoked when the lexer hits the end of /// the current file. This either returns the EOF token or pops a level off @@ -473,44 +515,14 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { } // If we are building a module that has an umbrella header, make sure that - // each of the headers within the directory covered by the umbrella header - // was actually included by the umbrella header. + // each of the headers within the directory, including all submodules, is + // covered by the umbrella header was actually included by the umbrella + // header. if (Module *Mod = getCurrentModule()) { - if (Mod->getUmbrellaHeader()) { - SourceLocation StartLoc - = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); - - if (!getDiagnostics().isIgnored(diag::warn_uncovered_module_header, - StartLoc)) { - ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap(); - const DirectoryEntry *Dir = Mod->getUmbrellaDir().Entry; - vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem(); - std::error_code EC; - for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End; - Entry != End && !EC; Entry.increment(EC)) { - using llvm::StringSwitch; - - // Check whether this entry has an extension typically associated with - // headers. - if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName())) - .Cases(".h", ".H", ".hh", ".hpp", true) - .Default(false)) - continue; - - if (const FileEntry *Header = - getFileManager().getFile(Entry->getName())) - if (!getSourceManager().hasFileInfo(Header)) { - if (!ModMap.isHeaderInUnavailableModule(Header)) { - // Find the relative path that would access this header. - SmallString<128> RelativePath; - computeRelativePath(FileMgr, Dir, Header, RelativePath); - Diag(StartLoc, diag::warn_uncovered_module_header) - << Mod->getFullModuleName() << RelativePath; - } - } - } - } - } + llvm::SmallVector<const Module *, 4> AllMods; + collectAllSubModulesWithUmbrellaHeader(*Mod, AllMods); + for (auto *M : AllMods) + diagnoseMissingHeaderInUmbrellaDir(*M); } return true; diff --git a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp index 358c96a78300..196223981d74 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp @@ -1422,7 +1422,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok, const DirectoryLookup *CurDir; const FileEntry *File = PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile, - CurDir, nullptr, nullptr, nullptr); + CurDir, nullptr, nullptr, nullptr, nullptr); // Get the result value. A result of true means the file exists. return File != nullptr; diff --git a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp index 87e105d1d03d..576151a98b2c 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp @@ -508,7 +508,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { const DirectoryLookup *CurDir; const FileEntry *File = LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr, - nullptr, CurDir, nullptr, nullptr, nullptr); + nullptr, CurDir, nullptr, nullptr, nullptr, nullptr); if (!File) { if (!SuppressIncludeNotFoundError) Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; @@ -534,6 +534,47 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { } } +void Preprocessor::HandlePragmaModuleImport(Token &ImportTok) { + SourceLocation ImportLoc = ImportTok.getLocation(); + + Token Tok; + + llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8> ModuleName; + while (true) { + LexUnexpandedToken(Tok); + if (Tok.isNot(tok::identifier)) { + Diag(Tok.getLocation(), + diag::err_pragma_module_import_expected_module_name) << 0; + return; + } + + ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation()); + + LexUnexpandedToken(Tok); + assert(Tok.isNot(tok::eof)); + if (Tok.is(tok::eod)) + break; + if (Tok.isNot(tok::period)) { + Diag(Tok.getLocation(), + diag::err_pragma_module_import_expected_module_name) << 1; + return; + } + } + + // If we have a non-empty module path, load the named module. + Module *Imported = + TheModuleLoader.loadModule(ImportLoc, ModuleName, Module::Hidden, + /*IsIncludeDirective=*/false); + if (!Imported) + return; + + makeModuleVisible(Imported, ImportLoc); + EnterAnnotationToken(SourceRange(ImportLoc, Tok.getLocation()), + tok::annot_module_include, Imported); + if (Callbacks) + Callbacks->moduleImport(ImportLoc, ModuleName, Imported); +} + /// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. /// Return the IdentifierInfo* associated with the macro to push or pop. IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { @@ -1301,6 +1342,19 @@ public: } }; +/// Handle the clang \#pragma module import extension. The syntax is: +/// \code +/// #pragma clang module import some.module.name +/// \endcode +struct PragmaModuleImportHandler : public PragmaHandler { + PragmaModuleImportHandler() : PragmaHandler("import") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &ImportTok) override { + PP.HandlePragmaModuleImport(ImportTok); + } +}; + /// PragmaPushMacroHandler - "\#pragma push_macro" saves the value of the /// macro on the top of the stack. struct PragmaPushMacroHandler : public PragmaHandler { @@ -1524,6 +1578,11 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler()); AddPragmaHandler("clang", new PragmaAssumeNonNullHandler()); + // #pragma clang module ... + auto *ModuleHandler = new PragmaNamespace("module"); + AddPragmaHandler("clang", ModuleHandler); + ModuleHandler->AddPragma(new PragmaModuleImportHandler()); + AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler()); AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler()); AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler()); diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp index 13e15f3c943b..03c4cbe589d5 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp @@ -422,7 +422,8 @@ void PreprocessingRecord::MacroDefined(const Token &Id, } void PreprocessingRecord::MacroUndefined(const Token &Id, - const MacroDefinition &MD) { + const MacroDefinition &MD, + const MacroDirective *Undef) { MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); }); } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp index dfb0438ba8ce..86ac035f3c8c 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp @@ -1690,6 +1690,30 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.MapType = OMPC_MAP_tofrom; Data.IsMapTypeImplicit = true; } + } else if (IsMapClauseModifierToken(PP.LookAhead(0))) { + if (PP.LookAhead(1).is(tok::colon)) { + Data.MapTypeModifier = Data.MapType; + if (Data.MapTypeModifier != OMPC_MAP_always) { + Diag(Tok, diag::err_omp_unknown_map_type_modifier); + Data.MapTypeModifier = OMPC_MAP_unknown; + } else + MapTypeModifierSpecified = true; + + ConsumeToken(); + + Data.MapType = + IsMapClauseModifierToken(Tok) + ? static_cast<OpenMPMapClauseKind>( + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))) + : OMPC_MAP_unknown; + if (Data.MapType == OMPC_MAP_unknown || + Data.MapType == OMPC_MAP_always) + Diag(Tok, diag::err_omp_unknown_map_type); + ConsumeToken(); + } else { + Data.MapType = OMPC_MAP_tofrom; + Data.IsMapTypeImplicit = true; + } } else { Data.MapType = OMPC_MAP_tofrom; Data.IsMapTypeImplicit = true; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 044ec74679d5..a206100b89eb 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -759,7 +759,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: - if (SemaBuiltinVAStart(TheCall)) + if (SemaBuiltinVAStart(BuiltinID, TheCall)) return ExprError(); break; case Builtin::BI__va_start: { @@ -770,7 +770,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; default: - if (SemaBuiltinVAStart(TheCall)) + if (SemaBuiltinVAStart(BuiltinID, TheCall)) return ExprError(); break; } @@ -2090,7 +2090,7 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return SemaBuiltinCpuSupports(*this, TheCall); if (BuiltinID == X86::BI__builtin_ms_va_start) - return SemaBuiltinMSVAStart(TheCall); + return SemaBuiltinVAStart(BuiltinID, TheCall); // If the intrinsic has rounding or SAE make sure its valid. if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) @@ -3611,11 +3611,81 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) { return Result; } +/// Check that the user is calling the appropriate va_start builtin for the +/// target and calling convention. +static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) { + const llvm::Triple &TT = S.Context.getTargetInfo().getTriple(); + bool IsX64 = TT.getArch() == llvm::Triple::x86_64; + bool IsWindows = TT.isOSWindows(); + bool IsMSVAStart = BuiltinID == X86::BI__builtin_ms_va_start; + if (IsX64) { + clang::CallingConv CC = CC_C; + if (const FunctionDecl *FD = S.getCurFunctionDecl()) + CC = FD->getType()->getAs<FunctionType>()->getCallConv(); + if (IsMSVAStart) { + // Don't allow this in System V ABI functions. + if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_X86_64Win64)) + return S.Diag(Fn->getLocStart(), + diag::err_ms_va_start_used_in_sysv_function); + } else { + // On x86-64 Unix, don't allow this in Win64 ABI functions. + // On x64 Windows, don't allow this in System V ABI functions. + // (Yes, that means there's no corresponding way to support variadic + // System V ABI functions on Windows.) + if ((IsWindows && CC == CC_X86_64SysV) || + (!IsWindows && CC == CC_X86_64Win64)) + return S.Diag(Fn->getLocStart(), + diag::err_va_start_used_in_wrong_abi_function) + << !IsWindows; + } + return false; + } + + if (IsMSVAStart) + return S.Diag(Fn->getLocStart(), diag::err_x86_builtin_64_only); + return false; +} + +static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn, + ParmVarDecl **LastParam = nullptr) { + // Determine whether the current function, block, or obj-c method is variadic + // and get its parameter list. + bool IsVariadic = false; + ArrayRef<ParmVarDecl *> Params; + if (BlockScopeInfo *CurBlock = S.getCurBlock()) { + IsVariadic = CurBlock->TheDecl->isVariadic(); + Params = CurBlock->TheDecl->parameters(); + } else if (FunctionDecl *FD = S.getCurFunctionDecl()) { + IsVariadic = FD->isVariadic(); + Params = FD->parameters(); + } else if (ObjCMethodDecl *MD = S.getCurMethodDecl()) { + IsVariadic = MD->isVariadic(); + // FIXME: This isn't correct for methods (results in bogus warning). + Params = MD->parameters(); + } else { + llvm_unreachable("unknown va_start context"); + } + + if (!IsVariadic) { + S.Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); + return true; + } + + if (LastParam) + *LastParam = Params.empty() ? nullptr : Params.back(); + + return false; +} + /// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start' /// for validity. Emit an error and return true on failure; return false /// on success. -bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { +bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { Expr *Fn = TheCall->getCallee(); + + if (checkVAStartABI(*this, BuiltinID, Fn)) + return true; + if (TheCall->getNumArgs() > 2) { Diag(TheCall->getArg(2)->getLocStart(), diag::err_typecheck_call_too_many_args) @@ -3636,20 +3706,10 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { if (checkBuiltinArgument(*this, TheCall, 0)) return true; - // Determine whether the current function is variadic or not. - BlockScopeInfo *CurBlock = getCurBlock(); - bool isVariadic; - if (CurBlock) - isVariadic = CurBlock->TheDecl->isVariadic(); - else if (FunctionDecl *FD = getCurFunctionDecl()) - isVariadic = FD->isVariadic(); - else - isVariadic = getCurMethodDecl()->isVariadic(); - - if (!isVariadic) { - Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); + // Check that the current function is variadic, and get its last parameter. + ParmVarDecl *LastParam; + if (checkVAStartIsInVariadicFunction(*this, Fn, &LastParam)) return true; - } // Verify that the second argument to the builtin is the last argument of the // current function or method. @@ -3664,16 +3724,7 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) { if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) { - // FIXME: This isn't correct for methods (results in bogus warning). - // Get the last formal in the current function. - const ParmVarDecl *LastArg; - if (CurBlock) - LastArg = CurBlock->TheDecl->parameters().back(); - else if (FunctionDecl *FD = getCurFunctionDecl()) - LastArg = FD->parameters().back(); - else - LastArg = getCurMethodDecl()->parameters().back(); - SecondArgIsLastNamedArgument = PV == LastArg; + SecondArgIsLastNamedArgument = PV == LastParam; Type = PV->getType(); ParamLoc = PV->getLocation(); @@ -3708,48 +3759,6 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { return false; } -/// Check the arguments to '__builtin_va_start' for validity, and that -/// it was called from a function of the native ABI. -/// Emit an error and return true on failure; return false on success. -bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { - // On x86-64 Unix, don't allow this in Win64 ABI functions. - // On x64 Windows, don't allow this in System V ABI functions. - // (Yes, that means there's no corresponding way to support variadic - // System V ABI functions on Windows.) - if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64) { - unsigned OS = Context.getTargetInfo().getTriple().getOS(); - clang::CallingConv CC = CC_C; - if (const FunctionDecl *FD = getCurFunctionDecl()) - CC = FD->getType()->getAs<FunctionType>()->getCallConv(); - if ((OS == llvm::Triple::Win32 && CC == CC_X86_64SysV) || - (OS != llvm::Triple::Win32 && CC == CC_X86_64Win64)) - return Diag(TheCall->getCallee()->getLocStart(), - diag::err_va_start_used_in_wrong_abi_function) - << (OS != llvm::Triple::Win32); - } - return SemaBuiltinVAStartImpl(TheCall); -} - -/// Check the arguments to '__builtin_ms_va_start' for validity, and that -/// it was called from a Win64 ABI function. -/// Emit an error and return true on failure; return false on success. -bool Sema::SemaBuiltinMSVAStart(CallExpr *TheCall) { - // This only makes sense for x86-64. - const llvm::Triple &TT = Context.getTargetInfo().getTriple(); - Expr *Callee = TheCall->getCallee(); - if (TT.getArch() != llvm::Triple::x86_64) - return Diag(Callee->getLocStart(), diag::err_x86_builtin_32_bit_tgt); - // Don't allow this in System V ABI functions. - clang::CallingConv CC = CC_C; - if (const FunctionDecl *FD = getCurFunctionDecl()) - CC = FD->getType()->getAs<FunctionType>()->getCallConv(); - if (CC == CC_X86_64SysV || - (TT.getOS() != llvm::Triple::Win32 && CC != CC_X86_64Win64)) - return Diag(Callee->getLocStart(), - diag::err_ms_va_start_used_in_sysv_function); - return SemaBuiltinVAStartImpl(TheCall); -} - bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { // void __va_start(va_list *ap, const char *named_addr, size_t slot_size, // const char *named_addr); @@ -3761,26 +3770,14 @@ bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { diag::err_typecheck_call_too_few_args_at_least) << 0 /*function call*/ << 3 << Call->getNumArgs(); - // Determine whether the current function is variadic or not. - bool IsVariadic; - if (BlockScopeInfo *CurBlock = getCurBlock()) - IsVariadic = CurBlock->TheDecl->isVariadic(); - else if (FunctionDecl *FD = getCurFunctionDecl()) - IsVariadic = FD->isVariadic(); - else if (ObjCMethodDecl *MD = getCurMethodDecl()) - IsVariadic = MD->isVariadic(); - else - llvm_unreachable("unexpected statement type"); - - if (!IsVariadic) { - Diag(Func->getLocStart(), diag::err_va_start_used_in_non_variadic_function); - return true; - } - // Type-check the first argument normally. if (checkBuiltinArgument(*this, Call, 0)) return true; + // Check that the current function is variadic. + if (checkVAStartIsInVariadicFunction(*this, Func)) + return true; + const struct { unsigned ArgNo; QualType Type; @@ -9866,25 +9863,6 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { ::CheckBoolLikeConversion(*this, E, CC); } -/// Diagnose when expression is an integer constant expression and its evaluation -/// results in integer overflow -void Sema::CheckForIntOverflow (Expr *E) { - // Use a work list to deal with nested struct initializers. - SmallVector<Expr *, 2> Exprs(1, E); - - do { - Expr *E = Exprs.pop_back_val(); - - if (isa<BinaryOperator>(E->IgnoreParenCasts())) { - E->IgnoreParenCasts()->EvaluateForOverflow(Context); - continue; - } - - if (auto InitList = dyn_cast<InitListExpr>(E)) - Exprs.append(InitList->inits().begin(), InitList->inits().end()); - } while (!Exprs.empty()); -} - namespace { /// \brief Visitor for expressions which looks for unsequenced operations on the /// same object. @@ -10386,7 +10364,7 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, if (!E->isInstantiationDependent()) CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) - CheckForIntOverflow(E); + E->EvaluateForOverflow(Context); DiagnoseMisalignedMembers(); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp index f838c9a4877d..d4c0783638d1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp @@ -2951,7 +2951,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, // Merge ns_returns_retained attribute. if (OldTypeInfo.getProducesResult() != NewTypeInfo.getProducesResult()) { if (NewTypeInfo.getProducesResult()) { - Diag(New->getLocation(), diag::err_returns_retained_mismatch); + Diag(New->getLocation(), diag::err_function_attribute_mismatch) + << "'ns_returns_retained'"; Diag(OldLocation, diag::note_previous_declaration); return true; } @@ -2960,6 +2961,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, RequiresAdjustment = true; } + if (OldTypeInfo.getNoCallerSavedRegs() != + NewTypeInfo.getNoCallerSavedRegs()) { + if (NewTypeInfo.getNoCallerSavedRegs()) { + AnyX86NoCallerSavedRegistersAttr *Attr = + New->getAttr<AnyX86NoCallerSavedRegistersAttr>(); + Diag(New->getLocation(), diag::err_function_attribute_mismatch) << Attr; + Diag(OldLocation, diag::note_previous_declaration); + return true; + } + + NewTypeInfo = NewTypeInfo.withNoCallerSavedRegs(true); + RequiresAdjustment = true; + } + if (RequiresAdjustment) { const FunctionType *AdjustedType = New->getType()->getAs<FunctionType>(); AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo); @@ -7410,6 +7425,10 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback { } // end anonymous namespace +void Sema::MarkTypoCorrectedFunctionDefinition(const NamedDecl *F) { + TypoCorrectedFunctionDefinitions.insert(F); +} + /// \brief Generate diagnostics for an invalid function redeclaration. /// /// This routine handles generating the diagnostic messages for an invalid @@ -7507,6 +7526,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration( if ((*I)->getCanonicalDecl() == Canonical) Correction.setCorrectionDecl(*I); + // Let Sema know about the correction. + SemaRef.MarkTypoCorrectedFunctionDefinition(Result); SemaRef.diagnoseTypo( Correction, SemaRef.PDiag(IsLocalFriend @@ -11718,6 +11739,11 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, if (canRedefineFunction(Definition, getLangOpts())) return; + // Don't emit an error when this is redifinition of a typo-corrected + // definition. + if (TypoCorrectedFunctionDefinitions.count(Definition)) + return; + // If we don't have a visible definition of the function, and it's inline or // a template, skip the new definition. if (SkipBody && !hasVisibleDefinition(Definition) && diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index 17c6975ca5e9..bb5434a03a10 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -1941,17 +1941,26 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { if (hasDeclarator(D)) return; - if (S.CheckNoReturnAttr(attr)) return; + if (S.CheckNoReturnAttr(attr)) + return; if (!isa<ObjCMethodDecl>(D)) { S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << ExpectedFunctionOrMethod; + << attr.getName() << ExpectedFunctionOrMethod; return; } - D->addAttr(::new (S.Context) - NoReturnAttr(attr.getRange(), S.Context, - attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NoReturnAttr( + attr.getRange(), S.Context, attr.getAttributeSpellingListIndex())); +} + +static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (S.CheckNoCallerSavedRegsAttr(Attr)) + return; + + D->addAttr(::new (S.Context) AnyX86NoCallerSavedRegistersAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } bool Sema::CheckNoReturnAttr(const AttributeList &attr) { @@ -1963,6 +1972,22 @@ bool Sema::CheckNoReturnAttr(const AttributeList &attr) { return false; } +bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &Attr) { + // Check whether the attribute is valid on the current target. + if (!Attr.existsInTarget(Context.getTargetInfo())) { + Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) << Attr.getName(); + Attr.setInvalid(); + return true; + } + + if (!checkAttributeNumArgs(*this, Attr, 0)) { + Attr.setInvalid(); + return true; + } + + return false; +} + static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -6428,6 +6453,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; + case AttributeList::AT_AnyX86NoCallerSavedRegisters: + handleNoCallerSavedRegsAttr(S, D, Attr); + break; case AttributeList::AT_RenderScriptKernel: handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr); break; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp index 4f51cd399c0c..fe9ba6f1f811 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp @@ -4313,6 +4313,51 @@ static void mergeInterfaceMethodToImpl(Sema &S, } } +/// Verify that the method parameters/return value have types that are supported +/// by the x86 target. +static void checkObjCMethodX86VectorTypes(Sema &SemaRef, + const ObjCMethodDecl *Method) { + assert(SemaRef.getASTContext().getTargetInfo().getTriple().getArch() == + llvm::Triple::x86 && + "x86-specific check invoked for a different target"); + SourceLocation Loc; + QualType T; + for (const ParmVarDecl *P : Method->parameters()) { + if (P->getType()->isVectorType()) { + Loc = P->getLocStart(); + T = P->getType(); + break; + } + } + if (Loc.isInvalid()) { + if (Method->getReturnType()->isVectorType()) { + Loc = Method->getReturnTypeSourceRange().getBegin(); + T = Method->getReturnType(); + } else + return; + } + + // Vector parameters/return values are not supported by objc_msgSend on x86 in + // iOS < 9 and macOS < 10.11. + const auto &Triple = SemaRef.getASTContext().getTargetInfo().getTriple(); + VersionTuple AcceptedInVersion; + if (Triple.getOS() == llvm::Triple::IOS) + AcceptedInVersion = VersionTuple(/*Major=*/9); + else if (Triple.isMacOSX()) + AcceptedInVersion = VersionTuple(/*Major=*/10, /*Minor=*/11); + else + return; + VersionTuple MethodVersion = Method->getVersionIntroduced(); + if (SemaRef.getASTContext().getTargetInfo().getPlatformMinVersion() >= + AcceptedInVersion && + (MethodVersion.empty() || MethodVersion >= AcceptedInVersion)) + return; + SemaRef.Diag(Loc, diag::err_objc_method_unsupported_param_ret_type) + << T << (Method->getReturnType()->isVectorType() ? /*return value*/ 1 + : /*parameter*/ 0) + << (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9"); +} + Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, @@ -4534,6 +4579,10 @@ Decl *Sema::ActOnMethodDeclaration( ObjCMethod->SetRelatedResultType(); } + if (MethodDefinition && + Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) + checkObjCMethodX86VectorTypes(*this, ObjCMethod); + ActOnDocumentableDecl(ObjCMethod); return ObjCMethod; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index 00480f821fc6..d63151ef6759 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -5275,8 +5275,7 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); - // We aren't supposed to apply this logic for if there'Scope an '&' - // involved. + // We aren't supposed to apply this logic if there's an '&' involved. if (!find.HasFormOfMemberPointer) { OverloadExpr *ovl = find.Expression; if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl)) @@ -6432,14 +6431,13 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, return S.Context .getQualifiedType(CompositeTy.getUnqualifiedType(), CompositeQuals) .withCVRQualifiers(MergedCVRQual); - } else - return CompositeTy.withCVRQualifiers(MergedCVRQual); + } + return CompositeTy.withCVRQualifiers(MergedCVRQual); }(); if (IsBlockPointer) ResultTy = S.Context.getBlockPointerType(ResultTy); - else { + else ResultTy = S.Context.getPointerType(ResultTy); - } LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind); @@ -15374,7 +15372,7 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) { } /// Check for operands with placeholder types and complain if found. -/// Returns true if there was an error and no recovery was possible. +/// Returns ExprError() if there was an error and no recovery was possible. ExprResult Sema::CheckPlaceholderExpr(Expr *E) { if (!getLangOpts().CPlusPlus) { // C cannot handle TypoExpr nodes on either side of a binop because it diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index d65570fcef76..9b88cddbc969 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -901,17 +901,36 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( // capturing lamdbda's call operator. // - // The issue is that we cannot rely entirely on the FunctionScopeInfo stack - // since ScopeInfos are pushed on during parsing and treetransforming. But - // since a generic lambda's call operator can be instantiated anywhere (even - // end of the TU) we need to be able to examine its enclosing lambdas and so - // we use the DeclContext to get a hold of the closure-class and query it for - // capture information. The reason we don't just resort to always using the - // DeclContext chain is that it is only mature for lambda expressions - // enclosing generic lambda's call operators that are being instantiated. - + // Since the FunctionScopeInfo stack is representative of the lexical + // nesting of the lambda expressions during initial parsing (and is the best + // place for querying information about captures about lambdas that are + // partially processed) and perhaps during instantiation of function templates + // that contain lambda expressions that need to be transformed BUT not + // necessarily during instantiation of a nested generic lambda's function call + // operator (which might even be instantiated at the end of the TU) - at which + // time the DeclContext tree is mature enough to query capture information + // reliably - we use a two pronged approach to walk through all the lexically + // enclosing lambda expressions: + // + // 1) Climb down the FunctionScopeInfo stack as long as each item represents + // a Lambda (i.e. LambdaScopeInfo) AND each LSI's 'closure-type' is lexically + // enclosed by the call-operator of the LSI below it on the stack (while + // tracking the enclosing DC for step 2 if needed). Note the topmost LSI on + // the stack represents the innermost lambda. + // + // 2) If we run out of enclosing LSI's, check if the enclosing DeclContext + // represents a lambda's call operator. If it does, we must be instantiating + // a generic lambda's call operator (represented by the Current LSI, and + // should be the only scenario where an inconsistency between the LSI and the + // DeclContext should occur), so climb out the DeclContexts if they + // represent lambdas, while querying the corresponding closure types + // regarding capture information. + + // 1) Climb down the function scope info stack. for (int I = FunctionScopes.size(); - I-- && isa<LambdaScopeInfo>(FunctionScopes[I]); + I-- && isa<LambdaScopeInfo>(FunctionScopes[I]) && + (!CurLSI || !CurLSI->Lambda || CurLSI->Lambda->getDeclContext() == + cast<LambdaScopeInfo>(FunctionScopes[I])->CallOperator); CurDC = getLambdaAwareParentOfDeclContext(CurDC)) { CurLSI = cast<LambdaScopeInfo>(FunctionScopes[I]); @@ -927,11 +946,17 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( return ASTCtx.getPointerType(ClassType); } } - // We've run out of ScopeInfos but check if CurDC is a lambda (which can - // happen during instantiation of generic lambdas) + + // 2) We've run out of ScopeInfos but check if CurDC is a lambda (which can + // happen during instantiation of its nested generic lambda call operator) if (isLambdaCallOperator(CurDC)) { - assert(CurLSI); - assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator)); + assert(CurLSI && "While computing 'this' capture-type for a generic " + "lambda, we must have a corresponding LambdaScopeInfo"); + assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator) && + "While computing 'this' capture-type for a generic lambda, when we " + "run out of enclosing LSI's, yet the enclosing DC is a " + "lambda-call-operator we must be (i.e. Current LSI) in a generic " + "lambda call oeprator"); assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator)); auto IsThisCaptured = diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index 9cc443ed4fd9..a44e9243e3c5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -595,7 +595,6 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { break; } } - CheckForIntOverflow(ValueExpr); // FIXME: Do I need to do anything special with BoolTy expressions? // Look for the appropriate method within NSNumber. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp index fb13669407fc..43fd055bbc56 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp @@ -824,21 +824,18 @@ DSAStackTy::hasDSA(ValueDecl *D, if (isStackEmpty()) return {}; D = getCanonicalDecl(D); - auto StartI = std::next(Stack.back().first.rbegin()); + auto I = (FromParent && Stack.back().first.size() > 1) + ? std::next(Stack.back().first.rbegin()) + : Stack.back().first.rbegin(); auto EndI = Stack.back().first.rend(); - if (FromParent && StartI != EndI) - StartI = std::next(StartI); - if (StartI == EndI) - return {}; - auto I = std::prev(StartI); - do { - ++I; + while (std::distance(I, EndI) > 1) { + std::advance(I, 1); if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive)) continue; DSAVarData DVar = getDSA(I, D); if (CPred(DVar.CKind)) return DVar; - } while (I != EndI); + } return {}; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp index 29ba34479dab..782c377e3202 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp @@ -11426,6 +11426,10 @@ static void AddOverloadedCallCandidate(Sema &S, assert(!KnownValid && "Explicit template arguments?"); return; } + // Prevent ill-formed function decls to be added as overload candidates. + if (!dyn_cast<FunctionProtoType>(Func->getType()->getAs<FunctionType>())) + return; + S.AddOverloadCandidate(Func, FoundDecl, Args, CandidateSet, /*SuppressUsedConversions=*/false, PartialOverloading); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp index 279b9ecef94e..bcc66bbd1c0a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp @@ -119,8 +119,9 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_NoReturn: \ - case AttributeList::AT_Regparm: \ + case AttributeList::AT_NoReturn: \ + case AttributeList::AT_Regparm: \ + case AttributeList::AT_AnyX86NoCallerSavedRegisters: \ CALLING_CONV_ATTRS_CASELIST // Microsoft-specific type qualifiers. @@ -6371,6 +6372,20 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } + if (attr.getKind() == AttributeList::AT_AnyX86NoCallerSavedRegisters) { + if (S.CheckNoCallerSavedRegsAttr(attr)) + return true; + + // Delay if this is not a function type. + if (!unwrapped.isFunctionType()) + return false; + + FunctionType::ExtInfo EI = + unwrapped.get()->getExtInfo().withNoCallerSavedRegs(true); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; + } + if (attr.getKind() == AttributeList::AT_Regparm) { unsigned value; if (S.CheckRegparmAttr(attr, value)) diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp index 7b1edc062d1e..61b5a822c552 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp @@ -3765,6 +3765,13 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, SourceMgr.getLoadedSLocEntryByID(Index); } + // Map the original source file ID into the ID space of the current + // compilation. + if (F.OriginalSourceFileID.isValid()) { + F.OriginalSourceFileID = FileID::get( + F.SLocEntryBaseID + F.OriginalSourceFileID.getOpaqueValue() - 1); + } + // Preload all the pending interesting identifiers by marking them out of // date. for (auto Offset : F.PreloadIdentifierOffsets) { @@ -3873,10 +3880,6 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); if (PrimaryModule.OriginalSourceFileID.isValid()) { - PrimaryModule.OriginalSourceFileID - = FileID::get(PrimaryModule.SLocEntryBaseID - + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1); - // If this AST file is a precompiled preamble, then set the // preamble file ID of the source manager to the file source file // from which the preamble was built. @@ -5528,14 +5531,8 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { "Invalid data, not enough diag/map pairs"); while (Size--) { unsigned DiagID = Record[Idx++]; - unsigned SeverityAndUpgradedFromWarning = Record[Idx++]; - bool WasUpgradedFromWarning = - DiagnosticMapping::deserializeUpgradedFromWarning( - SeverityAndUpgradedFromWarning); DiagnosticMapping NewMapping = - Diag.makeUserMapping(DiagnosticMapping::deserializeSeverity( - SeverityAndUpgradedFromWarning), - Loc); + DiagnosticMapping::deserialize(Record[Idx++]); if (!NewMapping.isPragma() && !IncludeNonPragmaStates) continue; @@ -5544,14 +5541,12 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { // If this mapping was specified as a warning but the severity was // upgraded due to diagnostic settings, simulate the current diagnostic // settings (and use a warning). - if (WasUpgradedFromWarning && !Mapping.isErrorOrFatal()) { - Mapping = Diag.makeUserMapping(diag::Severity::Warning, Loc); - continue; + if (NewMapping.wasUpgradedFromWarning() && !Mapping.isErrorOrFatal()) { + NewMapping.setSeverity(diag::Severity::Warning); + NewMapping.setUpgradedFromWarning(false); } - // Use the deserialized mapping verbatim. Mapping = NewMapping; - Mapping.setUpgradedFromWarning(WasUpgradedFromWarning); } return NewState; }; @@ -5566,15 +5561,36 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { DiagStates.push_back(FirstState); // Skip the initial diagnostic state from the serialized module. - assert(Record[0] == 0 && + assert(Record[1] == 0 && "Invalid data, unexpected backref in initial state"); - Idx = 2 + Record[1] * 2; + Idx = 3 + Record[2] * 2; assert(Idx < Record.size() && "Invalid data, not enough state change pairs in initial state"); + } else if (F.isModule()) { + // For an explicit module, preserve the flags from the module build + // command line (-w, -Weverything, -Werror, ...) along with any explicit + // -Wblah flags. + unsigned Flags = Record[Idx++]; + DiagState Initial; + Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1; + Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1; + Initial.WarningsAsErrors = Flags & 1; Flags >>= 1; + Initial.EnableAllWarnings = Flags & 1; Flags >>= 1; + Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1; + Initial.ExtBehavior = (diag::Severity)Flags; + FirstState = ReadDiagState(Initial, SourceLocation(), true); + + // Set up the root buffer of the module to start with the initial + // diagnostic state of the module itself, to cover files that contain no + // explicit transitions (for which we did not serialize anything). + Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID] + .StateTransitions.push_back({FirstState, 0}); } else { - FirstState = ReadDiagState( - F.isModule() ? DiagState() : *Diag.DiagStatesByLoc.CurDiagState, - SourceLocation(), F.isModule()); + // For prefix ASTs, start with whatever the user configured on the + // command line. + Idx++; // Skip flags. + FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState, + SourceLocation(), false); } // Read the state transitions. @@ -5801,13 +5817,13 @@ QualType ASTReader::readTypeRecord(unsigned Index) { } case TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 6) { + if (Record.size() != 7) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = readType(*Loc.F, Record, Idx); FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], - (CallingConv)Record[4], Record[5]); + (CallingConv)Record[4], Record[5], Record[6]); return Context.getFunctionNoProtoType(ResultType, Info); } @@ -5819,9 +5835,10 @@ QualType ASTReader::readTypeRecord(unsigned Index) { /*hasregparm*/ Record[2], /*regparm*/ Record[3], static_cast<CallingConv>(Record[4]), - /*produces*/ Record[5]); + /*produces*/ Record[5], + /*nocallersavedregs*/ Record[6]); - unsigned Idx = 6; + unsigned Idx = 7; EPI.Variadic = Record[Idx++]; EPI.HasTrailingReturn = Record[Idx++]; @@ -9305,6 +9322,9 @@ void ASTReader::diagnoseOdrViolations() { MethodVolatile, MethodConst, MethodInline, + MethodNumberParameters, + MethodParameterType, + MethodParameterName, }; // These lambdas have the common portions of the ODR diagnostics. This @@ -9335,6 +9355,12 @@ void ASTReader::diagnoseOdrViolations() { return Hash.CalculateHash(); }; + auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { + Hash.clear(); + Hash.AddQualType(Ty); + return Hash.CalculateHash(); + }; + switch (FirstDiffType) { case Other: case EndOfClass: @@ -9629,6 +9655,76 @@ void ASTReader::diagnoseOdrViolations() { break; } + const unsigned FirstNumParameters = FirstMethod->param_size(); + const unsigned SecondNumParameters = SecondMethod->param_size(); + if (FirstNumParameters != SecondNumParameters) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodNumberParameters) + << FirstName << FirstNumParameters; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodNumberParameters) + << SecondName << SecondNumParameters; + Diagnosed = true; + break; + } + + // Need this status boolean to know when break out of the switch. + bool ParameterMismatch = false; + for (unsigned I = 0; I < FirstNumParameters; ++I) { + const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I); + const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I); + + QualType FirstParamType = FirstParam->getType(); + QualType SecondParamType = SecondParam->getType(); + if (FirstParamType != SecondParamType && + ComputeQualTypeODRHash(FirstParamType) != + ComputeQualTypeODRHash(SecondParamType)) { + if (const DecayedType *ParamDecayedType = + FirstParamType->getAs<DecayedType>()) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodParameterType) + << FirstName << (I + 1) << FirstParamType << true + << ParamDecayedType->getOriginalType(); + } else { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodParameterType) + << FirstName << (I + 1) << FirstParamType << false; + } + + if (const DecayedType *ParamDecayedType = + SecondParamType->getAs<DecayedType>()) { + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodParameterType) + << SecondName << (I + 1) << SecondParamType << true + << ParamDecayedType->getOriginalType(); + } else { + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodParameterType) + << SecondName << (I + 1) << SecondParamType << false; + } + ParameterMismatch = true; + break; + } + + DeclarationName FirstParamName = FirstParam->getDeclName(); + DeclarationName SecondParamName = SecondParam->getDeclName(); + if (FirstParamName != SecondParamName) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodParameterName) + << FirstName << (I + 1) << FirstParamName; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodParameterName) + << SecondName << (I + 1) << SecondParamName; + ParameterMismatch = true; + break; + } + } + + if (ParameterMismatch) { + Diagnosed = true; + break; + } + break; } } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp index 84d2420f4ba9..8e4b217a44cd 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp @@ -255,6 +255,7 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) { // FIXME: need to stabilize encoding of calling convention... Record.push_back(C.getCC()); Record.push_back(C.getProducesResult()); + Record.push_back(C.getNoCallerSavedRegs()); if (C.getHasRegParm() || C.getRegParm() || C.getProducesResult()) AbbrevToUse = 0; @@ -839,6 +840,7 @@ void ASTWriter::WriteTypeAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // RegParm Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // CC Abv->Add(BitCodeAbbrevOp(0)); // ProducesResult + Abv->Add(BitCodeAbbrevOp(0)); // NoCallerSavedRegs // FunctionProtoType Abv->Add(BitCodeAbbrevOp(0)); // IsVariadic Abv->Add(BitCodeAbbrevOp(0)); // HasTrailingReturn @@ -2866,8 +2868,27 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, unsigned CurrID = 0; RecordData Record; + auto EncodeDiagStateFlags = + [](const DiagnosticsEngine::DiagState *DS) -> unsigned { + unsigned Result = (unsigned)DS->ExtBehavior; + for (unsigned Val : + {(unsigned)DS->IgnoreAllWarnings, (unsigned)DS->EnableAllWarnings, + (unsigned)DS->WarningsAsErrors, (unsigned)DS->ErrorsAsFatal, + (unsigned)DS->SuppressSystemWarnings}) + Result = (Result << 1) | Val; + return Result; + }; + + unsigned Flags = EncodeDiagStateFlags(Diag.DiagStatesByLoc.FirstDiagState); + Record.push_back(Flags); + auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State, bool IncludeNonPragmaStates) { + // Ensure that the diagnostic state wasn't modified since it was created. + // We will not correctly round-trip this information otherwise. + assert(Flags == EncodeDiagStateFlags(State) && + "diag state flags vary in single AST file"); + unsigned &DiagStateID = DiagStateIDMap[State]; Record.push_back(DiagStateID); @@ -2880,7 +2901,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, for (const auto &I : *State) { if (I.second.isPragma() || IncludeNonPragmaStates) { Record.push_back(I.first); - Record.push_back(I.second.serializeBits()); + Record.push_back(I.second.serialize()); } } // Update the placeholder. diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 5730517289bb..851114004b96 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" @@ -401,6 +402,9 @@ private: void ReportUseZeroAllocated(CheckerContext &C, SourceRange Range, SymbolRef Sym) const; + void ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal, + SourceRange Range, const Expr *FreeExpr) const; + /// Find the location of the allocation for Sym on the path leading to the /// exploded node N. LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym, @@ -1564,6 +1568,11 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, } } + if (SymBase->getType()->isFunctionPointerType()) { + ReportFunctionPointerFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); + return nullptr; + } + ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero()); @@ -1745,8 +1754,8 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_BadFree[*CheckKind]) - BT_BadFree[*CheckKind].reset( - new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error")); + BT_BadFree[*CheckKind].reset(new BugType( + CheckNames[*CheckKind], "Bad free", categories::MemoryError)); SmallString<100> buf; llvm::raw_svector_ostream os(buf); @@ -1790,8 +1799,8 @@ void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal, if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_FreeAlloca[*CheckKind]) - BT_FreeAlloca[*CheckKind].reset( - new BugType(CheckNames[*CheckKind], "Free alloca()", "Memory Error")); + BT_FreeAlloca[*CheckKind].reset(new BugType( + CheckNames[*CheckKind], "Free alloca()", categories::MemoryError)); auto R = llvm::make_unique<BugReport>( *BT_FreeAlloca[*CheckKind], @@ -1816,7 +1825,7 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, if (!BT_MismatchedDealloc) BT_MismatchedDealloc.reset( new BugType(CheckNames[CK_MismatchedDeallocatorChecker], - "Bad deallocator", "Memory Error")); + "Bad deallocator", categories::MemoryError)); SmallString<100> buf; llvm::raw_svector_ostream os(buf); @@ -1876,8 +1885,8 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, return; if (!BT_OffsetFree[*CheckKind]) - BT_OffsetFree[*CheckKind].reset( - new BugType(CheckNames[*CheckKind], "Offset free", "Memory Error")); + BT_OffsetFree[*CheckKind].reset(new BugType( + CheckNames[*CheckKind], "Offset free", categories::MemoryError)); SmallString<100> buf; llvm::raw_svector_ostream os(buf); @@ -1928,7 +1937,7 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range, if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_UseFree[*CheckKind]) BT_UseFree[*CheckKind].reset(new BugType( - CheckNames[*CheckKind], "Use-after-free", "Memory Error")); + CheckNames[*CheckKind], "Use-after-free", categories::MemoryError)); auto R = llvm::make_unique<BugReport>(*BT_UseFree[*CheckKind], "Use of memory after it is freed", N); @@ -1954,8 +1963,8 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_DoubleFree[*CheckKind]) - BT_DoubleFree[*CheckKind].reset( - new BugType(CheckNames[*CheckKind], "Double free", "Memory Error")); + BT_DoubleFree[*CheckKind].reset(new BugType( + CheckNames[*CheckKind], "Double free", categories::MemoryError)); auto R = llvm::make_unique<BugReport>( *BT_DoubleFree[*CheckKind], @@ -1983,7 +1992,8 @@ void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const { if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_DoubleDelete) BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker], - "Double delete", "Memory Error")); + "Double delete", + categories::MemoryError)); auto R = llvm::make_unique<BugReport>( *BT_DoubleDelete, "Attempt to delete released memory", N); @@ -2009,8 +2019,9 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C, if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_UseZerroAllocated[*CheckKind]) - BT_UseZerroAllocated[*CheckKind].reset(new BugType( - CheckNames[*CheckKind], "Use of zero allocated", "Memory Error")); + BT_UseZerroAllocated[*CheckKind].reset( + new BugType(CheckNames[*CheckKind], "Use of zero allocated", + categories::MemoryError)); auto R = llvm::make_unique<BugReport>(*BT_UseZerroAllocated[*CheckKind], "Use of zero-allocated memory", N); @@ -2024,10 +2035,45 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C, } } +void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal, + SourceRange Range, + const Expr *FreeExpr) const { + if (!ChecksEnabled[CK_MallocChecker]) + return; + + Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, FreeExpr); + if (!CheckKind.hasValue()) + return; + + if (ExplodedNode *N = C.generateErrorNode()) { + if (!BT_BadFree[*CheckKind]) + BT_BadFree[*CheckKind].reset( + new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error")); + + SmallString<100> Buf; + llvm::raw_svector_ostream Os(Buf); + + const MemRegion *MR = ArgVal.getAsRegion(); + while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR)) + MR = ER->getSuperRegion(); + + Os << "Argument to "; + if (!printAllocDeallocName(Os, C, FreeExpr)) + Os << "deallocator"; + + Os << " is a function pointer"; + + auto R = llvm::make_unique<BugReport>(*BT_BadFree[*CheckKind], Os.str(), N); + R->markInteresting(MR); + R->addRange(Range); + C.emitReport(std::move(R)); + } +} + ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C, const CallExpr *CE, bool FreesOnFail, - ProgramStateRef State, + ProgramStateRef State, bool SuffixWithN) const { if (!State) return nullptr; @@ -2210,8 +2256,8 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, assert(N); if (!BT_Leak[*CheckKind]) { - BT_Leak[*CheckKind].reset( - new BugType(CheckNames[*CheckKind], "Memory leak", "Memory Error")); + BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak", + categories::MemoryError)); // Leaks should not be reported if they are post-dominated by a sink: // (1) Sinks are higher importance bugs. // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 21527d8c347a..41999d252763 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -178,7 +178,7 @@ private: const MemRegion *Region, BugReporter &BR, const Stmt *ValueExpr = nullptr) const { if (!BT) - BT.reset(new BugType(this, "Nullability", "Memory error")); + BT.reset(new BugType(this, "Nullability", categories::MemoryError)); auto R = llvm::make_unique<BugReport>(*BT, Msg, N); if (Region) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp index d12ba6258073..06c4ef71d80b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp @@ -256,7 +256,7 @@ void ValistChecker::reportUninitializedAccess(const MemRegion *VAList, if (!BT_uninitaccess) BT_uninitaccess.reset(new BugType(CheckNames[CK_Uninitialized], "Uninitialized va_list", - "Memory Error")); + categories::MemoryError)); auto R = llvm::make_unique<BugReport>(*BT_uninitaccess, Msg, N); R->markInteresting(VAList); R->addVisitor(llvm::make_unique<ValistBugVisitor>(VAList)); @@ -274,7 +274,8 @@ void ValistChecker::reportLeakedVALists(const RegionVector &LeakedVALists, for (auto Reg : LeakedVALists) { if (!BT_leakedvalist) { BT_leakedvalist.reset(new BugType(CheckNames[CK_Unterminated], - "Leaked va_list", "Memory Error")); + "Leaked va_list", + categories::MemoryError)); BT_leakedvalist->setSuppressOnSink(true); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp index 3cb9323563b3..421dfa48c97b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp @@ -16,5 +16,6 @@ const char * const CoreFoundationObjectiveC = "Core Foundation/Objective-C"; const char * const LogicError = "Logic error"; const char * const MemoryCoreFoundationObjectiveC = "Memory (Core Foundation/Objective-C)"; +const char * const MemoryError = "Memory error"; const char * const UnixAPI = "Unix API"; }}} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp index c6f3baa7e3b2..cdb1ed9b3815 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp @@ -65,7 +65,7 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) { auto Invocation = std::make_shared<CompilerInvocation>(CI.getInvocation()); FrontendOptions &FrontendOpts = Invocation->getFrontendOpts(); - InputKind IK = IK_CXX; // FIXME + InputKind IK = InputKind::CXX; // FIXME FrontendOpts.Inputs.clear(); FrontendOpts.Inputs.emplace_back(fileName, IK); FrontendOpts.DisableFree = true; diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp index 981445675343..7efc9bccdc5c 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1670,7 +1670,7 @@ PragmaClangAttributeSupport::PragmaClangAttributeSupport( Records.getAllDerivedDefinitions("AttrSubjectMatcherRule"); auto MapFromSubjectsToRules = [this](const Record *SubjectContainer, const Record *MetaSubject, - const Record *Constraint = nullptr) { + const Record *Constraint) { Rules.emplace_back(MetaSubject, Constraint); std::vector<Record *> ApplicableSubjects = SubjectContainer->getValueAsListOfDefs("Subjects"); @@ -1688,7 +1688,7 @@ PragmaClangAttributeSupport::PragmaClangAttributeSupport( } }; for (const auto *MetaSubject : MetaSubjects) { - MapFromSubjectsToRules(MetaSubject, MetaSubject); + MapFromSubjectsToRules(MetaSubject, MetaSubject, /*Constraints=*/nullptr); std::vector<Record *> Constraints = MetaSubject->getValueAsListOfDefs("Constraints"); for (const auto *Constraint : Constraints) diff --git a/contrib/llvm/tools/lld/COFF/Chunks.cpp b/contrib/llvm/tools/lld/COFF/Chunks.cpp index 2e49f417a206..791d96ee92a5 100644 --- a/contrib/llvm/tools/lld/COFF/Chunks.cpp +++ b/contrib/llvm/tools/lld/COFF/Chunks.cpp @@ -326,41 +326,38 @@ void SEHTableChunk::writeTo(uint8_t *Buf) const { // usually loaded to that address. However, if there's already another // DLL that overlaps, the loader has to relocate it. To do that, DLLs // contain .reloc sections which contain offsets that need to be fixed -// up at runtime. If the loader find that a DLL cannot be loaded to its +// up at runtime. If the loader finds that a DLL cannot be loaded to its // desired base address, it loads it to somewhere else, and add <actual // base address> - <desired base address> to each offset that is -// specified by .reloc section. +// specified by the .reloc section. In ELF terms, .reloc sections +// contain relative relocations in REL format (as opposed to RELA.) // -// In ELF terms, .reloc sections contain arrays of relocation offsets. -// All these offsets in the section are implicitly R_*_RELATIVE, and -// addends are read from section contents (so it is REL as opposed to -// RELA). +// This already significantly reduces the size of relocations compared +// to ELF .rel.dyn, but Windows does more to reduce it (probably because +// it was invented for PCs in the late '80s or early '90s.) Offsets in +// .reloc are grouped by page where the page size is 12 bits, and +// offsets sharing the same page address are stored consecutively to +// represent them with less space. This is very similar to the page +// table which is grouped by (multiple stages of) pages. // -// This already reduce the size of relocations to 1/3 compared to ELF -// .dynrel, but Windows does more to reduce it (probably because it was -// invented for PCs in the late '80s or early '90s.) Offsets in .reloc -// are grouped by page where page size is 16 bits, and offsets sharing -// the same page address are stored consecutively to represent them with -// less space. This is a very similar to the page table which is grouped -// by (multiple stages of) pages. -// -// For example, let's say we have 0x00030, 0x00500, 0x01000, 0x01100, -// 0x20004, and 0x20008 in a .reloc section. In the section, they are -// represented like this: +// For example, let's say we have 0x00030, 0x00500, 0x00700, 0x00A00, +// 0x20004, and 0x20008 in a .reloc section for x64. The uppermost 4 +// bits have a type IMAGE_REL_BASED_DIR64 or 0xA. In the section, they +// are represented like this: // // 0x00000 -- page address (4 bytes) // 16 -- size of this block (4 bytes) -// 0x0030 -- entries (2 bytes each) -// 0x0500 -// 0x1000 -// 0x1100 +// 0xA030 -- entries (2 bytes each) +// 0xA500 +// 0xA700 +// 0xAA00 // 0x20000 -- page address (4 bytes) // 12 -- size of this block (4 bytes) -// 0x0004 -- entries (2 bytes each) -// 0x0008 +// 0xA004 -- entries (2 bytes each) +// 0xA008 // -// Usually we have a lot of relocatinos for each page, so the number of -// bytes for one .reloc entry is close to 2 bytes. +// Usually we have a lot of relocations for each page, so the number of +// bytes for one .reloc entry is close to 2 bytes on average. BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { // Block header consists of 4 byte page RVA and 4 byte block size. // Each entry is 2 byte. Last entry may be padding. diff --git a/contrib/llvm/tools/lld/COFF/Error.cpp b/contrib/llvm/tools/lld/COFF/Error.cpp index b2c7c89bd36c..166b1971e77f 100644 --- a/contrib/llvm/tools/lld/COFF/Error.cpp +++ b/contrib/llvm/tools/lld/COFF/Error.cpp @@ -59,6 +59,7 @@ void log(const Twine &Msg) { if (Config->Verbose) { std::lock_guard<std::mutex> Lock(Mu); outs() << Argv0 << ": " << Msg << "\n"; + outs().flush(); } } diff --git a/contrib/llvm/tools/lld/COFF/ICF.cpp b/contrib/llvm/tools/lld/COFF/ICF.cpp index 19468c0fac5e..fe59de6efa54 100644 --- a/contrib/llvm/tools/lld/COFF/ICF.cpp +++ b/contrib/llvm/tools/lld/COFF/ICF.cpp @@ -71,10 +71,18 @@ uint32_t ICF::getHash(SectionChunk *C) { } // Returns true if section S is subject of ICF. +// +// Microsoft's documentation +// (https://msdn.microsoft.com/en-us/library/bxwfs976.aspx; visited April +// 2017) says that /opt:icf folds both functions and read-only data. +// Despite that, the MSVC linker folds only functions. We found +// a few instances of programs that are not safe for data merging. +// Therefore, we merge only functions just like the MSVC tool. bool ICF::isEligible(SectionChunk *C) { bool Global = C->Sym && C->Sym->isExternal(); + bool Executable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE; bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; - return C->isCOMDAT() && C->isLive() && Global && !Writable; + return C->isCOMDAT() && C->isLive() && Global && Executable && !Writable; } // Split a range into smaller ranges by recoloring sections diff --git a/contrib/llvm/tools/lld/COFF/InputFiles.cpp b/contrib/llvm/tools/lld/COFF/InputFiles.cpp index cb56e13014db..df3b6a032cf8 100644 --- a/contrib/llvm/tools/lld/COFF/InputFiles.cpp +++ b/contrib/llvm/tools/lld/COFF/InputFiles.cpp @@ -327,6 +327,9 @@ void ImportFile::parse() { ImpSym = cast<DefinedImportData>( Symtab->addImportData(ImpName, this)->body()); + if (Hdr->getType() == llvm::COFF::IMPORT_CONST) + ConstSym = + cast<DefinedImportData>(Symtab->addImportData(Name, this)->body()); // If type is function, we need to create a thunk which jump to an // address pointed by the __imp_ symbol. (This allows you to call diff --git a/contrib/llvm/tools/lld/COFF/InputFiles.h b/contrib/llvm/tools/lld/COFF/InputFiles.h index 3078de687525..a2fd3f59ad70 100644 --- a/contrib/llvm/tools/lld/COFF/InputFiles.h +++ b/contrib/llvm/tools/lld/COFF/InputFiles.h @@ -167,6 +167,7 @@ public: static bool classof(const InputFile *F) { return F->kind() == ImportKind; } DefinedImportData *ImpSym = nullptr; + DefinedImportData *ConstSym = nullptr; DefinedImportThunk *ThunkSym = nullptr; std::string DLLName; diff --git a/contrib/llvm/tools/lld/COFF/MapFile.cpp b/contrib/llvm/tools/lld/COFF/MapFile.cpp index 43dd8dc35810..4e596e602fee 100644 --- a/contrib/llvm/tools/lld/COFF/MapFile.cpp +++ b/contrib/llvm/tools/lld/COFF/MapFile.cpp @@ -11,21 +11,21 @@ // hierarchically the output sections, input sections, input files and // symbol: // -// Address Size Align Out In File Symbol -// ================================================================= -// 00201000 00000015 4 .text -// 00201000 0000000e 4 .text -// 00201000 0000000e 4 test.o -// 0020100e 00000000 0 local -// 00201005 00000000 0 f(int) +// Address Size Align Out File Symbol +// 00201000 00000015 4 .text +// 00201000 0000000e 4 test.o:(.text) +// 0020100e 00000000 0 local +// 00201005 00000000 0 f(int) // //===----------------------------------------------------------------------===// #include "MapFile.h" #include "Error.h" +#include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Core/Parallel.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -34,72 +34,58 @@ using namespace llvm::object; using namespace lld; using namespace lld::coff; -static void writeOutSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size, - uint64_t Align, StringRef Name) { - OS << format("%08llx %08llx %5lld ", Address, Size, Align) - << left_justify(Name, 7); -} +typedef DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>> + SymbolMapTy; -static void writeInSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size, - uint64_t Align, StringRef Name) { - // Pass an empty name to align the text to the correct column. - writeOutSecLine(OS, Address, Size, Align, ""); - OS << ' ' << left_justify(Name, 7); +// Print out the first three columns of a line. +static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, + uint64_t Align) { + OS << format("%08llx %08llx %5lld ", Addr, Size, Align); } -static void writeFileLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size, - uint64_t Align, StringRef Name) { - // Pass an empty name to align the text to the correct column. - writeInSecLine(OS, Address, Size, Align, ""); - OS << ' ' << left_justify(Name, 7); -} +static std::string indent(int Depth) { return std::string(Depth * 8, ' '); } -static void writeSymbolLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size, - StringRef Name) { - // Pass an empty name to align the text to the correct column. - writeFileLine(OS, Address, Size, 0, ""); - OS << ' ' << left_justify(Name, 7); +// Returns a list of all symbols that we want to print out. +static std::vector<DefinedRegular *> getSymbols() { + std::vector<DefinedRegular *> V; + for (coff::ObjectFile *File : Symtab->ObjectFiles) + for (SymbolBody *B : File->getSymbols()) + if (auto *Sym = dyn_cast<DefinedRegular>(B)) + if (Sym && !Sym->getCOFFSymbol().isSectionDefinition()) + V.push_back(Sym); + return V; } -static void writeSectionChunk(raw_fd_ostream &OS, const SectionChunk *SC, - StringRef &PrevName) { - StringRef Name = SC->getSectionName(); - if (Name != PrevName) { - writeInSecLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(), Name); - OS << '\n'; - PrevName = Name; - } - coff::ObjectFile *File = SC->File; - if (!File) - return; - writeFileLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(), - toString(File)); - OS << '\n'; - ArrayRef<SymbolBody *> Syms = File->getSymbols(); - for (SymbolBody *Sym : Syms) { - auto *DR = dyn_cast<DefinedRegular>(Sym); - if (!DR || DR->getChunk() != SC || - DR->getCOFFSymbol().isSectionDefinition()) - continue; - writeSymbolLine(OS, DR->getRVA(), SC->getSize(), toString(*Sym)); - OS << '\n'; +// Returns a map from sections to their symbols. +static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) { + SymbolMapTy Ret; + for (DefinedRegular *S : Syms) + Ret[S->getChunk()].push_back(S); + + // Sort symbols by address. + for (auto &It : Ret) { + SmallVectorImpl<DefinedRegular *> &V = It.second; + std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) { + return A->getRVA() < B->getRVA(); + }); } + return Ret; } -static void writeMapFile2(raw_fd_ostream &OS, - ArrayRef<OutputSection *> OutputSections) { - OS << "Address Size Align Out In File Symbol\n"; +// Construct a map from symbols to their stringified representations. +static DenseMap<DefinedRegular *, std::string> +getSymbolStrings(ArrayRef<DefinedRegular *> Syms) { + std::vector<std::string> Str(Syms.size()); + parallel_for((size_t)0, Syms.size(), [&](size_t I) { + raw_string_ostream OS(Str[I]); + writeHeader(OS, Syms[I]->getRVA(), 0, 0); + OS << indent(2) << toString(*Syms[I]); + }); - for (OutputSection *Sec : OutputSections) { - uint32_t VA = Sec->getRVA(); - writeOutSecLine(OS, VA, Sec->getVirtualSize(), /*Align=*/PageSize, - Sec->getName()); - OS << '\n'; - StringRef PrevName = ""; - for (Chunk *C : Sec->getChunks()) - if (const auto *SC = dyn_cast<SectionChunk>(C)) - writeSectionChunk(OS, SC, PrevName); - } + DenseMap<DefinedRegular *, std::string> Ret; + for (size_t I = 0, E = Syms.size(); I < E; ++I) + Ret[Syms[I]] = std::move(Str[I]); + return Ret; } void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) { @@ -110,5 +96,30 @@ void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) { raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); if (EC) fatal("cannot open " + Config->MapFile + ": " + EC.message()); - writeMapFile2(OS, OutputSections); + + // Collect symbol info that we want to print out. + std::vector<DefinedRegular *> Syms = getSymbols(); + SymbolMapTy SectionSyms = getSectionSyms(Syms); + DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings(Syms); + + // Print out the header line. + OS << "Address Size Align Out In Symbol\n"; + + // Print out file contents. + for (OutputSection *Sec : OutputSections) { + writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize); + OS << Sec->getName() << '\n'; + + for (Chunk *C : Sec->getChunks()) { + auto *SC = dyn_cast<SectionChunk>(C); + if (!SC) + continue; + + writeHeader(OS, SC->getRVA(), SC->getSize(), SC->getAlign()); + OS << indent(1) << SC->File->getName() << ":(" << SC->getSectionName() + << ")\n"; + for (DefinedRegular *Sym : SectionSyms[SC]) + OS << SymStr[Sym] << '\n'; + } + } } diff --git a/contrib/llvm/tools/lld/COFF/PDB.cpp b/contrib/llvm/tools/lld/COFF/PDB.cpp index e32bcd20a541..20411a703e24 100644 --- a/contrib/llvm/tools/lld/COFF/PDB.cpp +++ b/contrib/llvm/tools/lld/COFF/PDB.cpp @@ -28,8 +28,8 @@ #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" -#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/Object/COFF.h" diff --git a/contrib/llvm/tools/lld/ELF/Config.h b/contrib/llvm/tools/lld/ELF/Config.h index d25c63c3c0d2..1ace4aa26fdb 100644 --- a/contrib/llvm/tools/lld/ELF/Config.h +++ b/contrib/llvm/tools/lld/ELF/Config.h @@ -89,7 +89,7 @@ struct Configuration { llvm::StringRef SoName; llvm::StringRef Sysroot; llvm::StringRef ThinLTOCacheDir; - std::string RPath; + std::string Rpath; std::vector<VersionDefinition> VersionDefinitions; std::vector<llvm::StringRef> AuxiliaryList; std::vector<llvm::StringRef> SearchPaths; diff --git a/contrib/llvm/tools/lld/ELF/Driver.cpp b/contrib/llvm/tools/lld/ELF/Driver.cpp index 68eb5616a5c6..6a71eb3ee490 100644 --- a/contrib/llvm/tools/lld/ELF/Driver.cpp +++ b/contrib/llvm/tools/lld/ELF/Driver.cpp @@ -124,7 +124,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. std::vector<MemoryBufferRef> -LinkerDriver::getArchiveMembers(MemoryBufferRef MB) { +static getArchiveMembers(MemoryBufferRef MB) { std::unique_ptr<Archive> File = check(Archive::create(MB), MB.getBufferIdentifier() + ": failed to parse archive"); @@ -242,6 +242,9 @@ static void checkOptions(opt::InputArgList &Args) { if (Config->Pie && Config->Shared) error("-shared and -pie may not be used together"); + if (!Config->Shared && !Config->AuxiliaryList.empty()) + error("-f may not be used without -shared"); + if (Config->Relocatable) { if (Config->Shared) error("-r and -shared may not be used together"); @@ -396,7 +399,7 @@ static std::vector<StringRef> getArgs(opt::InputArgList &Args, int Id) { return V; } -static std::string getRPath(opt::InputArgList &Args) { +static std::string getRpath(opt::InputArgList &Args) { std::vector<StringRef> V = getArgs(Args, OPT_rpath); return llvm::join(V.begin(), V.end(), ":"); } @@ -444,16 +447,14 @@ static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) { } static Target2Policy getTarget2(opt::InputArgList &Args) { - if (auto *Arg = Args.getLastArg(OPT_target2)) { - StringRef S = Arg->getValue(); - if (S == "rel") - return Target2Policy::Rel; - if (S == "abs") - return Target2Policy::Abs; - if (S == "got-rel") - return Target2Policy::GotRel; - error("unknown --target2 option: " + S); - } + StringRef S = getString(Args, OPT_target2, "got-rel"); + if (S == "rel") + return Target2Policy::Rel; + if (S == "abs") + return Target2Policy::Abs; + if (S == "got-rel") + return Target2Policy::GotRel; + error("unknown --target2 option: " + S); return Target2Policy::GotRel; } @@ -550,6 +551,29 @@ static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) { return {true, true}; } +// Parse --build-id or --build-id=<style>. We handle "tree" as a +// synonym for "sha1" because all our hash functions including +// -build-id=sha1 are actually tree hashes for performance reasons. +static std::pair<BuildIdKind, std::vector<uint8_t>> +getBuildId(opt::InputArgList &Args) { + if (Args.hasArg(OPT_build_id)) + return {BuildIdKind::Fast, {}}; + + StringRef S = getString(Args, OPT_build_id_eq, "none"); + if (S == "md5") + return {BuildIdKind::Md5, {}}; + if (S == "sha1" || S == "tree") + return {BuildIdKind::Sha1, {}}; + if (S == "uuid") + return {BuildIdKind::Uuid, {}}; + if (S.startswith("0x")) + return {BuildIdKind::Hexstring, parseHex(S.substr(2))}; + + if (S != "none") + error("unknown --build-id style: " + S); + return {BuildIdKind::None, {}}; +} + static std::vector<StringRef> getLines(MemoryBufferRef MB) { SmallVector<StringRef, 0> Arr; MB.getBuffer().split(Arr, '\n'); @@ -564,14 +588,14 @@ static std::vector<StringRef> getLines(MemoryBufferRef MB) { } static bool getCompressDebugSections(opt::InputArgList &Args) { - if (auto *Arg = Args.getLastArg(OPT_compress_debug_sections)) { - StringRef S = Arg->getValue(); - if (S == "zlib") - return zlib::isAvailable(); - if (S != "none") - error("unknown --compress-debug-sections value: " + S); - } - return false; + StringRef S = getString(Args, OPT_compress_debug_sections, "none"); + if (S == "none") + return false; + if (S != "zlib") + error("unknown --compress-debug-sections value: " + S); + if (!zlib::isAvailable()) + error("--compress-debug-sections: zlib is not available"); + return true; } // Initializes Config members by the command line options. @@ -616,7 +640,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->OutputFile = getString(Args, OPT_o); Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false); Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections); - Config->RPath = getRPath(Args); + Config->Rpath = getRpath(Args); Config->Relocatable = Args.hasArg(OPT_relocatable); Config->SaveTemps = Args.hasArg(OPT_save_temps); Config->SearchPaths = getArgs(Args, OPT_L); @@ -679,32 +703,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->ZRelro = false; std::tie(Config->SysvHash, Config->GnuHash) = getHashStyle(Args); - - // Parse --build-id or --build-id=<style>. We handle "tree" as a - // synonym for "sha1" because all of our hash functions including - // -build-id=sha1 are tree hashes for performance reasons. - if (Args.hasArg(OPT_build_id)) - Config->BuildId = BuildIdKind::Fast; - if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) { - StringRef S = Arg->getValue(); - if (S == "md5") { - Config->BuildId = BuildIdKind::Md5; - } else if (S == "sha1" || S == "tree") { - Config->BuildId = BuildIdKind::Sha1; - } else if (S == "uuid") { - Config->BuildId = BuildIdKind::Uuid; - } else if (S == "none") { - Config->BuildId = BuildIdKind::None; - } else if (S.startswith("0x")) { - Config->BuildId = BuildIdKind::Hexstring; - Config->BuildIdVector = parseHex(S.substr(2)); - } else { - error("unknown --build-id style: " + S); - } - } - - if (!Config->Shared && !Config->AuxiliaryList.empty()) - error("-f may not be used without -shared"); + std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args); if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) diff --git a/contrib/llvm/tools/lld/ELF/Driver.h b/contrib/llvm/tools/lld/ELF/Driver.h index 15ab23d1589d..8955624dbc12 100644 --- a/contrib/llvm/tools/lld/ELF/Driver.h +++ b/contrib/llvm/tools/lld/ELF/Driver.h @@ -31,7 +31,6 @@ public: void addLibrary(StringRef Name); private: - std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB); void readConfigs(llvm::opt::InputArgList &Args); void createFiles(llvm::opt::InputArgList &Args); void inferMachineType(); @@ -65,8 +64,6 @@ enum { }; void printHelp(const char *Argv0); -std::vector<uint8_t> parseHexstring(StringRef S); - std::string createResponseFile(const llvm::opt::InputArgList &Args); llvm::Optional<std::string> findFromSearchPaths(StringRef Path); diff --git a/contrib/llvm/tools/lld/ELF/Error.cpp b/contrib/llvm/tools/lld/ELF/Error.cpp index 2c61b58dfed5..7a58668bdcc0 100644 --- a/contrib/llvm/tools/lld/ELF/Error.cpp +++ b/contrib/llvm/tools/lld/ELF/Error.cpp @@ -60,6 +60,7 @@ void elf::log(const Twine &Msg) { if (Config->Verbose) { std::lock_guard<std::mutex> Lock(Mu); outs() << Argv0 << ": " << Msg << "\n"; + outs().flush(); } } diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.cpp b/contrib/llvm/tools/lld/ELF/InputFiles.cpp index d99f71eb4aae..260a78ebbf8e 100644 --- a/contrib/llvm/tools/lld/ELF/InputFiles.cpp +++ b/contrib/llvm/tools/lld/ELF/InputFiles.cpp @@ -123,10 +123,10 @@ std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S, return ""; } -// Returns "(internal)", "foo.a(bar.o)" or "baz.o". +// Returns "<internal>", "foo.a(bar.o)" or "baz.o". std::string lld::toString(const InputFile *F) { if (!F) - return "(internal)"; + return "<internal>"; if (F->ToStringCache.empty()) { if (F->ArchiveName.empty()) @@ -137,15 +137,13 @@ std::string lld::toString(const InputFile *F) { return F->ToStringCache; } -template <class ELFT> static ELFKind getELFKind() { - if (ELFT::TargetEndianness == support::little) - return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind; - return ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind; -} - template <class ELFT> ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { - EKind = getELFKind<ELFT>(); + if (ELFT::TargetEndianness == support::little) + EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind; + else + EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind; + EMachine = getObj().getHeader()->e_machine; OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI]; } @@ -174,8 +172,10 @@ void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections, } template <class ELFT> -elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M) - : ELFFileBase<ELFT>(Base::ObjectKind, M) {} +elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M, StringRef ArchiveName) + : ELFFileBase<ELFT>(Base::ObjectKind, M) { + this->ArchiveName = ArchiveName; +} template <class ELFT> ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() { @@ -361,6 +361,15 @@ InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { return Target; } +// Create a regular InputSection class that has the same contents +// as a given section. +InputSectionBase *toRegularSection(MergeInputSection *Sec) { + auto *Ret = make<InputSection>(Sec->Flags, Sec->Type, Sec->Alignment, + Sec->Data, Sec->Name); + Ret->File = Sec->File; + return Ret; +} + template <class ELFT> InputSectionBase * elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec, @@ -398,9 +407,18 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec, if (Target->FirstRelocation) fatal(toString(this) + ": multiple relocation sections to one section are not supported"); - if (isa<MergeInputSection>(Target)) - fatal(toString(this) + - ": relocations pointing to SHF_MERGE are not supported"); + + // Mergeable sections with relocations are tricky because relocations + // need to be taken into account when comparing section contents for + // merging. It's not worth supporting such mergeable sections because + // they are rare and it'd complicates the internal design (we usually + // have to determine if two sections are mergeable early in the link + // process much before applying relocations). We simply handle mergeable + // sections with relocations as non-mergeable. + if (auto *MS = dyn_cast<MergeInputSection>(Target)) { + Target = toRegularSection(MS); + this->Sections[Sec.sh_info] = Target; + } size_t NumRelocations; if (Sec.sh_type == SHT_RELA) { @@ -461,6 +479,15 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec, if (Config->Strip != StripPolicy::None && Name.startswith(".debug")) return &InputSection::Discarded; + // If -gdb-index is given, LLD creates .gdb_index section, and that + // section serves the same purpose as .debug_gnu_pub{names,types} sections. + // If that's the case, we want to eliminate .debug_gnu_pub{names,types} + // because they are redundant and can waste large amount of disk space + // (for example, they are about 400 MiB in total for a clang debug build.) + if (Config->GdbIndex && + (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes")) + return &InputSection::Discarded; + // The linkonce feature is a sort of proto-comdat. Some glibc i386 object // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce // sections. Drop those sections to avoid duplicate symbol errors. @@ -665,7 +692,7 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { uint64_t Val = Dyn.getVal(); if (Val >= this->StringTable.size()) fatal(toString(this) + ": invalid DT_SONAME entry"); - SoName = StringRef(this->StringTable.data() + Val); + SoName = this->StringTable.data() + Val; return; } } @@ -748,7 +775,7 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { // with explicit versions. if (V) { StringRef VerName = this->StringTable.data() + V->getAux()->vda_name; - Name = Saver.save(Twine(Name) + "@" + VerName); + Name = Saver.save(Name + "@" + VerName); elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); } } @@ -862,76 +889,50 @@ void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this)); } -// Small bit of template meta programming to handle the SharedFile constructor -// being the only one with a DefaultSoName parameter. -template <template <class> class T, class E> -typename std::enable_if<std::is_same<T<E>, SharedFile<E>>::value, - InputFile *>::type -createELFAux(MemoryBufferRef MB, StringRef DefaultSoName) { - return make<T<E>>(MB, DefaultSoName); -} -template <template <class> class T, class E> -typename std::enable_if<!std::is_same<T<E>, SharedFile<E>>::value, - InputFile *>::type -createELFAux(MemoryBufferRef MB, StringRef DefaultSoName) { - return make<T<E>>(MB); -} - -template <template <class> class T> -static InputFile *createELFFile(MemoryBufferRef MB, StringRef DefaultSoName) { +static ELFKind getELFKind(MemoryBufferRef MB) { unsigned char Size; unsigned char Endian; std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); + if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) fatal(MB.getBufferIdentifier() + ": invalid data encoding"); + if (Size != ELFCLASS32 && Size != ELFCLASS64) + fatal(MB.getBufferIdentifier() + ": invalid file class"); size_t BufSize = MB.getBuffer().size(); if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) || (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr))) fatal(MB.getBufferIdentifier() + ": file is too short"); - InputFile *Obj; - if (Size == ELFCLASS32 && Endian == ELFDATA2LSB) - Obj = createELFAux<T, ELF32LE>(MB, DefaultSoName); - else if (Size == ELFCLASS32 && Endian == ELFDATA2MSB) - Obj = createELFAux<T, ELF32BE>(MB, DefaultSoName); - else if (Size == ELFCLASS64 && Endian == ELFDATA2LSB) - Obj = createELFAux<T, ELF64LE>(MB, DefaultSoName); - else if (Size == ELFCLASS64 && Endian == ELFDATA2MSB) - Obj = createELFAux<T, ELF64BE>(MB, DefaultSoName); - else - fatal(MB.getBufferIdentifier() + ": invalid file class"); - - if (!Config->FirstElf) - Config->FirstElf = Obj; - return Obj; + if (Size == ELFCLASS32) + return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; + return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; } template <class ELFT> void BinaryFile::parse() { - StringRef Buf = MB.getBuffer(); - ArrayRef<uint8_t> Data = - makeArrayRef<uint8_t>((const uint8_t *)Buf.data(), Buf.size()); - - std::string Filename = MB.getBufferIdentifier(); - std::transform(Filename.begin(), Filename.end(), Filename.begin(), - [](char C) { return isalnum(C) ? C : '_'; }); - Filename = "_binary_" + Filename; - StringRef StartName = Saver.save(Twine(Filename) + "_start"); - StringRef EndName = Saver.save(Twine(Filename) + "_end"); - StringRef SizeName = Saver.save(Twine(Filename) + "_size"); - + ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer()); auto *Section = make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data"); Sections.push_back(Section); - elf::Symtab<ELFT>::X->addRegular(StartName, STV_DEFAULT, STT_OBJECT, 0, 0, - STB_GLOBAL, Section, nullptr); - elf::Symtab<ELFT>::X->addRegular(EndName, STV_DEFAULT, STT_OBJECT, - Data.size(), 0, STB_GLOBAL, Section, - nullptr); - elf::Symtab<ELFT>::X->addRegular(SizeName, STV_DEFAULT, STT_OBJECT, - Data.size(), 0, STB_GLOBAL, nullptr, + // For each input file foo that is embedded to a result as a binary + // blob, we define _binary_foo_{start,end,size} symbols, so that + // user programs can access blobs by name. Non-alphanumeric + // characters in a filename are replaced with underscore. + std::string S = "_binary_" + MB.getBufferIdentifier().str(); + for (size_t I = 0; I < S.size(); ++I) + if (!isalnum(S[I])) + S[I] = '_'; + + elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_start"), STV_DEFAULT, + STT_OBJECT, 0, 0, STB_GLOBAL, Section, nullptr); + elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_end"), STV_DEFAULT, + STT_OBJECT, Data.size(), 0, STB_GLOBAL, + Section, nullptr); + elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_size"), STV_DEFAULT, + STT_OBJECT, Data.size(), 0, STB_GLOBAL, + nullptr, nullptr); } static bool isBitcode(MemoryBufferRef MB) { @@ -941,15 +942,36 @@ static bool isBitcode(MemoryBufferRef MB) { InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) { - InputFile *F = isBitcode(MB) - ? make<BitcodeFile>(MB, ArchiveName, OffsetInArchive) - : createELFFile<ObjectFile>(MB, ""); - F->ArchiveName = ArchiveName; - return F; + if (isBitcode(MB)) + return make<BitcodeFile>(MB, ArchiveName, OffsetInArchive); + + switch (getELFKind(MB)) { + case ELF32LEKind: + return make<ObjectFile<ELF32LE>>(MB, ArchiveName); + case ELF32BEKind: + return make<ObjectFile<ELF32BE>>(MB, ArchiveName); + case ELF64LEKind: + return make<ObjectFile<ELF64LE>>(MB, ArchiveName); + case ELF64BEKind: + return make<ObjectFile<ELF64BE>>(MB, ArchiveName); + default: + llvm_unreachable("getELFKind"); + } } InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { - return createELFFile<SharedFile>(MB, DefaultSoName); + switch (getELFKind(MB)) { + case ELF32LEKind: + return make<SharedFile<ELF32LE>>(MB, DefaultSoName); + case ELF32BEKind: + return make<SharedFile<ELF32BE>>(MB, DefaultSoName); + case ELF64LEKind: + return make<SharedFile<ELF64LE>>(MB, DefaultSoName); + case ELF64BEKind: + return make<SharedFile<ELF64BE>>(MB, DefaultSoName); + default: + llvm_unreachable("getELFKind"); + } } MemoryBufferRef LazyObjectFile::getBuffer() { @@ -1004,17 +1026,18 @@ std::vector<StringRef> LazyObjectFile::getSymbols() { if (isBitcode(this->MB)) return getBitcodeSymbols(); - unsigned char Size; - unsigned char Endian; - std::tie(Size, Endian) = getElfArchType(this->MB.getBuffer()); - if (Size == ELFCLASS32) { - if (Endian == ELFDATA2LSB) - return getElfSymbols<ELF32LE>(); + switch (getELFKind(this->MB)) { + case ELF32LEKind: + return getElfSymbols<ELF32LE>(); + case ELF32BEKind: return getElfSymbols<ELF32BE>(); - } - if (Endian == ELFDATA2LSB) + case ELF64LEKind: return getElfSymbols<ELF64LE>(); - return getElfSymbols<ELF64BE>(); + case ELF64BEKind: + return getElfSymbols<ELF64BE>(); + default: + llvm_unreachable("getELFKind"); + } } template void ArchiveFile::parse<ELF32LE>(); diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.h b/contrib/llvm/tools/lld/ELF/InputFiles.h index 4552270316d9..d0a45a4a98cf 100644 --- a/contrib/llvm/tools/lld/ELF/InputFiles.h +++ b/contrib/llvm/tools/lld/ELF/InputFiles.h @@ -156,7 +156,7 @@ public: ArrayRef<SymbolBody *> getSymbols(); ArrayRef<SymbolBody *> getLocalSymbols(); - explicit ObjectFile(MemoryBufferRef M); + ObjectFile(MemoryBufferRef M, StringRef ArchiveName); void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); InputSectionBase *getSection(const Elf_Sym &Sym) const; diff --git a/contrib/llvm/tools/lld/ELF/InputSection.cpp b/contrib/llvm/tools/lld/ELF/InputSection.cpp index aff57551a8b3..c082f128a9bc 100644 --- a/contrib/llvm/tools/lld/ELF/InputSection.cpp +++ b/contrib/llvm/tools/lld/ELF/InputSection.cpp @@ -39,9 +39,7 @@ std::vector<InputSectionBase *> elf::InputSections; // Returns a string to construct an error message. std::string lld::toString(const InputSectionBase *Sec) { - // File can be absent if section is synthetic. - std::string FileName = Sec->File ? Sec->File->getName() : "<internal>"; - return (FileName + ":(" + Sec->Name + ")").str(); + return (toString(Sec->File) + ":(" + Sec->Name + ")").str(); } template <class ELFT> diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp index 63eb90456e17..3f872c65897f 100644 --- a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp +++ b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp @@ -406,8 +406,15 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { } // Add input sections to an output section. - for (InputSectionBase *S : V) - Factory.addInputSec(S, Cmd->Name); + unsigned Pos = 0; + for (InputSectionBase *S : V) { + // The actual offset will be computed during + // assignAddresses. For now, use the index as a very crude + // approximation so that it is at least easy for other code to + // know the section order. + cast<InputSection>(S)->OutSecOff = Pos++; + Factory.addInputSec(S, Cmd->Name, Cmd->Sec); + } } } CurOutSec = nullptr; @@ -421,13 +428,12 @@ void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) { if (AllocateHeader) StartAddr += elf::getHeaderSize(); - // The Sections with -T<section> are sorted in order of ascending address - // we must use this if it is lower than StartAddr as calls to setDot() must - // be monotonically increasing - if (!Config->SectionStartMap.empty()) { - uint64_t LowestSecStart = Config->SectionStartMap.begin()->second; - StartAddr = std::min(StartAddr, LowestSecStart); - } + // The Sections with -T<section> have been sorted in order of ascending + // address. We must lower StartAddr if the lowest -T<section address> as + // calls to setDot() must be monotonically increasing. + for (auto& KV : Config->SectionStartMap) + StartAddr = std::min(StartAddr, KV.second); + Commands.push_back( make<SymbolAssignment>(".", [=] { return StartAddr; }, "")); @@ -437,17 +443,19 @@ void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) { if (!(Sec->Flags & SHF_ALLOC)) continue; + auto *OSCmd = make<OutputSectionCommand>(Sec->Name); + OSCmd->Sec = Sec; + + // Prefer user supplied address over additional alignment constraint auto I = Config->SectionStartMap.find(Sec->Name); if (I != Config->SectionStartMap.end()) Commands.push_back( make<SymbolAssignment>(".", [=] { return I->second; }, "")); - - auto *OSCmd = make<OutputSectionCommand>(Sec->Name); - OSCmd->Sec = Sec; - if (Sec->PageAlign) + else if (Sec->PageAlign) OSCmd->AddrExpr = [=] { return alignTo(Script->getDot(), Config->MaxPageSize); }; + Commands.push_back(OSCmd); if (Sec->Sections.size()) { auto *ISD = make<InputSectionDescription>(""); @@ -465,9 +473,26 @@ void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) { // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { - for (InputSectionBase *S : InputSections) - if (S->Live && !S->OutSec) - Factory.addInputSec(S, getOutputSectionName(S->Name)); + for (InputSectionBase *S : InputSections) { + if (!S->Live || S->OutSec) + continue; + StringRef Name = getOutputSectionName(S->Name); + auto I = std::find_if( + Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + return Cmd->Name == Name; + return false; + }); + if (I == Opt.Commands.end()) { + Factory.addInputSec(S, Name); + } else { + auto *Cmd = cast<OutputSectionCommand>(*I); + Factory.addInputSec(S, Name, Cmd->Sec); + auto *ISD = make<InputSectionDescription>(""); + ISD->Sections.push_back(S); + Cmd->Commands.push_back(ISD); + } + } } static bool isTbss(OutputSection *Sec) { @@ -475,8 +500,6 @@ static bool isTbss(OutputSection *Sec) { } void LinkerScript::output(InputSection *S) { - if (!AlreadyOutputIS.insert(S).second) - return; bool IsTbss = isTbss(CurOutSec); uint64_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot; @@ -508,19 +531,9 @@ void LinkerScript::output(InputSection *S) { Dot = Pos; } -void LinkerScript::flush() { - assert(CurOutSec); - if (!AlreadyOutputOS.insert(CurOutSec).second) - return; - for (InputSection *I : CurOutSec->Sections) - output(I); -} - void LinkerScript::switchTo(OutputSection *Sec) { if (CurOutSec == Sec) return; - if (AlreadyOutputOS.count(Sec)) - return; CurOutSec = Sec; @@ -571,19 +584,11 @@ void LinkerScript::process(BaseCommand &Base) { if (!Sec->Live) continue; - assert(CurOutSec == Sec->OutSec || AlreadyOutputOS.count(Sec->OutSec)); + assert(CurOutSec == Sec->OutSec); output(cast<InputSection>(Sec)); } } -static OutputSection * -findSection(StringRef Name, const std::vector<OutputSection *> &Sections) { - for (OutputSection *Sec : Sections) - if (Sec->Name == Name) - return Sec; - return nullptr; -} - // This function searches for a memory region to place the given output // section in. If found, a pointer to the appropriate memory region is // returned. Otherwise, a nullptr is returned. @@ -638,19 +643,8 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { Dot = CurMemRegion->Offset; switchTo(Sec); - // flush() may add orphan sections, so the order of flush() and - // symbol assignments is important. We want to call flush() first so - // that symbols pointing the end of the current section points to - // the location after orphan sections. - auto Mid = - std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(), - [](BaseCommand *Cmd) { return !isa<SymbolAssignment>(Cmd); }) - .base(); - for (auto I = Cmd->Commands.begin(); I != Mid; ++I) - process(**I); - flush(); - for (auto I = Mid, E = Cmd->Commands.end(); I != E; ++I) - process(**I); + for (BaseCommand *C : Cmd->Commands) + process(*C); } void LinkerScript::removeEmptyCommands() { @@ -663,7 +657,8 @@ void LinkerScript::removeEmptyCommands() { auto Pos = std::remove_if( Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - return !Cmd->Sec; + return std::find(OutputSections->begin(), OutputSections->end(), + Cmd->Sec) == OutputSections->end(); return false; }); Opt.Commands.erase(Pos, Opt.Commands.end()); @@ -687,8 +682,7 @@ void LinkerScript::adjustSectionsBeforeSorting() { auto *Cmd = dyn_cast<OutputSectionCommand>(Base); if (!Cmd) continue; - if (OutputSection *Sec = findSection(Cmd->Name, *OutputSections)) { - Cmd->Sec = Sec; + if (OutputSection *Sec = Cmd->Sec) { Flags = Sec->Flags; Type = Sec->Type; continue; @@ -820,15 +814,24 @@ void LinkerScript::placeOrphanSections() { ++CmdIndex; } + // If there is no command corresponding to this output section, + // create one and put a InputSectionDescription in it so that both + // representations agree on which input sections to use. auto Pos = std::find_if(CmdIter, E, [&](BaseCommand *Base) { auto *Cmd = dyn_cast<OutputSectionCommand>(Base); return Cmd && Cmd->Name == Name; }); if (Pos == E) { auto *Cmd = make<OutputSectionCommand>(Name); - Cmd->Sec = Sec; Opt.Commands.insert(CmdIter, Cmd); ++CmdIndex; + + Cmd->Sec = Sec; + auto *ISD = make<InputSectionDescription>(""); + for (InputSection *IS : Sec->Sections) + ISD->Sections.push_back(IS); + Cmd->Commands.push_back(ISD); + continue; } @@ -846,6 +849,51 @@ void LinkerScript::processNonSectionCommands() { } } +// Do a last effort at synchronizing the linker script "AST" and the section +// list. This is needed to account for last minute changes, like adding a +// .ARM.exidx terminator and sorting SHF_LINK_ORDER sections. +// +// FIXME: We should instead create the "AST" earlier and the above changes would +// be done directly in the "AST". +// +// This can only handle new sections being added and sections being reordered. +void LinkerScript::synchronize() { + for (BaseCommand *Base : Opt.Commands) { + auto *Cmd = dyn_cast<OutputSectionCommand>(Base); + if (!Cmd) + continue; + ArrayRef<InputSection *> Sections = Cmd->Sec->Sections; + std::vector<InputSectionBase **> ScriptSections; + DenseSet<InputSectionBase *> ScriptSectionsSet; + for (BaseCommand *Base : Cmd->Commands) { + auto *ISD = dyn_cast<InputSectionDescription>(Base); + if (!ISD) + continue; + for (InputSectionBase *&IS : ISD->Sections) { + if (IS->Live) { + ScriptSections.push_back(&IS); + ScriptSectionsSet.insert(IS); + } + } + } + std::vector<InputSectionBase *> Missing; + for (InputSection *IS : Sections) + if (!ScriptSectionsSet.count(IS)) + Missing.push_back(IS); + if (!Missing.empty()) { + auto ISD = make<InputSectionDescription>(""); + ISD->Sections = Missing; + Cmd->Commands.push_back(ISD); + for (InputSectionBase *&IS : ISD->Sections) + if (IS->Live) + ScriptSections.push_back(&IS); + } + assert(ScriptSections.size() == Sections.size()); + for (int I = 0, N = Sections.size(); I < N; ++I) + *ScriptSections[I] = Sections[I]; + } +} + void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.h b/contrib/llvm/tools/lld/ELF/LinkerScript.h index 61942b2db357..dd96d335a660 100644 --- a/contrib/llvm/tools/lld/ELF/LinkerScript.h +++ b/contrib/llvm/tools/lld/ELF/LinkerScript.h @@ -228,7 +228,6 @@ protected: MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); void switchTo(OutputSection *Sec); - void flush(); void output(InputSection *Sec); void process(BaseCommand &Base); @@ -242,9 +241,6 @@ protected: OutputSection *CurOutSec = nullptr; MemoryRegion *CurMemRegion = nullptr; - llvm::DenseSet<OutputSection *> AlreadyOutputOS; - llvm::DenseSet<InputSectionBase *> AlreadyOutputIS; - public: bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } @@ -271,6 +267,7 @@ public: void assignOffsets(OutputSectionCommand *Cmd); void placeOrphanSections(); void processNonSectionCommands(); + void synchronize(); void assignAddresses(std::vector<PhdrEntry> &Phdrs); int getSectionIndex(StringRef Name); diff --git a/contrib/llvm/tools/lld/ELF/MapFile.cpp b/contrib/llvm/tools/lld/ELF/MapFile.cpp index 31c8091bb6a1..af5bc3c2c813 100644 --- a/contrib/llvm/tools/lld/ELF/MapFile.cpp +++ b/contrib/llvm/tools/lld/ELF/MapFile.cpp @@ -11,19 +11,19 @@ // hierarchically the output sections, input sections, input files and // symbol: // -// Address Size Align Out In File Symbol -// ================================================================= -// 00201000 00000015 4 .text -// 00201000 0000000e 4 .text -// 00201000 0000000e 4 test.o -// 0020100e 00000000 0 local -// 00201005 00000000 0 f(int) +// Address Size Align Out In Symbol +// 00201000 00000015 4 .text +// 00201000 0000000e 4 test.o:(.text) +// 0020100e 00000000 0 local +// 00201005 00000000 0 f(int) // //===----------------------------------------------------------------------===// #include "MapFile.h" #include "InputFiles.h" #include "Strings.h" +#include "SymbolTable.h" +#include "Threads.h" #include "llvm/Support/raw_ostream.h" @@ -33,83 +33,68 @@ using namespace llvm::object; using namespace lld; using namespace lld::elf; -static void writeOutSecLine(raw_fd_ostream &OS, int Width, uint64_t Address, - uint64_t Size, uint64_t Align, StringRef Name) { - OS << format("%0*llx %0*llx %5lld ", Width, Address, Width, Size, Align) - << left_justify(Name, 7); -} - -static void writeInSecLine(raw_fd_ostream &OS, int Width, uint64_t Address, - uint64_t Size, uint64_t Align, StringRef Name) { - // Pass an empty name to align the text to the correct column. - writeOutSecLine(OS, Width, Address, Size, Align, ""); - OS << ' ' << left_justify(Name, 7); -} +typedef DenseMap<const SectionBase *, SmallVector<DefinedRegular *, 4>> + SymbolMapTy; -static void writeFileLine(raw_fd_ostream &OS, int Width, uint64_t Address, - uint64_t Size, uint64_t Align, StringRef Name) { - // Pass an empty name to align the text to the correct column. - writeInSecLine(OS, Width, Address, Size, Align, ""); - OS << ' ' << left_justify(Name, 7); +// Print out the first three columns of a line. +template <class ELFT> +static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, + uint64_t Align) { + int W = ELFT::Is64Bits ? 16 : 8; + OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align); } -static void writeSymbolLine(raw_fd_ostream &OS, int Width, uint64_t Address, - uint64_t Size, StringRef Name) { - // Pass an empty name to align the text to the correct column. - writeFileLine(OS, Width, Address, Size, 0, ""); - OS << ' ' << left_justify(Name, 7); +static std::string indent(int Depth) { return std::string(Depth * 8, ' '); } + +// Returns a list of all symbols that we want to print out. +template <class ELFT> std::vector<DefinedRegular *> getSymbols() { + std::vector<DefinedRegular *> V; + for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles()) + for (SymbolBody *B : File->getSymbols()) + if (B->File == File && !B->isSection()) + if (auto *Sym = dyn_cast<DefinedRegular>(B)) + if (Sym->Section) + V.push_back(Sym); + return V; } +// Returns a map from sections to their symbols. template <class ELFT> -static void writeInputSection(raw_fd_ostream &OS, const InputSection *IS, - StringRef &PrevName) { - int Width = ELFT::Is64Bits ? 16 : 8; - StringRef Name = IS->Name; - if (Name != PrevName) { - writeInSecLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(), - IS->Alignment, Name); - OS << '\n'; - PrevName = Name; - } - - elf::ObjectFile<ELFT> *File = IS->template getFile<ELFT>(); - if (!File) - return; - writeFileLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(), - IS->Alignment, toString(File)); - OS << '\n'; - - for (SymbolBody *Sym : File->getSymbols()) { - auto *DR = dyn_cast<DefinedRegular>(Sym); - if (!DR) - continue; - if (DR->Section != IS) - continue; - if (DR->isSection()) - continue; - writeSymbolLine(OS, Width, Sym->getVA(), Sym->getSize<ELFT>(), - toString(*Sym)); - OS << '\n'; +SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) { + SymbolMapTy Ret; + for (DefinedRegular *S : Syms) + Ret[S->Section].push_back(S); + + // Sort symbols by address. We want to print out symbols in the + // order in the output file rather than the order they appeared + // in the input files. + for (auto &It : Ret) { + SmallVectorImpl<DefinedRegular *> &V = It.second; + std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) { + return A->getVA() < B->getVA(); + }); } + return Ret; } +// Construct a map from symbols to their stringified representations. +// Demangling symbols (which is what toString() does) is slow, so +// we do that in batch using parallel-for. template <class ELFT> -static void writeMapFile2(raw_fd_ostream &OS, - ArrayRef<OutputSection *> OutputSections) { - int Width = ELFT::Is64Bits ? 16 : 8; - - OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width) - << " Align Out In File Symbol\n"; - - for (OutputSection *Sec : OutputSections) { - writeOutSecLine(OS, Width, Sec->Addr, Sec->Size, Sec->Alignment, Sec->Name); - OS << '\n'; - - StringRef PrevName = ""; - for (InputSection *IS : Sec->Sections) { - writeInputSection<ELFT>(OS, IS, PrevName); - } - } +DenseMap<DefinedRegular *, std::string> +getSymbolStrings(ArrayRef<DefinedRegular *> Syms) { + std::vector<std::string> Str(Syms.size()); + parallelFor(0, Syms.size(), [&](size_t I) { + raw_string_ostream OS(Str[I]); + writeHeader<ELFT>(OS, Syms[I]->getVA(), Syms[I]->template getSize<ELFT>(), + 0); + OS << indent(2) << toString(*Syms[I]); + }); + + DenseMap<DefinedRegular *, std::string> Ret; + for (size_t I = 0, E = Syms.size(); I < E; ++I) + Ret[Syms[I]] = std::move(Str[I]); + return Ret; } template <class ELFT> @@ -117,12 +102,38 @@ void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) { if (Config->MapFile.empty()) return; + // Open a map file for writing. std::error_code EC; raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); - if (EC) + if (EC) { error("cannot open " + Config->MapFile + ": " + EC.message()); - else - writeMapFile2<ELFT>(OS, OutputSections); + return; + } + + // Collect symbol info that we want to print out. + std::vector<DefinedRegular *> Syms = getSymbols<ELFT>(); + SymbolMapTy SectionSyms = getSectionSyms<ELFT>(Syms); + DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings<ELFT>(Syms); + + // Print out the header line. + int W = ELFT::Is64Bits ? 16 : 8; + OS << left_justify("Address", W) << ' ' << left_justify("Size", W) + << " Align Out In Symbol\n"; + + // Print out file contents. + for (OutputSection *OSec : OutputSections) { + writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment); + OS << OSec->Name << '\n'; + + // Dump symbols for each input section. + for (InputSection *IS : OSec->Sections) { + writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), + IS->Alignment); + OS << indent(1) << toString(IS) << '\n'; + for (DefinedRegular *Sym : SectionSyms[IS]) + OS << SymStr[Sym] << '\n'; + } + } } template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSection *>); diff --git a/contrib/llvm/tools/lld/ELF/Options.td b/contrib/llvm/tools/lld/ELF/Options.td index fda675449956..8863912c179c 100644 --- a/contrib/llvm/tools/lld/ELF/Options.td +++ b/contrib/llvm/tools/lld/ELF/Options.td @@ -344,6 +344,26 @@ def end_group_paren: Flag<["-"], ")">; def start_group: F<"start-group">; def start_group_paren: Flag<["-"], "(">; +// LTO-related options. +def lto_aa_pipeline: J<"lto-aa-pipeline=">, + HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">; +def lto_newpm_passes: J<"lto-newpm-passes=">, + HelpText<"Passes to run during LTO">; +def lto_partitions: J<"lto-partitions=">, + HelpText<"Number of LTO codegen partitions">; +def disable_verify: F<"disable-verify">; +def mllvm: S<"mllvm">; +def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">, + HelpText<"YAML output file for optimization remarks">; +def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">, + HelpText<"Include hotness informations in the optimization remarks file">; +def save_temps: F<"save-temps">; +def thinlto_cache_dir: J<"thinlto-cache-dir=">, + HelpText<"Path to ThinLTO cached object file directory">; +def thinlto_cache_policy: S<"thinlto-cache-policy">, + HelpText<"Pruning policy for the ThinLTO cache">; +def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; + // Ignore LTO plugin-related options. // clang -flto passes -plugin and -plugin-opt to the linker. This is required // for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't @@ -365,6 +385,7 @@ def no_add_needed: F<"no-add-needed">; def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">; def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">, Alias<no_add_needed>; +def no_keep_memory: F<"no-keep-memory">; def no_mmap_output_file: F<"no-mmap-output-file">; def no_warn_common: F<"no-warn-common">; def no_warn_mismatch: F<"no-warn-mismatch">; @@ -382,23 +403,3 @@ def Qy : F<"Qy">; // Aliases for ignored options def alias_version_script_version_script: J<"version-script=">, Alias<version_script>; - -// LTO-related options. -def lto_aa_pipeline: J<"lto-aa-pipeline=">, - HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">; -def lto_newpm_passes: J<"lto-newpm-passes=">, - HelpText<"Passes to run during LTO">; -def lto_partitions: J<"lto-partitions=">, - HelpText<"Number of LTO codegen partitions">; -def disable_verify: F<"disable-verify">; -def mllvm: S<"mllvm">; -def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">, - HelpText<"YAML output file for optimization remarks">; -def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">, - HelpText<"Include hotness informations in the optimization remarks file">; -def save_temps: F<"save-temps">; -def thinlto_cache_dir: J<"thinlto-cache-dir=">, - HelpText<"Path to ThinLTO cached object file directory">; -def thinlto_cache_policy: S<"thinlto-cache-policy">, - HelpText<"Pruning policy for the ThinLTO cache">; -def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; diff --git a/contrib/llvm/tools/lld/ELF/OutputSections.cpp b/contrib/llvm/tools/lld/ELF/OutputSections.cpp index 71fc00ac35e7..839f68f2da55 100644 --- a/contrib/llvm/tools/lld/ELF/OutputSections.cpp +++ b/contrib/llvm/tools/lld/ELF/OutputSections.cpp @@ -395,14 +395,20 @@ static void reportDiscarded(InputSectionBase *IS) { void OutputSectionFactory::addInputSec(InputSectionBase *IS, StringRef OutsecName) { + SectionKey Key = createKey(IS, OutsecName); + OutputSection *&Sec = Map[Key]; + return addInputSec(IS, OutsecName, Sec); +} + +void OutputSectionFactory::addInputSec(InputSectionBase *IS, + StringRef OutsecName, + OutputSection *&Sec) { if (!IS->Live) { reportDiscarded(IS); return; } - SectionKey Key = createKey(IS, OutsecName); uint64_t Flags = getOutFlags(IS); - OutputSection *&Sec = Map[Key]; if (Sec) { if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) error("incompatible section flags for " + Sec->Name + @@ -418,7 +424,7 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, } Sec->Flags |= Flags; } else { - Sec = make<OutputSection>(Key.Name, IS->Type, Flags); + Sec = make<OutputSection>(OutsecName, IS->Type, Flags); OutputSections.push_back(Sec); } diff --git a/contrib/llvm/tools/lld/ELF/OutputSections.h b/contrib/llvm/tools/lld/ELF/OutputSections.h index bcda77d1a26d..6405fb38c6d6 100644 --- a/contrib/llvm/tools/lld/ELF/OutputSections.h +++ b/contrib/llvm/tools/lld/ELF/OutputSections.h @@ -141,6 +141,8 @@ public: ~OutputSectionFactory(); void addInputSec(InputSectionBase *IS, StringRef OutsecName); + void addInputSec(InputSectionBase *IS, StringRef OutsecName, + OutputSection *&Sec); private: llvm::SmallDenseMap<SectionKey, OutputSection *> Map; diff --git a/contrib/llvm/tools/lld/ELF/Strings.h b/contrib/llvm/tools/lld/ELF/Strings.h index 934b6427105f..bcfa28144989 100644 --- a/contrib/llvm/tools/lld/ELF/Strings.h +++ b/contrib/llvm/tools/lld/ELF/Strings.h @@ -76,6 +76,10 @@ llvm::Optional<std::string> demangle(StringRef Name); inline StringRef toStringRef(ArrayRef<uint8_t> Arr) { return {(const char *)Arr.data(), Arr.size()}; } + +inline ArrayRef<uint8_t> toArrayRef(StringRef S) { + return {(const uint8_t *)S.data(), S.size()}; +} } } diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp index e55b8bf52c10..30f1c3653f50 100644 --- a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp +++ b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp @@ -52,6 +52,9 @@ template <class ELFT> static bool isCompatible(InputFile *F) { // Add symbols in File to the symbol table. template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) { + if (!Config->FirstElf && isa<ELFFileBase<ELFT>>(File)) + Config->FirstElf = File; + if (!isCompatible<ELFT>(File)) return; @@ -276,9 +279,10 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal, return S; } if (Binding != STB_WEAK) { - if (S->body()->isShared() || S->body()->isLazy()) + SymbolBody *B = S->body(); + if (B->isShared() || B->isLazy() || B->isUndefined()) S->Binding = Binding; - if (auto *SS = dyn_cast<SharedSymbol>(S->body())) + if (auto *SS = dyn_cast<SharedSymbol>(B)) cast<SharedFile<ELFT>>(SS->File)->IsUsed = true; } if (auto *L = dyn_cast<Lazy>(S->body())) { diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp index e1f81940bb59..a271d31048f5 100644 --- a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp +++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp @@ -97,7 +97,7 @@ static ArrayRef<uint8_t> getVersion() { // Creates a .comment section containing LLD version info. // With this feature, you can identify LLD-generated binaries easily -// by "objdump -s -j .comment <file>". +// by "readelf --string-dump .comment <file>". // The returned object is a mergeable string section. template <class ELFT> MergeInputSection *elf::createCommentSection() { typename ELFT::Shdr Hdr = {}; @@ -541,6 +541,13 @@ template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() { Off += alignTo(Fde->size(), Config->Wordsize); } } + + // The LSB standard does not allow a .eh_frame section with zero + // Call Frame Information records. Therefore add a CIE record length + // 0 as a terminator if this .eh_frame section is empty. + if (Off == 0) + Off = 4; + this->Size = Off; } @@ -1022,9 +1029,9 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() { // fixed early. for (StringRef S : Config->AuxiliaryList) add({DT_AUXILIARY, In<ELFT>::DynStrTab->addString(S)}); - if (!Config->RPath.empty()) + if (!Config->Rpath.empty()) add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, - In<ELFT>::DynStrTab->addString(Config->RPath)}); + In<ELFT>::DynStrTab->addString(Config->Rpath)}); for (SharedFile<ELFT> *F : Symtab<ELFT>::X->getSharedFiles()) if (F->isNeeded()) add({DT_NEEDED, In<ELFT>::DynStrTab->addString(F->SoName)}); diff --git a/contrib/llvm/tools/lld/ELF/Target.cpp b/contrib/llvm/tools/lld/ELF/Target.cpp index 7bc29e3d3de2..921505ae4b61 100644 --- a/contrib/llvm/tools/lld/ELF/Target.cpp +++ b/contrib/llvm/tools/lld/ELF/Target.cpp @@ -1324,8 +1324,8 @@ RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, return R_ABS; case R_AARCH64_TLSDESC_ADR_PAGE21: return R_TLSDESC_PAGE; - case R_AARCH64_TLSDESC_LD64_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: + case R_AARCH64_TLSDESC_ADD_LO12: return R_TLSDESC; case R_AARCH64_TLSDESC_CALL: return R_TLSDESC_CALL; @@ -1376,8 +1376,8 @@ bool AArch64TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { case R_AARCH64_LDST32_ABS_LO12_NC: case R_AARCH64_LDST64_ABS_LO12_NC: case R_AARCH64_LDST8_ABS_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12_NC: - case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: + case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return true; } @@ -1503,7 +1503,7 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, break; case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: checkAlignment<8>(Loc, Val, Type); or32le(Loc, (Val & 0xFF8) << 7); break; @@ -1543,7 +1543,7 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, or32AArch64Imm(Loc, Val >> 12); break; case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: or32AArch64Imm(Loc, Val); break; default: @@ -1555,8 +1555,8 @@ void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] - // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC] - // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC] + // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] + // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] // .tlsdesccall [R_AARCH64_TLSDESC_CALL] // blr x1 // And it can optimized to: @@ -1567,14 +1567,14 @@ void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, checkUInt<32>(Loc, Val, Type); switch (Type) { - case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: write32le(Loc, 0xd503201f); // nop return; case R_AARCH64_TLSDESC_ADR_PAGE21: write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz return; - case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk return; default: @@ -1586,8 +1586,8 @@ void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] - // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC] - // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC] + // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] + // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] // .tlsdesccall [R_AARCH64_TLSDESC_CALL] // blr x1 // And it can optimized to: @@ -1597,7 +1597,7 @@ void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, // nop switch (Type) { - case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: write32le(Loc, 0xd503201f); // nop break; @@ -1605,7 +1605,7 @@ void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, write32le(Loc, 0x90000000); // adrp relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val); break; - case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: write32le(Loc, 0xf9400000); // ldr relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val); break; diff --git a/contrib/llvm/tools/lld/ELF/Writer.cpp b/contrib/llvm/tools/lld/ELF/Writer.cpp index 876585dbbb28..326df41b2286 100644 --- a/contrib/llvm/tools/lld/ELF/Writer.cpp +++ b/contrib/llvm/tools/lld/ELF/Writer.cpp @@ -101,7 +101,7 @@ StringRef elf::getOutputSectionName(StringRef Name) { for (StringRef V : {".rel.", ".rela."}) { if (Name.startswith(V)) { StringRef Inner = getOutputSectionName(Name.substr(V.size() - 1)); - return Saver.save(Twine(V.drop_back()) + Inner); + return Saver.save(V.drop_back() + Inner); } } } @@ -123,7 +123,7 @@ StringRef elf::getOutputSectionName(StringRef Name) { // ".zdebug_" is a prefix for ZLIB-compressed sections. // Because we decompressed input sections, we want to remove 'z'. if (Name.startswith(".zdebug_")) - return Saver.save(Twine(".") + Name.substr(2)); + return Saver.save("." + Name.substr(2)); return Name; } @@ -252,8 +252,9 @@ template <class ELFT> void Writer<ELFT>::run() { } else { if (!Script->Opt.HasSections) { fixSectionAlignments(); - Script->fabricateDefaultCommands(Config->MaxPageSize); + Script->fabricateDefaultCommands(AllocateHeader); } + Script->synchronize(); Script->assignAddresses(Phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a @@ -1080,6 +1081,7 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) { SS->OutSec->Sections.erase(std::find(SS->OutSec->Sections.begin(), SS->OutSec->Sections.end(), SS)); + SS->Live = false; // If there are no other sections in the output section, remove it from the // output. if (SS->OutSec->Sections.empty()) diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Module.h b/contrib/llvm/tools/lldb/include/lldb/Core/Module.h index ca47a38a2ef5..33735bc99f60 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/Module.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/Module.h @@ -614,6 +614,8 @@ public: const FileSpec &GetSymbolFileFileSpec() const { return m_symfile_spec; } + void PreloadSymbols(); + void SetSymbolFileFileSpec(const FileSpec &file); const llvm::sys::TimePoint<> &GetModificationTime() const { diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/TraceOptions.h b/contrib/llvm/tools/lldb/include/lldb/Core/TraceOptions.h index ffa2bae7f659..e875a531e870 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/TraceOptions.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/TraceOptions.h @@ -59,4 +59,4 @@ private: }; } -#endif // liblldb_TraceOptions_h_
\ No newline at end of file +#endif // liblldb_TraceOptions_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/UniqueCStringMap.h b/contrib/llvm/tools/lldb/include/lldb/Core/UniqueCStringMap.h index 1475fdaa74d9..e8c6c7c1353e 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/UniqueCStringMap.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/UniqueCStringMap.h @@ -17,10 +17,9 @@ // Other libraries and framework includes // Project includes +#include "lldb/Utility/ConstString.h" #include "lldb/Utility/RegularExpression.h" -#include "llvm/ADT/StringRef.h" - namespace lldb_private { //---------------------------------------------------------------------- @@ -37,13 +36,17 @@ public: struct Entry { Entry() {} - Entry(llvm::StringRef cstr) : cstring(cstr), value() {} + Entry(ConstString cstr) : cstring(cstr), value() {} - Entry(llvm::StringRef cstr, const T &v) : cstring(cstr), value(v) {} + Entry(ConstString cstr, const T &v) : cstring(cstr), value(v) {} - bool operator<(const Entry &rhs) const { return cstring < rhs.cstring; } + // This is only for uniqueness, not lexicographical ordering, so we can + // just compare pointers. + bool operator<(const Entry &rhs) const { + return cstring.GetCString() < rhs.cstring.GetCString(); + } - llvm::StringRef cstring; + ConstString cstring; T value; }; @@ -52,7 +55,7 @@ public: // this map, then later call UniqueCStringMap<T>::Sort() before doing // any searches by name. //------------------------------------------------------------------ - void Append(llvm::StringRef unique_cstr, const T &value) { + void Append(ConstString unique_cstr, const T &value) { m_map.push_back(typename UniqueCStringMap<T>::Entry(unique_cstr, value)); } @@ -64,7 +67,7 @@ public: // Call this function to always keep the map sorted when putting // entries into the map. //------------------------------------------------------------------ - void Insert(llvm::StringRef unique_cstr, const T &value) { + void Insert(ConstString unique_cstr, const T &value) { typename UniqueCStringMap<T>::Entry e(unique_cstr, value); m_map.insert(std::upper_bound(m_map.begin(), m_map.end(), e), e); } @@ -87,7 +90,7 @@ public: return false; } - llvm::StringRef GetCStringAtIndexUnchecked(uint32_t idx) const { + ConstString GetCStringAtIndexUnchecked(uint32_t idx) const { return m_map[idx].cstring; } @@ -101,8 +104,8 @@ public: return m_map[idx].value; } - llvm::StringRef GetCStringAtIndex(uint32_t idx) const { - return ((idx < m_map.size()) ? m_map[idx].cstring : llvm::StringRef()); + ConstString GetCStringAtIndex(uint32_t idx) const { + return ((idx < m_map.size()) ? m_map[idx].cstring : ConstString()); } //------------------------------------------------------------------ @@ -113,7 +116,7 @@ public: // T values and only if there is a sensible failure value that can // be returned and that won't match any existing values. //------------------------------------------------------------------ - T Find(llvm::StringRef unique_cstr, T fail_value) const { + T Find(ConstString unique_cstr, T fail_value) const { Entry search_entry(unique_cstr); const_iterator end = m_map.end(); const_iterator pos = std::lower_bound(m_map.begin(), end, search_entry); @@ -131,15 +134,12 @@ public: // The caller is responsible for ensuring that the collection does // not change during while using the returned pointer. //------------------------------------------------------------------ - const Entry *FindFirstValueForName(llvm::StringRef unique_cstr) const { + const Entry *FindFirstValueForName(ConstString unique_cstr) const { Entry search_entry(unique_cstr); const_iterator end = m_map.end(); const_iterator pos = std::lower_bound(m_map.begin(), end, search_entry); - if (pos != end) { - llvm::StringRef pos_cstr = pos->cstring; - if (pos_cstr == unique_cstr) - return &(*pos); - } + if (pos != end && pos->cstring == unique_cstr) + return &(*pos); return nullptr; } @@ -164,7 +164,7 @@ public: return nullptr; } - size_t GetValues(llvm::StringRef unique_cstr, std::vector<T> &values) const { + size_t GetValues(ConstString unique_cstr, std::vector<T> &values) const { const size_t start_size = values.size(); Entry search_entry(unique_cstr); @@ -186,7 +186,7 @@ public: const_iterator pos, end = m_map.end(); for (pos = m_map.begin(); pos != end; ++pos) { - if (regex.Execute(pos->cstring)) + if (regex.Execute(pos->cstring.GetCString())) values.push_back(pos->value); } @@ -240,7 +240,7 @@ public: } } - size_t Erase(llvm::StringRef unique_cstr) { + size_t Erase(ConstString unique_cstr) { size_t num_removed = 0; Entry search_entry(unique_cstr); iterator end = m_map.end(); diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Config.h.cmake b/contrib/llvm/tools/lldb/include/lldb/Host/Config.h.cmake index d072c1a08687..5a16425fe0a9 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/Config.h.cmake +++ b/contrib/llvm/tools/lldb/include/lldb/Host/Config.h.cmake @@ -16,4 +16,8 @@ #cmakedefine01 HAVE_SYS_EVENT_H +#cmakedefine01 HAVE_PPOLL + +#cmakedefine01 HAVE_SIGACTION + #endif // #ifndef LLDB_HOST_CONFIG_H diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h b/contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h index 8aa26b63183a..79370bf8461f 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h @@ -10,16 +10,96 @@ #ifndef lldb_Host_MainLoop_h_ #define lldb_Host_MainLoop_h_ -#ifdef _WIN32 +#include "lldb/Host/Config.h" #include "lldb/Host/MainLoopBase.h" + +#include "llvm/ADT/DenseMap.h" + +#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H +#define SIGNAL_POLLING_UNSUPPORTED 1 +#endif + namespace lldb_private { -typedef MainLoopBase MainLoop; -} -#else -#include "lldb/Host/posix/MainLoopPosix.h" -namespace lldb_private { -typedef MainLoopPosix MainLoop; -} + +// Implementation of the MainLoopBase class. It can monitor file descriptors for +// readability using ppoll, kqueue, poll or WSAPoll. On Windows it only supports +// polling sockets, and will not work on generic file handles or pipes. On +// systems without kqueue or ppoll handling singnals is not supported. In +// addition to the common base, this class provides the ability to invoke a +// given handler when a signal is received. +// +// Since this class is primarily intended to be used for single-threaded +// processing, it does not attempt to perform any internal synchronisation and +// any concurrent accesses must be protected externally. However, it is +// perfectly legitimate to have more than one instance of this class running on +// separate threads, or even a single thread (with some limitations on signal +// monitoring). +// TODO: Add locking if this class is to be used in a multi-threaded context. +class MainLoop : public MainLoopBase { +private: + class SignalHandle; + +public: + typedef std::unique_ptr<SignalHandle> SignalHandleUP; + + ~MainLoop() override; + + ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, + const Callback &callback, + Error &error) override; + + // Listening for signals from multiple MainLoop instances is perfectly safe as + // long as they don't try to listen for the same signal. The callback function + // is invoked when the control returns to the Run() function, not when the + // hander is executed. This mean that you can treat the callback as a normal + // function and perform things which would not be safe in a signal handler. + // However, since the callback is not invoked synchronously, you cannot use + // this mechanism to handle SIGSEGV and the like. + SignalHandleUP RegisterSignal(int signo, const Callback &callback, + Error &error); + + Error Run() override; + + // This should only be performed from a callback. Do not attempt to terminate + // the processing from another thread. + // TODO: Add synchronization if we want to be terminated from another thread. + void RequestTermination() override { m_terminate_request = true; } + +protected: + void UnregisterReadObject(IOObject::WaitableHandle handle) override; + + void UnregisterSignal(int signo); + +private: + class SignalHandle { + public: + ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); } + + private: + SignalHandle(MainLoop &mainloop, int signo) + : m_mainloop(mainloop), m_signo(signo) {} + + MainLoop &m_mainloop; + int m_signo; + + friend class MainLoop; + DISALLOW_COPY_AND_ASSIGN(SignalHandle); + }; + + struct SignalInfo { + Callback callback; +#if HAVE_SIGACTION + struct sigaction old_action; #endif + bool was_blocked : 1; + }; + class RunImpl; + + llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds; + llvm::DenseMap<int, SignalInfo> m_signals; + bool m_terminate_request : 1; +}; + +} // namespace lldb_private #endif // lldb_Host_MainLoop_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/PosixApi.h b/contrib/llvm/tools/lldb/include/lldb/Host/PosixApi.h index 23a291c401de..02324307dc9e 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/PosixApi.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/PosixApi.h @@ -14,9 +14,7 @@ // to provide a minimum level of compatibility across all platforms to rely // on various posix api functionality. -#include "llvm/Support/Compiler.h" - -#if defined(LLVM_ON_WIN32) +#if defined(_WIN32) #include "lldb/Host/windows/PosixApi.h" #endif diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Socket.h b/contrib/llvm/tools/lldb/include/lldb/Host/Socket.h index 386133e96952..36d506281cf8 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/Socket.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/Socket.h @@ -57,8 +57,7 @@ public: virtual Error Connect(llvm::StringRef name) = 0; virtual Error Listen(llvm::StringRef name, int backlog) = 0; - virtual Error Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) = 0; + virtual Error Accept(Socket *&socket) = 0; // Initialize a Tcp Socket object in listening mode. listen and accept are // implemented @@ -103,7 +102,8 @@ public: int32_t &port, Error *error_ptr); protected: - Socket(NativeSocket socket, SocketProtocol protocol, bool should_close); + Socket(SocketProtocol protocol, bool should_close, + bool m_child_process_inherit); virtual size_t Send(const void *buf, const size_t num_bytes); @@ -117,6 +117,7 @@ protected: SocketProtocol m_protocol; NativeSocket m_socket; + bool m_child_processes_inherit; }; } // namespace lldb_private diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/TCPSocket.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/TCPSocket.h index 2ce8d824f0a0..5b72f344019f 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/common/TCPSocket.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/TCPSocket.h @@ -11,12 +11,16 @@ #define liblldb_TCPSocket_h_ #include "lldb/Host/Socket.h" +#include "lldb/Host/SocketAddress.h" +#include <map> namespace lldb_private { class TCPSocket : public Socket { public: - TCPSocket(NativeSocket socket, bool should_close); - TCPSocket(bool child_processes_inherit, Error &error); + TCPSocket(bool should_close, bool child_processes_inherit); + TCPSocket(NativeSocket socket, bool should_close, + bool child_processes_inherit); + ~TCPSocket() override; // returns port number or 0 if error uint16_t GetLocalPortNumber() const; @@ -37,8 +41,18 @@ public: Error Connect(llvm::StringRef name) override; Error Listen(llvm::StringRef name, int backlog) override; - Error Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&conn_socket) override; + Error Accept(Socket *&conn_socket) override; + + Error CreateSocket(int domain); + + bool IsValid() const override; + +private: + TCPSocket(NativeSocket socket, const TCPSocket &listen_socket); + + void CloseListenSockets(); + + std::map<int, SocketAddress> m_listen_sockets; }; } diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/UDPSocket.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/UDPSocket.h index 507c9827caf6..38524fa8f62b 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/common/UDPSocket.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/UDPSocket.h @@ -15,19 +15,20 @@ namespace lldb_private { class UDPSocket : public Socket { public: - UDPSocket(bool child_processes_inherit, Error &error); + UDPSocket(bool should_close, bool child_processes_inherit); static Error Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket); private: - UDPSocket(NativeSocket socket); + UDPSocket(NativeSocket socket, const UDPSocket &listen_socket); size_t Send(const void *buf, const size_t num_bytes) override; Error Connect(llvm::StringRef name) override; Error Listen(llvm::StringRef name, int backlog) override; - Error Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) override; + Error Accept(Socket *&socket) override; + + Error CreateSocket(); SocketAddress m_sockaddr; }; diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/DomainSocket.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/DomainSocket.h index 3bd4e0141336..78a3dc89828a 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/DomainSocket.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/posix/DomainSocket.h @@ -15,22 +15,20 @@ namespace lldb_private { class DomainSocket : public Socket { public: - DomainSocket(bool child_processes_inherit, Error &error); + DomainSocket(bool should_close, bool child_processes_inherit); Error Connect(llvm::StringRef name) override; Error Listen(llvm::StringRef name, int backlog) override; - Error Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) override; + Error Accept(Socket *&socket) override; protected: - DomainSocket(SocketProtocol protocol, bool child_processes_inherit, - Error &error); + DomainSocket(SocketProtocol protocol, bool child_processes_inherit); virtual size_t GetNameOffset() const; virtual void DeleteSocketFile(llvm::StringRef name); private: - DomainSocket(NativeSocket socket); + DomainSocket(NativeSocket socket, const DomainSocket &listen_socket); }; } diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/MainLoopPosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/MainLoopPosix.h deleted file mode 100644 index 21e02becf872..000000000000 --- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/MainLoopPosix.h +++ /dev/null @@ -1,104 +0,0 @@ -//===-- MainLoopPosix.h -----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef lldb_Host_posix_MainLoopPosix_h_ -#define lldb_Host_posix_MainLoopPosix_h_ - -#include "lldb/Host/MainLoopBase.h" - -#include "llvm/ADT/DenseMap.h" - -namespace lldb_private { - -// Posix implementation of the MainLoopBase class. It can monitor file -// descriptors for -// readability using pselect. In addition to the common base, this class -// provides the ability to -// invoke a given handler when a signal is received. -// -// Since this class is primarily intended to be used for single-threaded -// processing, it does not -// attempt to perform any internal synchronisation and any concurrent accesses -// must be protected -// externally. However, it is perfectly legitimate to have more than one -// instance of this class -// running on separate threads, or even a single thread (with some limitations -// on signal -// monitoring). -// TODO: Add locking if this class is to be used in a multi-threaded context. -class MainLoopPosix : public MainLoopBase { -private: - class SignalHandle; - -public: - typedef std::unique_ptr<SignalHandle> SignalHandleUP; - - ~MainLoopPosix() override; - - ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, - const Callback &callback, - Error &error) override; - - // Listening for signals from multiple MainLoopPosix instances is perfectly - // safe as long as they - // don't try to listen for the same signal. The callback function is invoked - // when the control - // returns to the Run() function, not when the hander is executed. This means - // that you can - // treat the callback as a normal function and perform things which would not - // be safe in a - // signal handler. However, since the callback is not invoked synchronously, - // you cannot use - // this mechanism to handle SIGSEGV and the like. - SignalHandleUP RegisterSignal(int signo, const Callback &callback, - Error &error); - - Error Run() override; - - // This should only be performed from a callback. Do not attempt to terminate - // the processing - // from another thread. - // TODO: Add synchronization if we want to be terminated from another thread. - void RequestTermination() override { m_terminate_request = true; } - -protected: - void UnregisterReadObject(IOObject::WaitableHandle handle) override; - - void UnregisterSignal(int signo); - -private: - class SignalHandle { - public: - ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); } - - private: - SignalHandle(MainLoopPosix &mainloop, int signo) - : m_mainloop(mainloop), m_signo(signo) {} - - MainLoopPosix &m_mainloop; - int m_signo; - - friend class MainLoopPosix; - DISALLOW_COPY_AND_ASSIGN(SignalHandle); - }; - - struct SignalInfo { - Callback callback; - struct sigaction old_action; - bool was_blocked : 1; - }; - - llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds; - llvm::DenseMap<int, SignalInfo> m_signals; - bool m_terminate_request : 1; -}; - -} // namespace lldb_private - -#endif // lldb_Host_posix_MainLoopPosix_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h index 03564eca4b58..296c9ff2129f 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h @@ -805,9 +805,9 @@ public: bool IsInMemory() const { return m_memory_addr != LLDB_INVALID_ADDRESS; } // Strip linker annotations (such as @@VERSION) from symbol names. - virtual std::string + virtual llvm::StringRef StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { - return symbol_name.str(); + return symbol_name; } static lldb::SymbolType GetSymbolTypeFromName( diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolFile.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolFile.h index 34ae8d76e195..69110dc68cd7 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolFile.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolFile.h @@ -180,6 +180,8 @@ public: uint32_t type_mask, lldb_private::TypeList &type_list) = 0; + virtual void PreloadSymbols(); + virtual lldb_private::TypeSystem * GetTypeSystemForLanguage(lldb::LanguageType language); diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Symtab.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Symtab.h index 6a8d62cea8b7..3d24862af365 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Symtab.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Symtab.h @@ -40,6 +40,7 @@ public: Symtab(ObjectFile *objfile); ~Symtab(); + void PreloadSymbols(); void Reserve(size_t count); Symbol *Resize(size_t count); uint32_t AddSymbol(const Symbol &symbol); diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Target.h b/contrib/llvm/tools/lldb/include/lldb/Target/Target.h index 8d6fc772c887..8aa263f59254 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/Target.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/Target.h @@ -82,6 +82,10 @@ public: bool SetPreferDynamicValue(lldb::DynamicValueType d); + bool GetPreloadSymbols() const; + + void SetPreloadSymbols(bool b); + bool GetDisableASLR() const; void SetDisableASLR(bool b); diff --git a/contrib/llvm/tools/lldb/source/Core/Module.cpp b/contrib/llvm/tools/lldb/source/Core/Module.cpp index ddc9fca80671..d168474c3479 100644 --- a/contrib/llvm/tools/lldb/source/Core/Module.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Module.cpp @@ -1432,6 +1432,22 @@ size_t Module::FindSymbolsMatchingRegExAndType(const RegularExpression ®ex, return sc_list.GetSize() - initial_size; } +void Module::PreloadSymbols() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + SymbolVendor * sym_vendor = GetSymbolVendor(); + if (!sym_vendor) { + return; + } + // Prime the symbol file first, since it adds symbols to the symbol table. + if (SymbolFile *symbol_file = sym_vendor->GetSymbolFile()) { + symbol_file->PreloadSymbols(); + } + // Now we can prime the symbol table. + if (Symtab * symtab = sym_vendor->GetSymtab()) { + symtab->PreloadSymbols(); + } +} + void Module::SetSymbolFileFileSpec(const FileSpec &file) { if (!file.Exists()) return; diff --git a/contrib/llvm/tools/lldb/source/Host/common/MainLoop.cpp b/contrib/llvm/tools/lldb/source/Host/common/MainLoop.cpp new file mode 100644 index 000000000000..8a9d4f020d5f --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/MainLoop.cpp @@ -0,0 +1,382 @@ +//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/llvm-config.h" + +#include "lldb/Host/MainLoop.h" +#include "lldb/Utility/Error.h" +#include <algorithm> +#include <cassert> +#include <cerrno> +#include <csignal> +#include <vector> +#include <time.h> + +#if HAVE_SYS_EVENT_H +#include <sys/event.h> +#elif defined(LLVM_ON_WIN32) +#include <winsock2.h> +#else +#include <poll.h> +#endif + +#ifdef LLVM_ON_WIN32 +#define POLL WSAPoll +#else +#define POLL poll +#endif + +#ifdef __ANDROID__ +#define FORCE_PSELECT +#endif + +#if SIGNAL_POLLING_UNSUPPORTED +#ifdef LLVM_ON_WIN32 +typedef int sigset_t; +typedef int siginfo_t; +#endif + +int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts, + const sigset_t *) { + int timeout = + (timeout_ts == nullptr) + ? -1 + : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000); + return POLL(fds, nfds, timeout); +} + +#endif + +using namespace lldb; +using namespace lldb_private; + +static sig_atomic_t g_signal_flags[NSIG]; + +static void SignalHandler(int signo, siginfo_t *info, void *) { + assert(signo < NSIG); + g_signal_flags[signo] = 1; +} + +class MainLoop::RunImpl { +public: + // TODO: Use llvm::Expected<T> + static std::unique_ptr<RunImpl> Create(MainLoop &loop, Error &error); + ~RunImpl(); + + Error Poll(); + + template <typename F> void ForEachReadFD(F &&f); + template <typename F> void ForEachSignal(F &&f); + +private: + MainLoop &loop; + +#if HAVE_SYS_EVENT_H + int queue_id; + std::vector<struct kevent> in_events; + struct kevent out_events[4]; + int num_events = -1; + + RunImpl(MainLoop &loop, int queue_id) : loop(loop), queue_id(queue_id) { + in_events.reserve(loop.m_read_fds.size() + loop.m_signals.size()); + } +#else + std::vector<int> signals; +#ifdef FORCE_PSELECT + fd_set read_fd_set; +#else + std::vector<struct pollfd> read_fds; +#endif + + RunImpl(MainLoop &loop) : loop(loop) { + signals.reserve(loop.m_signals.size()); + } + + sigset_t get_sigmask(); +#endif +}; + +#if HAVE_SYS_EVENT_H +MainLoop::RunImpl::~RunImpl() { + int r = close(queue_id); + assert(r == 0); + (void)r; +} +std::unique_ptr<MainLoop::RunImpl> MainLoop::RunImpl::Create(MainLoop &loop, Error &error) +{ + error.Clear(); + int queue_id = kqueue(); + if(queue_id < 0) { + error = Error(errno, eErrorTypePOSIX); + return nullptr; + } + return std::unique_ptr<RunImpl>(new RunImpl(loop, queue_id)); +} + +Error MainLoop::RunImpl::Poll() { + in_events.resize(loop.m_read_fds.size() + loop.m_signals.size()); + unsigned i = 0; + for (auto &fd : loop.m_read_fds) + EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0); + + for (const auto &sig : loop.m_signals) + EV_SET(&in_events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); + + num_events = kevent(queue_id, in_events.data(), in_events.size(), out_events, + llvm::array_lengthof(out_events), nullptr); + + if (num_events < 0) + return Error("kevent() failed with error %d\n", num_events); + return Error(); +} + +template <typename F> void MainLoop::RunImpl::ForEachReadFD(F &&f) { + assert(num_events >= 0); + for (int i = 0; i < num_events; ++i) { + f(out_events[i].ident); + if (loop.m_terminate_request) + return; + } +} +template <typename F> void MainLoop::RunImpl::ForEachSignal(F && f) {} +#else +MainLoop::RunImpl::~RunImpl() {} +std::unique_ptr<MainLoop::RunImpl> MainLoop::RunImpl::Create(MainLoop &loop, Error &error) +{ + error.Clear(); + return std::unique_ptr<RunImpl>(new RunImpl(loop)); +} + +sigset_t MainLoop::RunImpl::get_sigmask() { +#if SIGNAL_POLLING_UNSUPPORTED + return 0; +#else + sigset_t sigmask; + int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask); + assert(ret == 0); + (void) ret; + + for (const auto &sig : loop.m_signals) { + signals.push_back(sig.first); + sigdelset(&sigmask, sig.first); + } + return sigmask; +#endif +} + +#ifdef FORCE_PSELECT +Error MainLoop::RunImpl::Poll() { + signals.clear(); + + FD_ZERO(&read_fd_set); + int nfds = 0; + for (const auto &fd : loop.m_read_fds) { + FD_SET(fd.first, &read_fd_set); + nfds = std::max(nfds, fd.first + 1); + } + + sigset_t sigmask = get_sigmask(); + if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 && + errno != EINTR) + return Error(errno, eErrorTypePOSIX); + + return Error(); +} + +template <typename F> void MainLoop::RunImpl::ForEachReadFD(F &&f) { + for (const auto &fd : loop.m_read_fds) { + if(!FD_ISSET(fd.first, &read_fd_set)) + continue; + + f(fd.first); + if (loop.m_terminate_request) + return; + } +} +#else +Error MainLoop::RunImpl::Poll() { + signals.clear(); + read_fds.clear(); + + sigset_t sigmask = get_sigmask(); + + for (const auto &fd : loop.m_read_fds) { + struct pollfd pfd; + pfd.fd = fd.first; + pfd.events = POLLIN; + pfd.revents = 0; + read_fds.push_back(pfd); + } + + if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 && + errno != EINTR) + return Error(errno, eErrorTypePOSIX); + + return Error(); +} + +template <typename F> void MainLoop::RunImpl::ForEachReadFD(F &&f) { + for (const auto &fd : read_fds) { + if ((fd.revents & POLLIN) == 0) + continue; + + f(fd.fd); + if (loop.m_terminate_request) + return; + } +} +#endif + +template <typename F> void MainLoop::RunImpl::ForEachSignal(F &&f) { + for (int sig : signals) { + if (g_signal_flags[sig] == 0) + continue; // No signal + g_signal_flags[sig] = 0; + f(sig); + + if (loop.m_terminate_request) + return; + } +} +#endif + +MainLoop::~MainLoop() { + assert(m_read_fds.size() == 0); + assert(m_signals.size() == 0); +} + +MainLoop::ReadHandleUP +MainLoop::RegisterReadObject(const IOObjectSP &object_sp, + const Callback &callback, Error &error) { +#ifdef LLVM_ON_WIN32 + if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) { + error.SetErrorString("MainLoop: non-socket types unsupported on Windows"); + return nullptr; + } +#endif + if (!object_sp || !object_sp->IsValid()) { + error.SetErrorString("IO object is not valid."); + return nullptr; + } + + const bool inserted = + m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second; + if (!inserted) { + error.SetErrorStringWithFormat("File descriptor %d already monitored.", + object_sp->GetWaitableHandle()); + return nullptr; + } + + return CreateReadHandle(object_sp); +} + +// We shall block the signal, then install the signal handler. The signal will +// be unblocked in +// the Run() function to check for signal delivery. +MainLoop::SignalHandleUP +MainLoop::RegisterSignal(int signo, const Callback &callback, + Error &error) { +#ifdef SIGNAL_POLLING_UNSUPPORTED + error.SetErrorString("Signal polling is not supported on this platform."); + return nullptr; +#else + if (m_signals.find(signo) != m_signals.end()) { + error.SetErrorStringWithFormat("Signal %d already monitored.", signo); + return nullptr; + } + + SignalInfo info; + info.callback = callback; + struct sigaction new_action; + new_action.sa_sigaction = &SignalHandler; + new_action.sa_flags = SA_SIGINFO; + sigemptyset(&new_action.sa_mask); + sigaddset(&new_action.sa_mask, signo); + + sigset_t old_set; + if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) { + error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", + ret); + return nullptr; + } + + info.was_blocked = sigismember(&old_set, signo); + if (sigaction(signo, &new_action, &info.old_action) == -1) { + error.SetErrorToErrno(); + if (!info.was_blocked) + pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr); + return nullptr; + } + + m_signals.insert({signo, info}); + g_signal_flags[signo] = 0; + + return SignalHandleUP(new SignalHandle(*this, signo)); +#endif +} + +void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) { + bool erased = m_read_fds.erase(handle); + UNUSED_IF_ASSERT_DISABLED(erased); + assert(erased); +} + +void MainLoop::UnregisterSignal(int signo) { +#if SIGNAL_POLLING_UNSUPPORTED + Error("Signal polling is not supported on this platform."); +#else + // We undo the actions of RegisterSignal on a best-effort basis. + auto it = m_signals.find(signo); + assert(it != m_signals.end()); + + sigaction(signo, &it->second.old_action, nullptr); + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, signo); + pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, + nullptr); + + m_signals.erase(it); +#endif +} + +Error MainLoop::Run() { + m_terminate_request = false; + + Error error; + auto impl = RunImpl::Create(*this, error); + if (!impl) + return error; + + // run until termination or until we run out of things to listen to + while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) { + + error = impl->Poll(); + if (error.Fail()) + return error; + + impl->ForEachSignal([&](int sig) { + auto it = m_signals.find(sig); + if (it != m_signals.end()) + it->second.callback(*this); // Do the work + }); + if (m_terminate_request) + return Error(); + + impl->ForEachReadFD([&](int fd) { + auto it = m_read_fds.find(fd); + if (it != m_read_fds.end()) + it->second(*this); // Do the work + }); + if (m_terminate_request) + return Error(); + } + return Error(); +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp index 2a665ddacb64..d73b5d0ad073 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp @@ -18,6 +18,8 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" +#include "llvm/ADT/STLExtras.h" + #ifndef LLDB_DISABLE_POSIX #include "lldb/Host/posix/DomainSocket.h" @@ -67,9 +69,11 @@ bool IsInterrupted() { } } -Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close) +Socket::Socket(SocketProtocol protocol, bool should_close, + bool child_processes_inherit) : IOObject(eFDTypeSocket, should_close), m_protocol(protocol), - m_socket(socket) {} + m_socket(kInvalidSocketValue), + m_child_processes_inherit(child_processes_inherit) {} Socket::~Socket() { Close(); } @@ -81,14 +85,17 @@ std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol, std::unique_ptr<Socket> socket_up; switch (protocol) { case ProtocolTcp: - socket_up.reset(new TCPSocket(child_processes_inherit, error)); + socket_up = + llvm::make_unique<TCPSocket>(true, child_processes_inherit); break; case ProtocolUdp: - socket_up.reset(new UDPSocket(child_processes_inherit, error)); + socket_up = + llvm::make_unique<UDPSocket>(true, child_processes_inherit); break; case ProtocolUnixDomain: #ifndef LLDB_DISABLE_POSIX - socket_up.reset(new DomainSocket(child_processes_inherit, error)); + socket_up = + llvm::make_unique<DomainSocket>(true, child_processes_inherit); #else error.SetErrorString( "Unix domain sockets are not supported on this platform."); @@ -96,7 +103,8 @@ std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol, break; case ProtocolUnixAbstract: #ifdef __linux__ - socket_up.reset(new AbstractSocket(child_processes_inherit, error)); + socket_up = + llvm::make_unique<AbstractSocket>(child_processes_inherit); #else error.SetErrorString( "Abstract domain sockets are not supported on this platform."); @@ -145,7 +153,7 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, return error; std::unique_ptr<TCPSocket> listen_socket( - new TCPSocket(child_processes_inherit, error)); + new TCPSocket(true, child_processes_inherit)); if (error.Fail()) return error; @@ -208,7 +216,7 @@ Error Socket::UnixDomainAccept(llvm::StringRef name, if (error.Fail()) return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = listen_socket->Accept(socket); return error; } @@ -240,18 +248,22 @@ Error Socket::UnixAbstractAccept(llvm::StringRef name, if (error.Fail()) return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = listen_socket->Accept(socket); return error; } bool Socket::DecodeHostAndPort(llvm::StringRef host_and_port, std::string &host_str, std::string &port_str, int32_t &port, Error *error_ptr) { - static RegularExpression g_regex(llvm::StringRef("([^:]+):([0-9]+)")); + static RegularExpression g_regex( + llvm::StringRef("([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)")); RegularExpression::Match regex_match(2); if (g_regex.Execute(host_and_port, ®ex_match)) { if (regex_match.GetMatchAtIndex(host_and_port.data(), 1, host_str) && regex_match.GetMatchAtIndex(host_and_port.data(), 2, port_str)) { + // IPv6 addresses are wrapped in [] when specified with ports + if (host_str.front() == '[' && host_str.back() == ']') + host_str = host_str.substr(1, host_str.size() - 2); bool ok = false; port = StringConvert::ToUInt32(port_str.c_str(), UINT32_MAX, 10, &ok); if (ok && port <= UINT16_MAX) { @@ -404,12 +416,12 @@ NativeSocket Socket::CreateSocket(const int domain, const int type, const int protocol, bool child_processes_inherit, Error &error) { error.Clear(); - auto socketType = type; + auto socket_type = type; #ifdef SOCK_CLOEXEC if (!child_processes_inherit) - socketType |= SOCK_CLOEXEC; + socket_type |= SOCK_CLOEXEC; #endif - auto sock = ::socket(domain, socketType, protocol); + auto sock = ::socket(domain, socket_type, protocol); if (sock == kInvalidSocketValue) SetLastError(error); diff --git a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp index b41cef6ca2eb..440ae5d9027f 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp @@ -6,6 +6,12 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// +// Note: This file is used on Darwin by debugserver, so it needs to remain as +// self contained as possible, and devoid of references to LLVM unless +// there is compelling reason. +// +//===----------------------------------------------------------------------===// #if defined(_MSC_VER) #define _WINSOCK_DEPRECATED_NO_WARNINGS @@ -227,7 +233,8 @@ bool SocketAddress::getaddrinfo(const char *host, const char *service, int ai_flags) { Clear(); - auto addresses = GetAddressInfo(host, service, ai_family, ai_socktype, ai_protocol, ai_flags); + auto addresses = GetAddressInfo(host, service, ai_family, ai_socktype, + ai_protocol, ai_flags); if (!addresses.empty()) *this = addresses[0]; return IsValid(); diff --git a/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp b/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp index 9a009280a904..55db4bb0c456 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp @@ -14,30 +14,57 @@ #include "lldb/Host/common/TCPSocket.h" #include "lldb/Host/Config.h" +#include "lldb/Host/MainLoop.h" #include "lldb/Utility/Log.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/raw_ostream.h" + #ifndef LLDB_DISABLE_POSIX #include <arpa/inet.h> #include <netinet/tcp.h> #include <sys/socket.h> #endif +#if defined(LLVM_ON_WIN32) +#include <winsock2.h> +#endif + +#ifdef LLVM_ON_WIN32 +#define CLOSE_SOCKET closesocket +typedef const char *set_socket_option_arg_type; +#else +#define CLOSE_SOCKET ::close +typedef const void *set_socket_option_arg_type; +#endif + using namespace lldb; using namespace lldb_private; namespace { - -const int kDomain = AF_INET; const int kType = SOCK_STREAM; } -TCPSocket::TCPSocket(NativeSocket socket, bool should_close) - : Socket(socket, ProtocolTcp, should_close) {} +TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit) + : Socket(ProtocolTcp, should_close, child_processes_inherit) {} -TCPSocket::TCPSocket(bool child_processes_inherit, Error &error) - : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP, - child_processes_inherit, error), - true) {} +TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket) + : Socket(ProtocolTcp, listen_socket.m_should_close_fd, + listen_socket.m_child_processes_inherit) { + m_socket = socket; +} + +TCPSocket::TCPSocket(NativeSocket socket, bool should_close, + bool child_processes_inherit) + : Socket(ProtocolTcp, should_close, child_processes_inherit) { + m_socket = socket; +} + +TCPSocket::~TCPSocket() { CloseListenSockets(); } + +bool TCPSocket::IsValid() const { + return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0; +} // Return the port number that is being used by the socket. uint16_t TCPSocket::GetLocalPortNumber() const { @@ -46,6 +73,12 @@ uint16_t TCPSocket::GetLocalPortNumber() const { socklen_t sock_addr_len = sock_addr.GetMaxLength(); if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0) return sock_addr.GetPort(); + } else if (!m_listen_sockets.empty()) { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength(); + if (::getsockname(m_listen_sockets.begin()->first, sock_addr, + &sock_addr_len) == 0) + return sock_addr.GetPort(); } return 0; } @@ -84,9 +117,18 @@ std::string TCPSocket::GetRemoteIPAddress() const { return ""; } +Error TCPSocket::CreateSocket(int domain) { + Error error; + if (IsValid()) + error = Close(); + if (error.Fail()) + return error; + m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP, + m_child_processes_inherit, error); + return error; +} + Error TCPSocket::Connect(llvm::StringRef name) { - if (m_socket == kInvalidSocketValue) - return Error("Invalid socket"); Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); if (log) @@ -99,146 +141,140 @@ Error TCPSocket::Connect(llvm::StringRef name) { if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) return error; - struct sockaddr_in sa; - ::memset(&sa, 0, sizeof(sa)); - sa.sin_family = kDomain; - sa.sin_port = htons(port); - - int inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr); - - if (inet_pton_result <= 0) { - struct hostent *host_entry = gethostbyname(host_str.c_str()); - if (host_entry) - host_str = ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list); - inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr); - if (inet_pton_result <= 0) { - if (inet_pton_result == -1) - SetLastError(error); - else - error.SetErrorStringWithFormat("invalid host string: '%s'", - host_str.c_str()); + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + for (auto address : addresses) { + error = CreateSocket(address.GetFamily()); + if (error.Fail()) + continue; - return error; + address.SetPort(port); + + if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(), + address.GetLength())) { + CLOSE_SOCKET(GetNativeSocket()); + continue; } - } - if (-1 == - ::connect(GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) { - SetLastError(error); + SetOptionNoDelay(); + + error.Clear(); return error; } - // Keep our TCP packets coming without any delays. - SetOptionNoDelay(); - error.Clear(); + error.SetErrorString("Failed to connect port"); return error; } Error TCPSocket::Listen(llvm::StringRef name, int backlog) { - Error error; - - // enable local address reuse - SetOptionReuseAddress(); - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data()); + Error error; std::string host_str; std::string port_str; int32_t port = INT32_MIN; if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) return error; - SocketAddress bind_addr; + if (host_str == "*") + host_str = "0.0.0.0"; + auto addresses = lldb_private::SocketAddress::GetAddressInfo( + host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + for (auto address : addresses) { + int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, + m_child_processes_inherit, error); + if (error.Fail()) { + error.Clear(); + continue; + } - // Only bind to the loopback address if we are expecting a connection from - // localhost to avoid any firewall issues. - const bool bind_addr_success = (host_str == "127.0.0.1") - ? bind_addr.SetToLocalhost(kDomain, port) - : bind_addr.SetToAnyAddress(kDomain, port); + // enable local address reuse + int option_value = 1; + set_socket_option_arg_type option_value_p = + reinterpret_cast<set_socket_option_arg_type>(&option_value); + ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p, + sizeof(option_value)); - if (!bind_addr_success) { - error.SetErrorString("Failed to bind port"); - return error; - } + address.SetPort(port); + + int err = ::bind(fd, &address.sockaddr(), address.GetLength()); + if (-1 != err) + err = ::listen(fd, backlog); - int err = ::bind(GetNativeSocket(), bind_addr, bind_addr.GetLength()); - if (err != -1) - err = ::listen(GetNativeSocket(), backlog); + if (-1 == err) { + CLOSE_SOCKET(fd); + continue; + } - if (err == -1) - SetLastError(error); + if (port == 0) { + socklen_t sa_len = address.GetLength(); + if (getsockname(fd, &address.sockaddr(), &sa_len) == 0) + port = address.GetPort(); + } + m_listen_sockets[fd] = address; + } + if (m_listen_sockets.size() == 0) + error.SetErrorString("Failed to connect port"); return error; } -Error TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&conn_socket) { +void TCPSocket::CloseListenSockets() { + for (auto socket : m_listen_sockets) + CLOSE_SOCKET(socket.first); + m_listen_sockets.clear(); +} + +Error TCPSocket::Accept(Socket *&conn_socket) { Error error; - std::string host_str; - std::string port_str; - int32_t port; - if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) + if (m_listen_sockets.size() == 0) { + error.SetErrorString("No open listening sockets!"); return error; + } - const sa_family_t family = kDomain; - const int socktype = kType; - const int protocol = IPPROTO_TCP; - SocketAddress listen_addr; - if (host_str.empty()) - listen_addr.SetToLocalhost(family, port); - else if (host_str.compare("*") == 0) - listen_addr.SetToAnyAddress(family, port); - else { - if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, - socktype, protocol)) { - error.SetErrorStringWithFormat("unable to resolve hostname '%s'", - host_str.c_str()); + int sock = -1; + int listen_sock = -1; + lldb_private::SocketAddress AcceptAddr; + MainLoop accept_loop; + std::vector<MainLoopBase::ReadHandleUP> handles; + for (auto socket : m_listen_sockets) { + auto fd = socket.first; + auto inherit = this->m_child_processes_inherit; + auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit)); + handles.emplace_back(accept_loop.RegisterReadObject( + io_sp, [fd, inherit, &sock, &AcceptAddr, &error, + &listen_sock](MainLoopBase &loop) { + socklen_t sa_len = AcceptAddr.GetMaxLength(); + sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit, + error); + listen_sock = fd; + loop.RequestTermination(); + }, error)); + if (error.Fail()) return error; - } } bool accept_connection = false; std::unique_ptr<TCPSocket> accepted_socket; - // Loop until we are happy with our connection while (!accept_connection) { - struct sockaddr_in accept_addr; - ::memset(&accept_addr, 0, sizeof accept_addr); -#if !(defined(__linux__) || defined(_WIN32)) - accept_addr.sin_len = sizeof accept_addr; -#endif - socklen_t accept_addr_len = sizeof accept_addr; - - int sock = AcceptSocket(GetNativeSocket(), (struct sockaddr *)&accept_addr, - &accept_addr_len, child_processes_inherit, error); - + accept_loop.Run(); + if (error.Fail()) - break; - - bool is_same_addr = true; -#if !(defined(__linux__) || (defined(_WIN32))) - is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len); -#endif - if (is_same_addr) - is_same_addr = (accept_addr.sin_addr.s_addr == - listen_addr.sockaddr_in().sin_addr.s_addr); - - if (is_same_addr || - (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY)) { - accept_connection = true; - accepted_socket.reset(new TCPSocket(sock, true)); - } else { - const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr; - const uint8_t *listen_ip = - (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr; - ::fprintf(stderr, "error: rejecting incoming connection from %u.%u.%u.%u " - "(expecting %u.%u.%u.%u)\n", - accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], - listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); - accepted_socket.reset(); + return error; + + lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock]; + if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) { + CLOSE_SOCKET(sock); + llvm::errs() << llvm::formatv( + "error: rejecting incoming connection from {0} (expecting {1})", + AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress()); + continue; } + accept_connection = true; + accepted_socket.reset(new TCPSocket(sock, *this)); } if (!accepted_socket) diff --git a/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp b/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp index 7ca62e7496ba..a32657aab0a6 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp @@ -28,13 +28,16 @@ const int kDomain = AF_INET; const int kType = SOCK_DGRAM; static const char *g_not_supported_error = "Not supported"; -} +} // namespace -UDPSocket::UDPSocket(NativeSocket socket) : Socket(socket, ProtocolUdp, true) {} +UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit) + : Socket(ProtocolUdp, should_close, child_processes_inherit) {} -UDPSocket::UDPSocket(bool child_processes_inherit, Error &error) - : UDPSocket( - CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {} +UDPSocket::UDPSocket(NativeSocket socket, const UDPSocket &listen_socket) + : Socket(ProtocolUdp, listen_socket.m_should_close_fd, + listen_socket.m_child_processes_inherit) { + m_socket = socket; +} size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { return ::sendto(m_socket, static_cast<const char *>(buf), num_bytes, 0, @@ -42,27 +45,14 @@ size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { } Error UDPSocket::Connect(llvm::StringRef name) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Listen(llvm::StringRef name, int backlog) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { - std::unique_ptr<UDPSocket> final_socket; - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("UDPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); Error error; + if (error.Fail()) + return error; + std::string host_str; std::string port_str; int32_t port = INT32_MIN; @@ -94,12 +84,11 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, for (struct addrinfo *service_info_ptr = service_info_list; service_info_ptr != nullptr; service_info_ptr = service_info_ptr->ai_next) { - auto send_fd = CreateSocket( + m_socket = Socket::CreateSocket( service_info_ptr->ai_family, service_info_ptr->ai_socktype, - service_info_ptr->ai_protocol, child_processes_inherit, error); + service_info_ptr->ai_protocol, m_child_processes_inherit, error); if (error.Success()) { - final_socket.reset(new UDPSocket(send_fd)); - final_socket->m_sockaddr = service_info_ptr; + m_sockaddr = service_info_ptr; break; } else continue; @@ -107,16 +96,17 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, ::freeaddrinfo(service_info_list); - if (!final_socket) + if (IsValid()) return error; SocketAddress bind_addr; // Only bind to the loopback address if we are expecting a connection from // localhost to avoid any firewall issues. - const bool bind_addr_success = (host_str == "127.0.0.1" || host_str == "localhost") - ? bind_addr.SetToLocalhost(kDomain, port) - : bind_addr.SetToAnyAddress(kDomain, port); + const bool bind_addr_success = + (host_str == "127.0.0.1" || host_str == "localhost") + ? bind_addr.SetToLocalhost(kDomain, port) + : bind_addr.SetToAnyAddress(kDomain, port); if (!bind_addr_success) { error.SetErrorString("Failed to get hostspec to bind for"); @@ -125,13 +115,37 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, bind_addr.SetPort(0); // Let the source port # be determined dynamically - err = ::bind(final_socket->GetNativeSocket(), bind_addr, bind_addr.GetLength()); - - struct sockaddr_in source_info; - socklen_t address_len = sizeof (struct sockaddr_in); - err = ::getsockname(final_socket->GetNativeSocket(), (struct sockaddr *) &source_info, &address_len); + err = ::bind(m_socket, bind_addr, bind_addr.GetLength()); - socket = final_socket.release(); error.Clear(); return error; } + +Error UDPSocket::Listen(llvm::StringRef name, int backlog) { + return Error("%s", g_not_supported_error); +} + +Error UDPSocket::Accept(Socket *&socket) { + return Error("%s", g_not_supported_error); +} + +Error UDPSocket::CreateSocket() { + Error error; + if (IsValid()) + error = Close(); + if (error.Fail()) + return error; + m_socket = + Socket::CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); + return error; +} + +Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, + Socket *&socket) { + std::unique_ptr<UDPSocket> final_socket( + new UDPSocket(true, child_processes_inherit)); + Error error = final_socket->Connect(name); + if (!error.Fail()) + socket = final_socket.release(); + return error; +} diff --git a/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index a3ac36558e32..befc847d8a86 100644 --- a/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -218,7 +218,7 @@ ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path, // assume we don't own it. std::unique_ptr<TCPSocket> tcp_socket; - tcp_socket.reset(new TCPSocket(fd, false)); + tcp_socket.reset(new TCPSocket(fd, false, false)); // Try and get a socket option from this file descriptor to // see if this is a socket and set m_is_socket accordingly. int resuse; @@ -720,7 +720,7 @@ ConnectionFileDescriptor::SocketListenAndAccept(llvm::StringRef s, listening_socket_up.reset(socket); socket = nullptr; - error = listening_socket_up->Accept(s, m_child_processes_inherit, socket); + error = listening_socket_up->Accept(socket); listening_socket_up.reset(); if (error_ptr) *error_ptr = error; diff --git a/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp b/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp index 538979df2b6b..33c71268c2e3 100644 --- a/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp +++ b/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp @@ -56,19 +56,21 @@ bool SetSockAddr(llvm::StringRef name, const size_t name_offset, return true; } -} - -DomainSocket::DomainSocket(NativeSocket socket) - : Socket(socket, ProtocolUnixDomain, true) {} +} // namespace -DomainSocket::DomainSocket(bool child_processes_inherit, Error &error) - : DomainSocket( - CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {} +DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit) + : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {} DomainSocket::DomainSocket(SocketProtocol protocol, - bool child_processes_inherit, Error &error) - : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error), - protocol, true) {} + bool child_processes_inherit) + : Socket(protocol, true, child_processes_inherit) {} + +DomainSocket::DomainSocket(NativeSocket socket, + const DomainSocket &listen_socket) + : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd, + listen_socket.m_child_processes_inherit) { + m_socket = socket; +} Error DomainSocket::Connect(llvm::StringRef name) { sockaddr_un saddr_un; @@ -77,6 +79,9 @@ Error DomainSocket::Connect(llvm::StringRef name) { return Error("Failed to set socket address"); Error error; + m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); + if (error.Fail()) + return error; if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) < 0) SetLastError(error); @@ -93,6 +98,9 @@ Error DomainSocket::Listen(llvm::StringRef name, int backlog) { DeleteSocketFile(name); Error error; + m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); + if (error.Fail()) + return error; if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == 0) if (::listen(GetNativeSocket(), backlog) == 0) @@ -102,13 +110,12 @@ Error DomainSocket::Listen(llvm::StringRef name, int backlog) { return error; } -Error DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { +Error DomainSocket::Accept(Socket *&socket) { Error error; auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, - child_processes_inherit, error); + m_child_processes_inherit, error); if (error.Success()) - socket = new DomainSocket(conn_fd); + socket = new DomainSocket(conn_fd, *this); return error; } diff --git a/contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp deleted file mode 100644 index a73187e730f0..000000000000 --- a/contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp +++ /dev/null @@ -1,182 +0,0 @@ -//===-- MainLoopPosix.cpp ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/posix/MainLoopPosix.h" -#include "lldb/Utility/Error.h" -#include <algorithm> -#include <cassert> -#include <cerrno> -#include <csignal> -#include <sys/select.h> -#include <vector> - -using namespace lldb; -using namespace lldb_private; - -static sig_atomic_t g_signal_flags[NSIG]; - -static void SignalHandler(int signo, siginfo_t *info, void *) { - assert(signo < NSIG); - g_signal_flags[signo] = 1; -} - -MainLoopPosix::~MainLoopPosix() { - assert(m_read_fds.size() == 0); - assert(m_signals.size() == 0); -} - -MainLoopPosix::ReadHandleUP -MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, - const Callback &callback, Error &error) { - if (!object_sp || !object_sp->IsValid()) { - error.SetErrorString("IO object is not valid."); - return nullptr; - } - - const bool inserted = - m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second; - if (!inserted) { - error.SetErrorStringWithFormat("File descriptor %d already monitored.", - object_sp->GetWaitableHandle()); - return nullptr; - } - - return CreateReadHandle(object_sp); -} - -// We shall block the signal, then install the signal handler. The signal will -// be unblocked in -// the Run() function to check for signal delivery. -MainLoopPosix::SignalHandleUP -MainLoopPosix::RegisterSignal(int signo, const Callback &callback, - Error &error) { - if (m_signals.find(signo) != m_signals.end()) { - error.SetErrorStringWithFormat("Signal %d already monitored.", signo); - return nullptr; - } - - SignalInfo info; - info.callback = callback; - struct sigaction new_action; - new_action.sa_sigaction = &SignalHandler; - new_action.sa_flags = SA_SIGINFO; - sigemptyset(&new_action.sa_mask); - sigaddset(&new_action.sa_mask, signo); - - sigset_t old_set; - if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) { - error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", - ret); - return nullptr; - } - - info.was_blocked = sigismember(&old_set, signo); - if (sigaction(signo, &new_action, &info.old_action) == -1) { - error.SetErrorToErrno(); - if (!info.was_blocked) - pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr); - return nullptr; - } - - m_signals.insert({signo, info}); - g_signal_flags[signo] = 0; - - return SignalHandleUP(new SignalHandle(*this, signo)); -} - -void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) { - bool erased = m_read_fds.erase(handle); - UNUSED_IF_ASSERT_DISABLED(erased); - assert(erased); -} - -void MainLoopPosix::UnregisterSignal(int signo) { - // We undo the actions of RegisterSignal on a best-effort basis. - auto it = m_signals.find(signo); - assert(it != m_signals.end()); - - sigaction(signo, &it->second.old_action, nullptr); - - sigset_t set; - sigemptyset(&set); - sigaddset(&set, signo); - pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, - nullptr); - - m_signals.erase(it); -} - -Error MainLoopPosix::Run() { - std::vector<int> signals; - sigset_t sigmask; - std::vector<int> read_fds; - fd_set read_fd_set; - m_terminate_request = false; - - // run until termination or until we run out of things to listen to - while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) { - // To avoid problems with callbacks changing the things we're supposed to - // listen to, we - // will store the *real* list of events separately. - signals.clear(); - read_fds.clear(); - FD_ZERO(&read_fd_set); - int nfds = 0; - - if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask)) - return Error("pthread_sigmask failed with error %d\n", ret); - - for (const auto &fd : m_read_fds) { - read_fds.push_back(fd.first); - FD_SET(fd.first, &read_fd_set); - nfds = std::max(nfds, fd.first + 1); - } - - for (const auto &sig : m_signals) { - signals.push_back(sig.first); - sigdelset(&sigmask, sig.first); - } - - if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == - -1 && - errno != EINTR) - return Error(errno, eErrorTypePOSIX); - - for (int sig : signals) { - if (g_signal_flags[sig] == 0) - continue; // No signal - g_signal_flags[sig] = 0; - - auto it = m_signals.find(sig); - if (it == m_signals.end()) - continue; // Signal must have gotten unregistered in the meantime - - it->second.callback(*this); // Do the work - - if (m_terminate_request) - return Error(); - } - - for (int fd : read_fds) { - if (!FD_ISSET(fd, &read_fd_set)) - continue; // Not ready - - auto it = m_read_fds.find(fd); - if (it == m_read_fds.end()) - continue; // File descriptor must have gotten unregistered in the - // meantime - - it->second(*this); // Do the work - - if (m_terminate_request) - return Error(); - } - } - return Error(); -} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp index de27f7be30d3..8703bc97f06e 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp @@ -645,8 +645,8 @@ void CommandInterpreter::LoadCommandDictionary() { "gdb-remote [<hostname>:]<portnum>", 2, 0, false)); if (connect_gdb_remote_cmd_ap.get()) { if (connect_gdb_remote_cmd_ap->AddRegexCommand( - "^([^:]+:[[:digit:]]+)$", - "process connect --plugin gdb-remote connect://%1") && + "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$", + "process connect --plugin gdb-remote connect://%1:%2") && connect_gdb_remote_cmd_ap->AddRegexCommand( "^([[:digit:]]+)$", "process connect --plugin gdb-remote connect://localhost:%1")) { diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp index d3899677ba53..2bff0bdcec37 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp @@ -37,7 +37,7 @@ void OptionValueEnumeration::DumpValue(const ExecutionContext *exe_ctx, const size_t count = m_enumerations.GetSize(); for (size_t i = 0; i < count; ++i) { if (m_enumerations.GetValueAtIndexUnchecked(i).value == m_current_value) { - strm.PutCString(m_enumerations.GetCStringAtIndex(i)); + strm.PutCString(m_enumerations.GetCStringAtIndex(i).GetStringRef()); return; } } @@ -58,8 +58,7 @@ Error OptionValueEnumeration::SetValueFromString(llvm::StringRef value, case eVarSetOperationAssign: { ConstString const_enumerator_name(value.trim()); const EnumerationMapEntry *enumerator_entry = - m_enumerations.FindFirstValueForName( - const_enumerator_name.GetStringRef()); + m_enumerations.FindFirstValueForName(const_enumerator_name); if (enumerator_entry) { m_current_value = enumerator_entry->value.value; NotifyValueChanged(); @@ -69,10 +68,10 @@ Error OptionValueEnumeration::SetValueFromString(llvm::StringRef value, const size_t count = m_enumerations.GetSize(); if (count) { error_strm.Printf(", valid values are: %s", - m_enumerations.GetCStringAtIndex(0).str().c_str()); + m_enumerations.GetCStringAtIndex(0).GetCString()); for (size_t i = 1; i < count; ++i) { error_strm.Printf(", %s", - m_enumerations.GetCStringAtIndex(i).str().c_str()); + m_enumerations.GetCStringAtIndex(i).GetCString()); } } error.SetErrorString(error_strm.GetString()); @@ -99,7 +98,7 @@ void OptionValueEnumeration::SetEnumerations( ConstString const_enumerator_name(enumerators[i].string_value); EnumeratorInfo enumerator_info = {enumerators[i].value, enumerators[i].usage}; - m_enumerations.Append(const_enumerator_name.GetStringRef(), + m_enumerations.Append(const_enumerator_name, enumerator_info); } m_enumerations.Sort(); @@ -119,14 +118,14 @@ size_t OptionValueEnumeration::AutoComplete( const uint32_t num_enumerators = m_enumerations.GetSize(); if (!s.empty()) { for (size_t i = 0; i < num_enumerators; ++i) { - llvm::StringRef name = m_enumerations.GetCStringAtIndex(i); + llvm::StringRef name = m_enumerations.GetCStringAtIndex(i).GetStringRef(); if (name.startswith(s)) matches.AppendString(name); } } else { // only suggest "true" or "false" by default for (size_t i = 0; i < num_enumerators; ++i) - matches.AppendString(m_enumerations.GetCStringAtIndex(i)); + matches.AppendString(m_enumerations.GetCStringAtIndex(i).GetStringRef()); } return matches.GetSize(); } diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp index 10370c2f667f..732769f6e6df 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp @@ -59,7 +59,7 @@ void OptionValueProperties::Initialize(const PropertyDefinition *defs) { for (size_t i = 0; defs[i].name; ++i) { Property property(defs[i]); assert(property.IsValid()); - m_name_to_index.Append(property.GetName(), m_properties.size()); + m_name_to_index.Append(ConstString(property.GetName()), m_properties.size()); property.GetValue()->SetParent(shared_from_this()); m_properties.push_back(property); } @@ -78,7 +78,7 @@ void OptionValueProperties::AppendProperty(const ConstString &name, bool is_global, const OptionValueSP &value_sp) { Property property(name, desc, is_global, value_sp); - m_name_to_index.Append(name.GetStringRef(), m_properties.size()); + m_name_to_index.Append(name, m_properties.size()); m_properties.push_back(property); value_sp->SetParent(shared_from_this()); m_name_to_index.Sort(); @@ -108,7 +108,7 @@ OptionValueProperties::GetValueForKey(const ExecutionContext *exe_ctx, const ConstString &key, bool will_modify) const { lldb::OptionValueSP value_sp; - size_t idx = m_name_to_index.Find(key.GetStringRef(), SIZE_MAX); + size_t idx = m_name_to_index.Find(key, SIZE_MAX); if (idx < m_properties.size()) value_sp = GetPropertyAtIndex(exe_ctx, will_modify, idx)->GetValue(); return value_sp; @@ -218,7 +218,7 @@ Error OptionValueProperties::SetSubValue(const ExecutionContext *exe_ctx, uint32_t OptionValueProperties::GetPropertyIndex(const ConstString &name) const { - return m_name_to_index.Find(name.GetStringRef(), SIZE_MAX); + return m_name_to_index.Find(name, SIZE_MAX); } const Property * @@ -227,7 +227,7 @@ OptionValueProperties::GetProperty(const ExecutionContext *exe_ctx, const ConstString &name) const { return GetPropertyAtIndex( exe_ctx, will_modify, - m_name_to_index.Find(name.GetStringRef(), SIZE_MAX)); + m_name_to_index.Find(name, SIZE_MAX)); } const Property *OptionValueProperties::GetPropertyAtIndex( diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 3c3a2cd9c3fc..7622791778ba 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -348,7 +348,7 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { GetCompleteObjCInterface(original_iface_decl); if (complete_iface_decl && (complete_iface_decl != original_iface_decl)) { - m_ast_importer_sp->SetDeclOrigin(interface_decl, original_iface_decl); + m_ast_importer_sp->SetDeclOrigin(interface_decl, complete_iface_decl); } } } @@ -472,7 +472,7 @@ void ClangASTSource::FindExternalLexicalDecls( original_decl = complete_iface_decl; original_ctx = &complete_iface_decl->getASTContext(); - m_ast_importer_sp->SetDeclOrigin(context_decl, original_iface_decl); + m_ast_importer_sp->SetDeclOrigin(context_decl, complete_iface_decl); } } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index fe42a5ed9214..1ae9418e4d9c 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -271,144 +271,6 @@ bool CPlusPlusLanguage::ExtractContextAndIdentifier( return false; } -class CPPRuntimeEquivalents { -public: - CPPRuntimeEquivalents() { - m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, " - "std::allocator<char> >") - .GetStringRef(), - ConstString("basic_string<char>")); - - // these two (with a prefixed std::) occur when c++stdlib string class - // occurs as a template argument in some STL container - m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, " - "std::allocator<char> >") - .GetStringRef(), - ConstString("std::basic_string<char>")); - - m_impl.Sort(); - } - - void Add(ConstString &type_name, ConstString &type_equivalent) { - m_impl.Insert(type_name.GetStringRef(), type_equivalent); - } - - uint32_t FindExactMatches(ConstString &type_name, - std::vector<ConstString> &equivalents) { - uint32_t count = 0; - - for (ImplData match = - m_impl.FindFirstValueForName(type_name.GetStringRef()); - match != nullptr; match = m_impl.FindNextValueForName(match)) { - equivalents.push_back(match->value); - count++; - } - - return count; - } - - // partial matches can occur when a name with equivalents is a template - // argument. - // e.g. we may have "class Foo" be a match for "struct Bar". if we have a - // typename - // such as "class Templatized<class Foo, Anything>" we want this to be - // replaced with - // "class Templatized<struct Bar, Anything>". Since partial matching is time - // consuming - // once we get a partial match, we add it to the exact matches list for faster - // retrieval - uint32_t FindPartialMatches(ConstString &type_name, - std::vector<ConstString> &equivalents) { - uint32_t count = 0; - - llvm::StringRef type_name_cstr = type_name.GetStringRef(); - - size_t items_count = m_impl.GetSize(); - - for (size_t item = 0; item < items_count; item++) { - llvm::StringRef key_cstr = m_impl.GetCStringAtIndex(item); - if (type_name_cstr.contains(key_cstr)) { - count += AppendReplacements(type_name_cstr, key_cstr, equivalents); - } - } - - return count; - } - -private: - std::string &replace(std::string &target, std::string &pattern, - std::string &with) { - size_t pos; - size_t pattern_len = pattern.size(); - - while ((pos = target.find(pattern)) != std::string::npos) - target.replace(pos, pattern_len, with); - - return target; - } - - uint32_t AppendReplacements(llvm::StringRef original, - llvm::StringRef matching_key, - std::vector<ConstString> &equivalents) { - std::string matching_key_str(matching_key); - ConstString original_const(original); - - uint32_t count = 0; - - for (ImplData match = m_impl.FindFirstValueForName(matching_key); - match != nullptr; match = m_impl.FindNextValueForName(match)) { - std::string target(original); - std::string equiv_class(match->value.AsCString()); - - replace(target, matching_key_str, equiv_class); - - ConstString target_const(target.c_str()); - -// you will most probably want to leave this off since it might make this map -// grow indefinitely -#ifdef ENABLE_CPP_EQUIVALENTS_MAP_TO_GROW - Add(original_const, target_const); -#endif - equivalents.push_back(target_const); - - count++; - } - - return count; - } - - typedef UniqueCStringMap<ConstString> Impl; - typedef const Impl::Entry *ImplData; - Impl m_impl; -}; - -static CPPRuntimeEquivalents &GetEquivalentsMap() { - static CPPRuntimeEquivalents g_equivalents_map; - return g_equivalents_map; -} - -uint32_t -CPlusPlusLanguage::FindEquivalentNames(ConstString type_name, - std::vector<ConstString> &equivalents) { - uint32_t count = GetEquivalentsMap().FindExactMatches(type_name, equivalents); - - bool might_have_partials = - (count == 0) // if we have a full name match just use it - && (strchr(type_name.AsCString(), '<') != - nullptr // we should only have partial matches when templates are - // involved, check that we have - && strchr(type_name.AsCString(), '>') != nullptr); // angle brackets - // in the type_name - // before trying to - // scan for partial - // matches - - if (might_have_partials) - count = GetEquivalentsMap().FindPartialMatches(type_name, equivalents); - - return count; -} - /// Given a mangled function `mangled`, replace all the primitive function type /// arguments of `search` with type `replace`. static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled, diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h index 056cced2808a..7380ef321305 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -119,18 +119,6 @@ public: llvm::StringRef &context, llvm::StringRef &identifier); - // in some cases, compilers will output different names for one same type. - // when that happens, it might be impossible - // to construct SBType objects for a valid type, because the name that is - // available is not the same as the name that - // can be used as a search key in FindTypes(). the equivalents map here is - // meant to return possible alternative names - // for a type through which a search can be conducted. Currently, this is only - // enabled for C++ but can be extended - // to ObjC or other languages if necessary - static uint32_t FindEquivalentNames(ConstString type_name, - std::vector<ConstString> &equivalents); - // Given a mangled function name, calculates some alternative manglings since // the compiler mangling may not line up with the symbol we are expecting static uint32_t diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 50d4510ec5f9..293d64075921 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -219,6 +219,7 @@ size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: CalculateNumChildren() { static ConstString g___pair3_("__pair3_"); static ConstString g___first_("__first_"); + static ConstString g___value_("__value_"); if (m_count != UINT32_MAX) return m_count; @@ -227,7 +228,22 @@ size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: ValueObjectSP m_item(m_tree->GetChildMemberWithName(g___pair3_, true)); if (!m_item) return 0; - m_item = m_item->GetChildMemberWithName(g___first_, true); + + switch (m_item->GetCompilerType().GetNumDirectBaseClasses()) { + case 1: + // Assume a pre llvm r300140 __compressed_pair implementation: + m_item = m_item->GetChildMemberWithName(g___first_, true); + break; + case 2: { + // Assume a post llvm r300140 __compressed_pair implementation: + ValueObjectSP first_elem_parent = m_item->GetChildAtIndex(0, true); + m_item = first_elem_parent->GetChildMemberWithName(g___value_, true); + break; + } + default: + return false; + } + if (!m_item) return 0; m_count = m_item->GetValueAsUnsigned(0); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index c3566b7c6bfb..526bae6900f5 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -94,9 +94,30 @@ lldb::ValueObjectSP lldb_private::formatters:: node_sp->GetChildMemberWithName(ConstString("__hash_"), true); if (!hash_sp || !value_sp) { if (!m_element_type) { - auto first_sp = m_backend.GetChildAtNamePath({ConstString("__table_"), - ConstString("__p1_"), - ConstString("__first_")}); + auto p1_sp = m_backend.GetChildAtNamePath({ConstString("__table_"), + ConstString("__p1_")}); + if (!p1_sp) + return nullptr; + + ValueObjectSP first_sp = nullptr; + switch (p1_sp->GetCompilerType().GetNumDirectBaseClasses()) { + case 1: + // Assume a pre llvm r300140 __compressed_pair implementation: + first_sp = p1_sp->GetChildMemberWithName(ConstString("__first_"), + true); + break; + case 2: { + // Assume a post llvm r300140 __compressed_pair implementation: + ValueObjectSP first_elem_parent_sp = + p1_sp->GetChildAtIndex(0, true); + first_sp = p1_sp->GetChildMemberWithName(ConstString("__value_"), + true); + break; + } + default: + return nullptr; + } + if (!first_sp) return nullptr; m_element_type = first_sp->GetCompilerType(); @@ -152,22 +173,39 @@ bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: m_backend.GetChildMemberWithName(ConstString("__table_"), true); if (!table_sp) return false; - ValueObjectSP num_elements_sp = table_sp->GetChildAtNamePath( - {ConstString("__p2_"), ConstString("__first_")}); + + ValueObjectSP p2_sp = table_sp->GetChildMemberWithName( + ConstString("__p2_"), true); + ValueObjectSP num_elements_sp = nullptr; + llvm::SmallVector<ConstString, 3> next_path; + switch (p2_sp->GetCompilerType().GetNumDirectBaseClasses()) { + case 1: + // Assume a pre llvm r300140 __compressed_pair implementation: + num_elements_sp = p2_sp->GetChildMemberWithName( + ConstString("__first_"), true); + next_path.append({ConstString("__p1_"), ConstString("__first_"), + ConstString("__next_")}); + break; + case 2: { + // Assume a post llvm r300140 __compressed_pair implementation: + ValueObjectSP first_elem_parent = p2_sp->GetChildAtIndex(0, true); + num_elements_sp = first_elem_parent->GetChildMemberWithName( + ConstString("__value_"), true); + next_path.append({ConstString("__p1_"), ConstString("__value_"), + ConstString("__next_")}); + break; + } + default: + return false; + } + if (!num_elements_sp) return false; m_num_elements = num_elements_sp->GetValueAsUnsigned(0); - m_tree = - table_sp - ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"), - ConstString("__next_")}) - .get(); + m_tree = table_sp->GetChildAtNamePath(next_path).get(); if (m_num_elements > 0) m_next_element = - table_sp - ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"), - ConstString("__next_")}) - .get(); + table_sp->GetChildAtNamePath(next_path).get(); return false; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp index 2843201e2ed9..96d7e51deba4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp @@ -127,8 +127,25 @@ bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() { m_backend.GetChildMemberWithName(ConstString("__end_cap_"), true)); if (!data_type_finder_sp) return false; - data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName( + + switch (data_type_finder_sp->GetCompilerType().GetNumDirectBaseClasses()) { + case 1: + // Assume a pre llvm r300140 __compressed_pair implementation: + data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName( ConstString("__first_"), true); + break; + case 2: { + // Assume a post llvm r300140 __compressed_pair implementation: + ValueObjectSP first_elem_parent_sp = + data_type_finder_sp->GetChildAtIndex(0, true); + data_type_finder_sp = first_elem_parent_sp->GetChildMemberWithName( + ConstString("__value_"), true); + break; + } + default: + return false; + } + if (!data_type_finder_sp) return false; m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType(); diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index 07b4ae5e0add..e99fd74a352f 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -355,9 +355,14 @@ public: } } + clang::IdentifierInfo **identifier_infos = selector_components.data(); + if (!identifier_infos) { + return NULL; + } + clang::Selector sel = ast_ctx.Selectors.getSelector( is_zero_argument ? 0 : selector_components.size(), - selector_components.data()); + identifier_infos); clang::QualType ret_type = ClangUtil::GetQualType(type_realizer_sp->RealizeType( diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index b74da3300170..928157516808 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -158,7 +158,7 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() { size_t obj_idx = m_objects.size(); m_objects.push_back(obj); // Insert all of the C strings out of order for now... - m_object_name_to_index_map.Append(obj.ar_name.GetStringRef(), obj_idx); + m_object_name_to_index_map.Append(obj.ar_name, obj_idx); offset += obj.ar_file_size; obj.Clear(); } while (data.ValidOffset(offset)); @@ -174,8 +174,7 @@ ObjectContainerBSDArchive::Archive::FindObject( const ConstString &object_name, const llvm::sys::TimePoint<> &object_mod_time) { const ObjectNameToIndexMap::Entry *match = - m_object_name_to_index_map.FindFirstValueForName( - object_name.GetStringRef()); + m_object_name_to_index_map.FindFirstValueForName(object_name); if (match) { if (object_mod_time != llvm::sys::TimePoint<>()) { const uint64_t object_date = llvm::sys::toTimeT(object_mod_time); diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 6e2001b21630..0720cca27341 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1808,10 +1808,10 @@ DataExtractor ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id) { segment_header->p_filesz); } -std::string +llvm::StringRef ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { size_t pos = symbol_name.find('@'); - return symbol_name.substr(0, pos).str(); + return symbol_name.substr(0, pos); } //---------------------------------------------------------------------- @@ -2418,7 +2418,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, .emplace(sect_name.GetCString(), module_section_list->FindSectionByName(sect_name)) .first; - if (section_it->second && section_it->second->GetFileSize()) + if (section_it->second) symbol_section_sp = section_it->second; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 98bd9abb1932..9b2d58b7be82 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -152,7 +152,7 @@ public: // Returns segment data for the given index. lldb_private::DataExtractor GetSegmentDataByIndex(lldb::user_id_t id); - std::string + llvm::StringRef StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; private: diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 1d8b759d2fa8..8aec35d09ce5 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -3900,10 +3900,9 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( if (src_name) { ConstString src_const_name(src_name); if (src_die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0)) - src_name_to_die_artificial.Append(src_const_name.GetStringRef(), - src_die); + src_name_to_die_artificial.Append(src_const_name, src_die); else - src_name_to_die.Append(src_const_name.GetStringRef(), src_die); + src_name_to_die.Append(src_const_name, src_die); } } } @@ -3920,10 +3919,9 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( if (dst_name) { ConstString dst_const_name(dst_name); if (dst_die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0)) - dst_name_to_die_artificial.Append(dst_const_name.GetStringRef(), - dst_die); + dst_name_to_die_artificial.Append(dst_const_name, dst_die); else - dst_name_to_die.Append(dst_const_name.GetStringRef(), dst_die); + dst_name_to_die.Append(dst_const_name, dst_die); } } } @@ -4036,7 +4034,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( src_name_to_die.Sort(); for (idx = 0; idx < dst_size; ++idx) { - llvm::StringRef dst_name = dst_name_to_die.GetCStringAtIndex(idx); + ConstString dst_name = dst_name_to_die.GetCStringAtIndex(idx); dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx); src_die = src_name_to_die.Find(dst_name, DWARFDIE()); @@ -4091,7 +4089,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( dst_name_to_die_artificial.Sort(); for (idx = 0; idx < src_size_artificial; ++idx) { - llvm::StringRef src_name_artificial = + ConstString src_name_artificial = src_name_to_die_artificial.GetCStringAtIndex(idx); src_die = src_name_to_die_artificial.GetValueAtIndexUnchecked(idx); dst_die = @@ -4135,13 +4133,13 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( if (dst_size_artificial) { for (idx = 0; idx < dst_size_artificial; ++idx) { - llvm::StringRef dst_name_artificial = + ConstString dst_name_artificial = dst_name_to_die_artificial.GetCStringAtIndex(idx); dst_die = dst_name_to_die_artificial.GetValueAtIndexUnchecked(idx); if (log) log->Printf("warning: need to create artificial method for 0x%8.8x for " "method '%s'", - dst_die.GetOffset(), dst_name_artificial.str().c_str()); + dst_die.GetOffset(), dst_name_artificial.GetCString()); failures.Append(dst_die); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp index f5f979caa38e..c97680eda0fe 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp @@ -28,11 +28,11 @@ void NameToDIE::Finalize() { } void NameToDIE::Insert(const ConstString &name, const DIERef &die_ref) { - m_map.Append(name.GetStringRef(), die_ref); + m_map.Append(name, die_ref); } size_t NameToDIE::Find(const ConstString &name, DIEArray &info_array) const { - return m_map.GetValues(name.GetStringRef(), info_array); + return m_map.GetValues(name, info_array); } size_t NameToDIE::Find(const RegularExpression ®ex, @@ -55,15 +55,15 @@ size_t NameToDIE::FindAllEntriesForCompileUnit(dw_offset_t cu_offset, void NameToDIE::Dump(Stream *s) { const uint32_t size = m_map.GetSize(); for (uint32_t i = 0; i < size; ++i) { - llvm::StringRef cstr = m_map.GetCStringAtIndex(i); + ConstString cstr = m_map.GetCStringAtIndex(i); const DIERef &die_ref = m_map.GetValueAtIndexUnchecked(i); - s->Printf("%p: {0x%8.8x/0x%8.8x} \"%s\"\n", (const void *)cstr.data(), - die_ref.cu_offset, die_ref.die_offset, cstr.str().c_str()); + s->Printf("%p: {0x%8.8x/0x%8.8x} \"%s\"\n", (const void *)cstr.GetCString(), + die_ref.cu_offset, die_ref.die_offset, cstr.GetCString()); } } void NameToDIE::ForEach( - std::function<bool(llvm::StringRef name, const DIERef &die_ref)> const + std::function<bool(ConstString name, const DIERef &die_ref)> const &callback) const { const uint32_t size = m_map.GetSize(); for (uint32_t i = 0; i < size; ++i) { diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h index e3fe321338a2..bba44fda3c04 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h +++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h @@ -43,7 +43,8 @@ public: DIEArray &info_array) const; void - ForEach(std::function<bool(llvm::StringRef name, const DIERef &die_ref)> const + ForEach(std::function<bool(lldb_private::ConstString name, + const DIERef &die_ref)> const &callback) const; protected: diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 973b5ef9fb46..8c2fc3d3aa42 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1917,6 +1917,12 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, return sc_list.GetSize() - prev_size; } +void SymbolFileDWARF::PreloadSymbols() { + std::lock_guard<std::recursive_mutex> guard( + GetObjectFile()->GetModule()->GetMutex()); + Index(); +} + void SymbolFileDWARF::Index() { if (m_indexed) return; diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 14b29fa44fa3..9b1eb1d76fea 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -226,6 +226,8 @@ public: const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx) override; + void PreloadSymbols() override; + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp b/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp index d4c303111343..ac1bbb53cdf8 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp @@ -378,10 +378,9 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { // Set some properties which depend solely on the input kind; it would be nice // to move these to the language standard, and have the driver resolve the // input kind + language standard. - if (IK == IK_Asm) { + if (IK.getLanguage() == InputKind::Asm) { Opts.AsmPreprocessor = 1; - } else if (IK == IK_ObjC || IK == IK_ObjCXX || IK == IK_PreprocessedObjC || - IK == IK_PreprocessedObjCXX) { + } else if (IK.isObjectiveC()) { Opts.ObjC1 = Opts.ObjC2 = 1; } @@ -389,30 +388,24 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { if (LangStd == LangStandard::lang_unspecified) { // Based on the base language, pick one. - switch (IK) { - case IK_None: - case IK_AST: - case IK_LLVM_IR: - case IK_RenderScript: + switch (IK.getLanguage()) { + case InputKind::Unknown: + case InputKind::LLVM_IR: + case InputKind::RenderScript: llvm_unreachable("Invalid input kind!"); - case IK_OpenCL: - LangStd = LangStandard::lang_opencl; + case InputKind::OpenCL: + LangStd = LangStandard::lang_opencl10; break; - case IK_CUDA: - case IK_PreprocessedCuda: + case InputKind::CUDA: LangStd = LangStandard::lang_cuda; break; - case IK_Asm: - case IK_C: - case IK_PreprocessedC: - case IK_ObjC: - case IK_PreprocessedObjC: + case InputKind::Asm: + case InputKind::C: + case InputKind::ObjC: LangStd = LangStandard::lang_gnu99; break; - case IK_CXX: - case IK_PreprocessedCXX: - case IK_ObjCXX: - case IK_PreprocessedObjCXX: + case InputKind::CXX: + case InputKind::ObjCXX: LangStd = LangStandard::lang_gnucxx98; break; } @@ -432,7 +425,7 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { Opts.WChar = true; // OpenCL has some additional defaults. - if (LangStd == LangStandard::lang_opencl) { + if (LangStd == LangStandard::lang_opencl10) { Opts.OpenCL = 1; Opts.AltiVec = 1; Opts.CXXOperatorNames = 1; @@ -784,8 +777,8 @@ IdentifierTable *ClangASTContext::getIdentifierTable() { LangOptions *ClangASTContext::getLanguageOptions() { if (m_language_options_ap.get() == nullptr) { m_language_options_ap.reset(new LangOptions()); - ParseLangArgs(*m_language_options_ap, IK_ObjCXX, GetTargetTriple()); - // InitializeLangOptions(*m_language_options_ap, IK_ObjCXX); + ParseLangArgs(*m_language_options_ap, InputKind::ObjCXX, GetTargetTriple()); + // InitializeLangOptions(*m_language_options_ap, InputKind::ObjCXX); } return m_language_options_ap.get(); } @@ -961,75 +954,60 @@ ClangASTContext::GetBasicTypeEnumeration(const ConstString &name) { static llvm::once_flag g_once_flag; llvm::call_once(g_once_flag, []() { // "void" - g_type_map.Append(ConstString("void").GetStringRef(), eBasicTypeVoid); + g_type_map.Append(ConstString("void"), eBasicTypeVoid); // "char" - g_type_map.Append(ConstString("char").GetStringRef(), eBasicTypeChar); - g_type_map.Append(ConstString("signed char").GetStringRef(), - eBasicTypeSignedChar); - g_type_map.Append(ConstString("unsigned char").GetStringRef(), - eBasicTypeUnsignedChar); - g_type_map.Append(ConstString("wchar_t").GetStringRef(), eBasicTypeWChar); - g_type_map.Append(ConstString("signed wchar_t").GetStringRef(), - eBasicTypeSignedWChar); - g_type_map.Append(ConstString("unsigned wchar_t").GetStringRef(), + g_type_map.Append(ConstString("char"), eBasicTypeChar); + g_type_map.Append(ConstString("signed char"), eBasicTypeSignedChar); + g_type_map.Append(ConstString("unsigned char"), eBasicTypeUnsignedChar); + g_type_map.Append(ConstString("wchar_t"), eBasicTypeWChar); + g_type_map.Append(ConstString("signed wchar_t"), eBasicTypeSignedWChar); + g_type_map.Append(ConstString("unsigned wchar_t"), eBasicTypeUnsignedWChar); // "short" - g_type_map.Append(ConstString("short").GetStringRef(), eBasicTypeShort); - g_type_map.Append(ConstString("short int").GetStringRef(), - eBasicTypeShort); - g_type_map.Append(ConstString("unsigned short").GetStringRef(), - eBasicTypeUnsignedShort); - g_type_map.Append(ConstString("unsigned short int").GetStringRef(), + g_type_map.Append(ConstString("short"), eBasicTypeShort); + g_type_map.Append(ConstString("short int"), eBasicTypeShort); + g_type_map.Append(ConstString("unsigned short"), eBasicTypeUnsignedShort); + g_type_map.Append(ConstString("unsigned short int"), eBasicTypeUnsignedShort); // "int" - g_type_map.Append(ConstString("int").GetStringRef(), eBasicTypeInt); - g_type_map.Append(ConstString("signed int").GetStringRef(), - eBasicTypeInt); - g_type_map.Append(ConstString("unsigned int").GetStringRef(), - eBasicTypeUnsignedInt); - g_type_map.Append(ConstString("unsigned").GetStringRef(), - eBasicTypeUnsignedInt); + g_type_map.Append(ConstString("int"), eBasicTypeInt); + g_type_map.Append(ConstString("signed int"), eBasicTypeInt); + g_type_map.Append(ConstString("unsigned int"), eBasicTypeUnsignedInt); + g_type_map.Append(ConstString("unsigned"), eBasicTypeUnsignedInt); // "long" - g_type_map.Append(ConstString("long").GetStringRef(), eBasicTypeLong); - g_type_map.Append(ConstString("long int").GetStringRef(), eBasicTypeLong); - g_type_map.Append(ConstString("unsigned long").GetStringRef(), - eBasicTypeUnsignedLong); - g_type_map.Append(ConstString("unsigned long int").GetStringRef(), + g_type_map.Append(ConstString("long"), eBasicTypeLong); + g_type_map.Append(ConstString("long int"), eBasicTypeLong); + g_type_map.Append(ConstString("unsigned long"), eBasicTypeUnsignedLong); + g_type_map.Append(ConstString("unsigned long int"), eBasicTypeUnsignedLong); // "long long" - g_type_map.Append(ConstString("long long").GetStringRef(), - eBasicTypeLongLong); - g_type_map.Append(ConstString("long long int").GetStringRef(), - eBasicTypeLongLong); - g_type_map.Append(ConstString("unsigned long long").GetStringRef(), + g_type_map.Append(ConstString("long long"), eBasicTypeLongLong); + g_type_map.Append(ConstString("long long int"), eBasicTypeLongLong); + g_type_map.Append(ConstString("unsigned long long"), eBasicTypeUnsignedLongLong); - g_type_map.Append(ConstString("unsigned long long int").GetStringRef(), + g_type_map.Append(ConstString("unsigned long long int"), eBasicTypeUnsignedLongLong); // "int128" - g_type_map.Append(ConstString("__int128_t").GetStringRef(), - eBasicTypeInt128); - g_type_map.Append(ConstString("__uint128_t").GetStringRef(), - eBasicTypeUnsignedInt128); + g_type_map.Append(ConstString("__int128_t"), eBasicTypeInt128); + g_type_map.Append(ConstString("__uint128_t"), eBasicTypeUnsignedInt128); // Miscellaneous - g_type_map.Append(ConstString("bool").GetStringRef(), eBasicTypeBool); - g_type_map.Append(ConstString("float").GetStringRef(), eBasicTypeFloat); - g_type_map.Append(ConstString("double").GetStringRef(), eBasicTypeDouble); - g_type_map.Append(ConstString("long double").GetStringRef(), - eBasicTypeLongDouble); - g_type_map.Append(ConstString("id").GetStringRef(), eBasicTypeObjCID); - g_type_map.Append(ConstString("SEL").GetStringRef(), eBasicTypeObjCSel); - g_type_map.Append(ConstString("nullptr").GetStringRef(), - eBasicTypeNullPtr); + g_type_map.Append(ConstString("bool"), eBasicTypeBool); + g_type_map.Append(ConstString("float"), eBasicTypeFloat); + g_type_map.Append(ConstString("double"), eBasicTypeDouble); + g_type_map.Append(ConstString("long double"), eBasicTypeLongDouble); + g_type_map.Append(ConstString("id"), eBasicTypeObjCID); + g_type_map.Append(ConstString("SEL"), eBasicTypeObjCSel); + g_type_map.Append(ConstString("nullptr"), eBasicTypeNullPtr); g_type_map.Sort(); }); - return g_type_map.Find(name.GetStringRef(), eBasicTypeInvalid); + return g_type_map.Find(name, eBasicTypeInvalid); } return eBasicTypeInvalid; } diff --git a/contrib/llvm/tools/lldb/source/Symbol/GoASTContext.cpp b/contrib/llvm/tools/lldb/source/Symbol/GoASTContext.cpp index 5ca173ae113c..6761a605e46b 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/GoASTContext.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/GoASTContext.cpp @@ -598,33 +598,32 @@ GoASTContext::GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) { static llvm::once_flag g_once_flag; llvm::call_once(g_once_flag, []() { // "void" - g_type_map.Append(ConstString("void").GetStringRef(), eBasicTypeVoid); + g_type_map.Append(ConstString("void"), eBasicTypeVoid); // "int" - g_type_map.Append(ConstString("int").GetStringRef(), eBasicTypeInt); - g_type_map.Append(ConstString("uint").GetStringRef(), - eBasicTypeUnsignedInt); + g_type_map.Append(ConstString("int"), eBasicTypeInt); + g_type_map.Append(ConstString("uint"), eBasicTypeUnsignedInt); // Miscellaneous - g_type_map.Append(ConstString("bool").GetStringRef(), eBasicTypeBool); + g_type_map.Append(ConstString("bool"), eBasicTypeBool); // Others. Should these map to C types? - g_type_map.Append(ConstString("byte").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("uint8").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("uint16").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("uint32").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("uint64").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("int8").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("int16").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("int32").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("int64").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("float32").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("float64").GetStringRef(), eBasicTypeOther); - g_type_map.Append(ConstString("uintptr").GetStringRef(), eBasicTypeOther); + g_type_map.Append(ConstString("byte"), eBasicTypeOther); + g_type_map.Append(ConstString("uint8"), eBasicTypeOther); + g_type_map.Append(ConstString("uint16"), eBasicTypeOther); + g_type_map.Append(ConstString("uint32"), eBasicTypeOther); + g_type_map.Append(ConstString("uint64"), eBasicTypeOther); + g_type_map.Append(ConstString("int8"), eBasicTypeOther); + g_type_map.Append(ConstString("int16"), eBasicTypeOther); + g_type_map.Append(ConstString("int32"), eBasicTypeOther); + g_type_map.Append(ConstString("int64"), eBasicTypeOther); + g_type_map.Append(ConstString("float32"), eBasicTypeOther); + g_type_map.Append(ConstString("float64"), eBasicTypeOther); + g_type_map.Append(ConstString("uintptr"), eBasicTypeOther); g_type_map.Sort(); }); - return g_type_map.Find(name.GetStringRef(), eBasicTypeInvalid); + return g_type_map.Find(name, eBasicTypeInvalid); } return eBasicTypeInvalid; } diff --git a/contrib/llvm/tools/lldb/source/Symbol/SymbolFile.cpp b/contrib/llvm/tools/lldb/source/Symbol/SymbolFile.cpp index d7898919f45e..eb20b80f4916 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/SymbolFile.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/SymbolFile.cpp @@ -21,6 +21,10 @@ using namespace lldb_private; +void SymbolFile::PreloadSymbols() { + // No-op for most implementations. +} + SymbolFile *SymbolFile::FindPlugin(ObjectFile *obj_file) { std::unique_ptr<SymbolFile> best_symfile_ap; if (obj_file != nullptr) { diff --git a/contrib/llvm/tools/lldb/source/Symbol/Symtab.cpp b/contrib/llvm/tools/lldb/source/Symbol/Symtab.cpp index 427029802634..e0710aa4e6b9 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/Symtab.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/Symtab.cpp @@ -263,36 +263,35 @@ void Symtab::InitNameIndexes() { continue; const Mangled &mangled = symbol->GetMangled(); - entry.cstring = mangled.GetMangledName().GetStringRef(); - if (!entry.cstring.empty()) { + entry.cstring = mangled.GetMangledName(); + if (entry.cstring) { m_name_to_index.Append(entry); if (symbol->ContainsLinkerAnnotations()) { // If the symbol has linker annotations, also add the version without // the annotations. entry.cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations( - entry.cstring)) - .GetStringRef(); + entry.cstring.GetStringRef())); m_name_to_index.Append(entry); } const SymbolType symbol_type = symbol->GetType(); if (symbol_type == eSymbolTypeCode || symbol_type == eSymbolTypeResolver) { - if (entry.cstring[0] == '_' && entry.cstring[1] == 'Z' && - (entry.cstring[2] != 'T' && // avoid virtual table, VTT structure, - // typeinfo structure, and typeinfo - // name - entry.cstring[2] != 'G' && // avoid guard variables - entry.cstring[2] != 'Z')) // named local entities (if we + llvm::StringRef entry_ref(entry.cstring.GetStringRef()); + if (entry_ref[0] == '_' && entry_ref[1] == 'Z' && + (entry_ref[2] != 'T' && // avoid virtual table, VTT structure, + // typeinfo structure, and typeinfo + // name + entry_ref[2] != 'G' && // avoid guard variables + entry_ref[2] != 'Z')) // named local entities (if we // eventually handle eSymbolTypeData, // we will want this back) { CPlusPlusLanguage::MethodName cxx_method( mangled.GetDemangledName(lldb::eLanguageTypeC_plus_plus)); - entry.cstring = - ConstString(cxx_method.GetBasename()).GetStringRef(); - if (!entry.cstring.empty()) { + entry.cstring = ConstString(cxx_method.GetBasename()); + if (entry.cstring) { // ConstString objects permanently store the string in the pool so // calling // GetCString() on the value gets us a const char * that will @@ -300,16 +299,24 @@ void Symtab::InitNameIndexes() { const char *const_context = ConstString(cxx_method.GetContext()).GetCString(); - if (entry.cstring[0] == '~' || - !cxx_method.GetQualifiers().empty()) { - // The first character of the demangled basename is '~' which - // means we have a class destructor. We can use this information - // to help us know what is a class and what isn't. - if (class_contexts.find(const_context) == class_contexts.end()) - class_contexts.insert(const_context); - m_method_to_index.Append(entry); + if (!const_context || const_context[0] == 0) { + // No context for this function so this has to be a basename + m_basename_to_index.Append(entry); + // If there is no context (no namespaces or class scopes that + // come before the function name) then this also could be a + // fullname. + m_name_to_index.Append(entry); } else { - if (const_context && const_context[0]) { + entry_ref = entry.cstring.GetStringRef(); + if (entry_ref[0] == '~' || + !cxx_method.GetQualifiers().empty()) { + // The first character of the demangled basename is '~' which + // means we have a class destructor. We can use this information + // to help us know what is a class and what isn't. + if (class_contexts.find(const_context) == class_contexts.end()) + class_contexts.insert(const_context); + m_method_to_index.Append(entry); + } else { if (class_contexts.find(const_context) != class_contexts.end()) { // The current decl context is in our "class_contexts" which @@ -326,14 +333,6 @@ void Symtab::InitNameIndexes() { mangled_name_to_index.Append(entry); symbol_contexts[entry.value] = const_context; } - } else { - // No context for this function so this has to be a basename - m_basename_to_index.Append(entry); - // If there is no context (no namespaces or class scopes that - // come before the function name) then this also could be a - // fullname. - if (cxx_method.GetContext().empty()) - m_name_to_index.Append(entry); } } } @@ -341,17 +340,15 @@ void Symtab::InitNameIndexes() { } } - entry.cstring = - mangled.GetDemangledName(symbol->GetLanguage()).GetStringRef(); - if (!entry.cstring.empty()) { + entry.cstring = mangled.GetDemangledName(symbol->GetLanguage()); + if (entry.cstring) { m_name_to_index.Append(entry); if (symbol->ContainsLinkerAnnotations()) { // If the symbol has linker annotations, also add the version without // the annotations. entry.cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations( - entry.cstring)) - .GetStringRef(); + entry.cstring.GetStringRef())); m_name_to_index.Append(entry); } } @@ -359,15 +356,15 @@ void Symtab::InitNameIndexes() { // If the demangled name turns out to be an ObjC name, and // is a category name, add the version without categories to the index // too. - ObjCLanguage::MethodName objc_method(entry.cstring, true); + ObjCLanguage::MethodName objc_method(entry.cstring.GetStringRef(), true); if (objc_method.IsValid(true)) { - entry.cstring = objc_method.GetSelector().GetStringRef(); + entry.cstring = objc_method.GetSelector(); m_selector_to_index.Append(entry); ConstString objc_method_no_category( objc_method.GetFullNameWithoutCategory(true)); if (objc_method_no_category) { - entry.cstring = objc_method_no_category.GetStringRef(); + entry.cstring = objc_method_no_category; m_name_to_index.Append(entry); } } @@ -427,6 +424,11 @@ void Symtab::InitNameIndexes() { } } +void Symtab::PreloadSymbols() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + InitNameIndexes(); +} + void Symtab::AppendSymbolNamesToMap(const IndexCollection &indexes, bool add_demangled, bool add_mangled, NameToIndexMap &name_to_index_map) const { @@ -444,15 +446,14 @@ void Symtab::AppendSymbolNamesToMap(const IndexCollection &indexes, const Mangled &mangled = symbol->GetMangled(); if (add_demangled) { - entry.cstring = - mangled.GetDemangledName(symbol->GetLanguage()).GetStringRef(); - if (!entry.cstring.empty()) + entry.cstring = mangled.GetDemangledName(symbol->GetLanguage()); + if (entry.cstring) name_to_index_map.Append(entry); } if (add_mangled) { - entry.cstring = mangled.GetMangledName().GetStringRef(); - if (!entry.cstring.empty()) + entry.cstring = mangled.GetMangledName(); + if (entry.cstring) name_to_index_map.Append(entry); } } @@ -625,7 +626,7 @@ uint32_t Symtab::AppendSymbolIndexesWithName(const ConstString &symbol_name, if (!m_name_indexes_computed) InitNameIndexes(); - return m_name_to_index.GetValues(symbol_name.GetStringRef(), indexes); + return m_name_to_index.GetValues(symbol_name, indexes); } return 0; } @@ -644,7 +645,7 @@ uint32_t Symtab::AppendSymbolIndexesWithName(const ConstString &symbol_name, std::vector<uint32_t> all_name_indexes; const size_t name_match_count = - m_name_to_index.GetValues(symbol_name.GetStringRef(), all_name_indexes); + m_name_to_index.GetValues(symbol_name, all_name_indexes); for (size_t i = 0; i < name_match_count; ++i) { if (CheckSymbolAtIndex(all_name_indexes[i], symbol_debug_type, symbol_visibility)) @@ -1068,8 +1069,6 @@ size_t Symtab::FindFunctionSymbols(const ConstString &name, size_t count = 0; std::vector<uint32_t> symbol_indexes; - llvm::StringRef name_cstr = name.GetStringRef(); - // eFunctionNameTypeAuto should be pre-resolved by a call to // Module::LookupInfo::LookupInfo() assert((name_type_mask & eFunctionNameTypeAuto) == 0); @@ -1107,7 +1106,7 @@ size_t Symtab::FindFunctionSymbols(const ConstString &name, if (!m_basename_to_index.IsEmpty()) { const UniqueCStringMap<uint32_t>::Entry *match; - for (match = m_basename_to_index.FindFirstValueForName(name_cstr); + for (match = m_basename_to_index.FindFirstValueForName(name); match != nullptr; match = m_basename_to_index.FindNextValueForName(match)) { symbol_indexes.push_back(match->value); @@ -1121,7 +1120,7 @@ size_t Symtab::FindFunctionSymbols(const ConstString &name, if (!m_method_to_index.IsEmpty()) { const UniqueCStringMap<uint32_t>::Entry *match; - for (match = m_method_to_index.FindFirstValueForName(name_cstr); + for (match = m_method_to_index.FindFirstValueForName(name); match != nullptr; match = m_method_to_index.FindNextValueForName(match)) { symbol_indexes.push_back(match->value); @@ -1135,7 +1134,7 @@ size_t Symtab::FindFunctionSymbols(const ConstString &name, if (!m_selector_to_index.IsEmpty()) { const UniqueCStringMap<uint32_t>::Entry *match; - for (match = m_selector_to_index.FindFirstValueForName(name_cstr); + for (match = m_selector_to_index.FindFirstValueForName(name); match != nullptr; match = m_selector_to_index.FindNextValueForName(match)) { symbol_indexes.push_back(match->value); diff --git a/contrib/llvm/tools/lldb/source/Target/Target.cpp b/contrib/llvm/tools/lldb/source/Target/Target.cpp index df021e3953bc..5c9e92aaaa27 100644 --- a/contrib/llvm/tools/lldb/source/Target/Target.cpp +++ b/contrib/llvm/tools/lldb/source/Target/Target.cpp @@ -1870,6 +1870,11 @@ ModuleSP Target::GetSharedModule(const ModuleSpec &module_spec, } } + // Preload symbols outside of any lock, so hopefully we can do this for + // each library in parallel. + if (GetPreloadSymbols()) + module_sp->PreloadSymbols(); + if (old_module_sp && m_images.GetIndexForModule(old_module_sp.get()) != LLDB_INVALID_INDEX32) { @@ -3277,6 +3282,8 @@ static PropertyDefinition g_properties[] = { {"detach-on-error", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, "debugserver will detach (rather than killing) a process if it " "loses connection with lldb."}, + {"preload-symbols", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, + "Enable loading of symbol tables before they are needed."}, {"disable-aslr", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, "Disable Address Space Layout Randomization (ASLR)"}, {"disable-stdio", OptionValue::eTypeBoolean, false, false, nullptr, nullptr, @@ -3379,6 +3386,7 @@ enum { ePropertyOutputPath, ePropertyErrorPath, ePropertyDetachOnError, + ePropertyPreloadSymbols, ePropertyDisableASLR, ePropertyDisableSTDIO, ePropertyInlineStrategy, @@ -3641,6 +3649,17 @@ bool TargetProperties::SetPreferDynamicValue(lldb::DynamicValueType d) { return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, d); } +bool TargetProperties::GetPreloadSymbols() const { + const uint32_t idx = ePropertyPreloadSymbols; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); +} + +void TargetProperties::SetPreloadSymbols(bool b) { + const uint32_t idx = ePropertyPreloadSymbols; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +} + bool TargetProperties::GetDisableASLR() const { const uint32_t idx = ePropertyDisableASLR; return m_collection_sp->GetPropertyAtIndexAsBoolean( diff --git a/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp b/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp index 8adeb6f364ef..49cf8a6d864d 100644 --- a/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp @@ -38,14 +38,13 @@ public: static StringPoolEntryType & GetStringMapEntryFromKeyData(const char *keyData) { - char *ptr = const_cast<char *>(keyData) - sizeof(StringPoolEntryType); - return *reinterpret_cast<StringPoolEntryType *>(ptr); + return StringPoolEntryType::GetStringMapEntryFromKeyData(keyData); } - size_t GetConstCStringLength(const char *ccstr) const { + static size_t GetConstCStringLength(const char *ccstr) { if (ccstr != nullptr) { - const uint8_t h = hash(llvm::StringRef(ccstr)); - llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex); + // Since the entry is read only, and we derive the entry entirely from the + // pointer, we don't need the lock. const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr); return entry.getKey().size(); } @@ -218,10 +217,8 @@ bool ConstString::operator<(const ConstString &rhs) const { if (m_string == rhs.m_string) return false; - llvm::StringRef lhs_string_ref(m_string, - StringPool().GetConstCStringLength(m_string)); - llvm::StringRef rhs_string_ref( - rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string)); + llvm::StringRef lhs_string_ref(GetStringRef()); + llvm::StringRef rhs_string_ref(rhs.GetStringRef()); // If both have valid C strings, then return the comparison if (lhs_string_ref.data() && rhs_string_ref.data()) @@ -240,7 +237,7 @@ Stream &lldb_private::operator<<(Stream &s, const ConstString &str) { } size_t ConstString::GetLength() const { - return StringPool().GetConstCStringLength(m_string); + return Pool::GetConstCStringLength(m_string); } bool ConstString::Equals(const ConstString &lhs, const ConstString &rhs, @@ -255,10 +252,8 @@ bool ConstString::Equals(const ConstString &lhs, const ConstString &rhs, return false; // perform case insensitive equality test - llvm::StringRef lhs_string_ref( - lhs.m_string, StringPool().GetConstCStringLength(lhs.m_string)); - llvm::StringRef rhs_string_ref( - rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string)); + llvm::StringRef lhs_string_ref(lhs.GetStringRef()); + llvm::StringRef rhs_string_ref(rhs.GetStringRef()); return lhs_string_ref.equals_lower(rhs_string_ref); } @@ -270,10 +265,8 @@ int ConstString::Compare(const ConstString &lhs, const ConstString &rhs, if (lhs_cstr == rhs_cstr) return 0; if (lhs_cstr && rhs_cstr) { - llvm::StringRef lhs_string_ref( - lhs_cstr, StringPool().GetConstCStringLength(lhs_cstr)); - llvm::StringRef rhs_string_ref( - rhs_cstr, StringPool().GetConstCStringLength(rhs_cstr)); + llvm::StringRef lhs_string_ref(lhs.GetStringRef()); + llvm::StringRef rhs_string_ref(rhs.GetStringRef()); if (case_sensitive) { return lhs_string_ref.compare(rhs_string_ref); diff --git a/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.cpp b/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.cpp index e6e73f8bdb6b..48a364886dc3 100644 --- a/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.cpp +++ b/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.cpp @@ -62,8 +62,7 @@ Error Acceptor::Listen(int backlog) { Error Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) { Socket *conn_socket = nullptr; - auto error = m_listener_socket_up->Accept( - StringRef(m_name), child_processes_inherit, conn_socket); + auto error = m_listener_socket_up->Accept(conn_socket); if (error.Success()) conn = new ConnectionFileDescriptor(conn_socket); diff --git a/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index 84fa0e4d2d9e..8ecf18480994 100644 --- a/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -78,6 +78,11 @@ static cl::opt<bool> SummarizeTypes("summarize-types", cl::desc("Abbreviate the description of type unit entries")); +static cl::opt<bool> Verify("verify", cl::desc("Verify the DWARF debug info")); + +static cl::opt<bool> Quiet("quiet", + cl::desc("Use with -verify to not emit to STDOUT.")); + static void error(StringRef Filename, std::error_code EC) { if (!EC) return; @@ -116,6 +121,46 @@ static void DumpInput(StringRef Filename) { } } +static bool VerifyObjectFile(ObjectFile &Obj, Twine Filename) { + std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(Obj)); + + // Verify the DWARF and exit with non-zero exit status if verification + // fails. + raw_ostream &stream = Quiet ? nulls() : outs(); + stream << "Verifying " << Filename.str() << ":\tfile format " + << Obj.getFileFormatName() << "\n"; + bool Result = DICtx->verify(stream, DumpType); + if (Result) + stream << "No errors.\n"; + else + stream << "Errors detected.\n"; + return Result; +} + +static bool VerifyInput(StringRef Filename) { + ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = + MemoryBuffer::getFileOrSTDIN(Filename); + error(Filename, BuffOrErr.getError()); + std::unique_ptr<MemoryBuffer> Buff = std::move(BuffOrErr.get()); + + Expected<std::unique_ptr<Binary>> BinOrErr = + object::createBinary(Buff->getMemBufferRef()); + if (!BinOrErr) + error(Filename, errorToErrorCode(BinOrErr.takeError())); + + bool Result = true; + if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) + Result = VerifyObjectFile(*Obj, Filename); + else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get())) + for (auto &ObjForArch : Fat->objects()) { + auto MachOOrErr = ObjForArch.getAsObjectFile(); + error(Filename, errorToErrorCode(MachOOrErr.takeError())); + if (!VerifyObjectFile(**MachOOrErr, Filename + " (" + ObjForArch.getArchFlagName() + ")")) + Result = false; + } + return Result; +} + /// If the input path is a .dSYM bundle (as created by the dsymutil tool), /// replace it with individual entries for each of the object files inside the /// bundle otherwise return the input path. @@ -168,7 +213,13 @@ int main(int argc, char **argv) { Objects.insert(Objects.end(), Objs.begin(), Objs.end()); } - std::for_each(Objects.begin(), Objects.end(), DumpInput); + if (Verify) { + // If we encountered errors during verify, exit with a non-zero exit status. + if (!std::all_of(Objects.begin(), Objects.end(), VerifyInput)) + exit(1); + } else { + std::for_each(Objects.begin(), Objects.end(), DumpInput); + } return EXIT_SUCCESS; } diff --git a/contrib/llvm/tools/llvm-link/llvm-link.cpp b/contrib/llvm/tools/llvm-link/llvm-link.cpp index a024b6926d5d..27199d53538e 100644 --- a/contrib/llvm/tools/llvm-link/llvm-link.cpp +++ b/contrib/llvm/tools/llvm-link/llvm-link.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" +#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DiagnosticInfo.h" @@ -23,7 +24,6 @@ #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Linker/Linker.h" -#include "llvm/Object/ModuleSummaryIndexObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" diff --git a/contrib/llvm/tools/llvm-lto/llvm-lto.cpp b/contrib/llvm/tools/llvm-lto/llvm-lto.cpp index 2f005412a3b9..27e5c5e122c2 100644 --- a/contrib/llvm/tools/llvm-lto/llvm-lto.cpp +++ b/contrib/llvm/tools/llvm-lto/llvm-lto.cpp @@ -23,7 +23,6 @@ #include "llvm/LTO/legacy/LTOCodeGenerator.h" #include "llvm/LTO/legacy/LTOModule.h" #include "llvm/LTO/legacy/ThinLTOCodeGenerator.h" -#include "llvm/Object/ModuleSummaryIndexObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" @@ -332,12 +331,9 @@ static void createCombinedModuleSummaryIndex() { uint64_t NextModuleId = 0; for (auto &Filename : InputFilenames) { ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': "); - std::unique_ptr<ModuleSummaryIndex> Index = - ExitOnErr(llvm::getModuleSummaryIndexForFile(Filename)); - // Skip files without a module summary. - if (!Index) - continue; - CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId); + std::unique_ptr<MemoryBuffer> MB = + ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename))); + ExitOnErr(readModuleSummaryIndex(*MB, CombinedIndex, ++NextModuleId)); } std::error_code EC; assert(!OutputFilename.empty()); diff --git a/contrib/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp b/contrib/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp new file mode 100644 index 000000000000..b38b36532a71 --- /dev/null +++ b/contrib/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.cpp @@ -0,0 +1,87 @@ +//===- C13DebugFragmentVisitor.cpp -------------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "C13DebugFragmentVisitor.h" + +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +C13DebugFragmentVisitor::C13DebugFragmentVisitor(PDBFile &F) : F(F) {} + +C13DebugFragmentVisitor::~C13DebugFragmentVisitor() {} + +Error C13DebugFragmentVisitor::visitUnknown( + codeview::ModuleDebugUnknownFragmentRef &Fragment) { + return Error::success(); +} + +Error C13DebugFragmentVisitor::visitFileChecksums( + codeview::ModuleDebugFileChecksumFragmentRef &Checksums) { + assert(!this->Checksums.hasValue()); + this->Checksums = Checksums; + return Error::success(); +} + +Error C13DebugFragmentVisitor::visitLines( + codeview::ModuleDebugLineFragmentRef &Lines) { + this->Lines.push_back(Lines); + return Error::success(); +} + +Error C13DebugFragmentVisitor::visitInlineeLines( + codeview::ModuleDebugInlineeLineFragmentRef &Lines) { + this->InlineeLines.push_back(Lines); + return Error::success(); +} + +Error C13DebugFragmentVisitor::finished() { + if (!Checksums.hasValue()) { + assert(Lines.empty()); + return Error::success(); + } + if (auto EC = handleFileChecksums()) + return EC; + + if (auto EC = handleLines()) + return EC; + + if (auto EC = handleInlineeLines()) + return EC; + + return Error::success(); +} + +Expected<StringRef> +C13DebugFragmentVisitor::getNameFromStringTable(uint32_t Offset) { + auto ST = F.getStringTable(); + if (!ST) + return ST.takeError(); + + return ST->getStringForID(Offset); +} + +Expected<StringRef> +C13DebugFragmentVisitor::getNameFromChecksumsBuffer(uint32_t Offset) { + assert(Checksums.hasValue()); + + auto Array = Checksums->getArray(); + auto ChecksumIter = Array.at(Offset); + if (ChecksumIter == Array.end()) + return make_error<RawError>(raw_error_code::invalid_format); + const auto &Entry = *ChecksumIter; + return getNameFromStringTable(Entry.FileNameOffset); +} diff --git a/contrib/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.h b/contrib/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.h new file mode 100644 index 000000000000..1054b0c9f6e0 --- /dev/null +++ b/contrib/llvm/tools/llvm-pdbdump/C13DebugFragmentVisitor.h @@ -0,0 +1,60 @@ +//===- C13DebugFragmentVisitor.h - Visitor for CodeView Info ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_C13DEBUGFRAGMENTVISITOR_H +#define LLVM_TOOLS_LLVMPDBDUMP_C13DEBUGFRAGMENTVISITOR_H + +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h" +#include "llvm/Support/Error.h" + +#include <vector> + +namespace llvm { + +namespace pdb { + +class PDBFile; + +class C13DebugFragmentVisitor : public codeview::ModuleDebugFragmentVisitor { +public: + C13DebugFragmentVisitor(PDBFile &F); + ~C13DebugFragmentVisitor(); + + Error visitUnknown(codeview::ModuleDebugUnknownFragmentRef &Fragment) final; + + Error visitFileChecksums( + codeview::ModuleDebugFileChecksumFragmentRef &Checksums) final; + + Error visitLines(codeview::ModuleDebugLineFragmentRef &Lines) final; + + Error + visitInlineeLines(codeview::ModuleDebugInlineeLineFragmentRef &Lines) final; + + Error finished() final; + +protected: + virtual Error handleFileChecksums() { return Error::success(); } + virtual Error handleLines() { return Error::success(); } + virtual Error handleInlineeLines() { return Error::success(); } + + Expected<StringRef> getNameFromStringTable(uint32_t Offset); + Expected<StringRef> getNameFromChecksumsBuffer(uint32_t Offset); + + Optional<codeview::ModuleDebugFileChecksumFragmentRef> Checksums; + std::vector<codeview::ModuleDebugInlineeLineFragmentRef> InlineeLines; + std::vector<codeview::ModuleDebugLineFragmentRef> Lines; + + PDBFile &F; +}; +} +} + +#endif diff --git a/contrib/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp b/contrib/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp index 1fc8dd5d51f0..5ad0bfad26c1 100644 --- a/contrib/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp @@ -31,14 +31,15 @@ static StringRef getLeafName(TypeLeafKind K) { CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB, ScopedPrinter *W) - : W(W), TI(TypeIndex::None()), Offset(0), TypeDB(TypeDB) {} + : CompactTypeDumpVisitor(TypeDB, TypeIndex(TypeIndex::FirstNonSimpleIndex), + W) {} -Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) { - if (TI == TypeIndex::None()) - TI.setIndex(TypeIndex::FirstNonSimpleIndex); - else - TI.setIndex(TI.getIndex() + 1); +CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB, + TypeIndex FirstTI, + ScopedPrinter *W) + : W(W), TI(FirstTI), Offset(0), TypeDB(TypeDB) {} +Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) { return Error::success(); } @@ -52,6 +53,7 @@ Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) { .str()); Offset += Record.length(); + TI.setIndex(TI.getIndex() + 1); return Error::success(); } diff --git a/contrib/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h b/contrib/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h index 180eea7b8d6a..76fafc93e030 100644 --- a/contrib/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h +++ b/contrib/llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h @@ -27,6 +27,8 @@ namespace pdb { class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks { public: CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, ScopedPrinter *W); + CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, + codeview::TypeIndex FirstTI, ScopedPrinter *W); /// Paired begin/end actions for all types. Receives all record data, /// including the fixed-length record prefix. diff --git a/contrib/llvm/tools/llvm-pdbdump/Diff.cpp b/contrib/llvm/tools/llvm-pdbdump/Diff.cpp index 8c02d36044d8..418c2361ac32 100644 --- a/contrib/llvm/tools/llvm-pdbdump/Diff.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/Diff.cpp @@ -15,8 +15,8 @@ #include "llvm/DebugInfo/PDB/Native/Formatters.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatProviders.h" @@ -394,11 +394,17 @@ Error DiffStyle::diffStringTable() { StringRef S1, S2; if (I < IdList1.size()) { Id1 = IdList1[I]; - S1 = ST1.getStringForID(*Id1); + if (auto Result = ST1.getStringForID(*Id1)) + S1 = *Result; + else + return Result.takeError(); } if (I < IdList2.size()) { Id2 = IdList2[I]; - S2 = ST2.getStringForID(*Id2); + if (auto Result = ST2.getStringForID(*Id2)) + S2 = *Result; + else + return Result.takeError(); } if (Id1 == Id2 && S1 == S2) continue; @@ -418,10 +424,18 @@ Error DiffStyle::diffStringTable() { std::vector<StringRef> Strings1, Strings2; Strings1.reserve(IdList1.size()); Strings2.reserve(IdList2.size()); - for (auto ID : IdList1) - Strings1.push_back(ST1.getStringForID(ID)); - for (auto ID : IdList2) - Strings2.push_back(ST2.getStringForID(ID)); + for (auto ID : IdList1) { + auto S = ST1.getStringForID(ID); + if (!S) + return S.takeError(); + Strings1.push_back(*S); + } + for (auto ID : IdList2) { + auto S = ST2.getStringForID(ID); + if (!S) + return S.takeError(); + Strings2.push_back(*S); + } SmallVector<StringRef, 64> OnlyP; SmallVector<StringRef, 64> OnlyQ; diff --git a/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 8348751703f1..ec1325ff2335 100644 --- a/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -9,6 +9,7 @@ #include "LLVMOutputStyle.h" +#include "C13DebugFragmentVisitor.h" #include "CompactTypeDumpVisitor.h" #include "StreamUtil.h" #include "llvm-pdbdump.h" @@ -16,20 +17,25 @@ #include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" -#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" +#include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/EnumTables.h" #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/ModInfo.h" -#include "llvm/DebugInfo/PDB/Native/ModStream.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" @@ -74,6 +80,127 @@ struct PageStats { // Pages which are marked free in the FPM but are used. BitVector UseAfterFreePages; }; + +class C13RawVisitor : public C13DebugFragmentVisitor { +public: + C13RawVisitor(ScopedPrinter &P, PDBFile &F, TypeDatabase &IPI) + : C13DebugFragmentVisitor(F), P(P), IPI(IPI) {} + + Error handleLines() override { + if (Lines.empty()) + return Error::success(); + + DictScope DD(P, "Lines"); + + for (const auto &Fragment : Lines) { + DictScope DDD(P, "Block"); + P.printNumber("RelocSegment", Fragment.header()->RelocSegment); + P.printNumber("RelocOffset", Fragment.header()->RelocOffset); + P.printNumber("CodeSize", Fragment.header()->CodeSize); + P.printBoolean("HasColumns", Fragment.hasColumnInfo()); + + for (const auto &L : Fragment) { + DictScope DDDD(P, "Lines"); + + if (auto EC = printFileName("FileName", L.NameIndex)) + return EC; + + for (const auto &N : L.LineNumbers) { + DictScope DDD(P, "Line"); + LineInfo LI(N.Flags); + P.printNumber("Offset", N.Offset); + if (LI.isAlwaysStepInto()) + P.printString("StepInto", StringRef("Always")); + else if (LI.isNeverStepInto()) + P.printString("StepInto", StringRef("Never")); + else + P.printNumber("LineNumberStart", LI.getStartLine()); + P.printNumber("EndDelta", LI.getLineDelta()); + P.printBoolean("IsStatement", LI.isStatement()); + } + for (const auto &C : L.Columns) { + DictScope DDD(P, "Column"); + P.printNumber("Start", C.StartColumn); + P.printNumber("End", C.EndColumn); + } + } + } + + return Error::success(); + } + + Error handleFileChecksums() override { + if (!Checksums.hasValue()) + return Error::success(); + + DictScope DD(P, "FileChecksums"); + for (const auto &CS : *Checksums) { + DictScope DDD(P, "Checksum"); + if (auto Result = getNameFromStringTable(CS.FileNameOffset)) + P.printString("FileName", *Result); + else + return Result.takeError(); + P.printEnum("Kind", uint8_t(CS.Kind), getFileChecksumNames()); + P.printBinaryBlock("Checksum", CS.Checksum); + } + return Error::success(); + } + + Error handleInlineeLines() override { + if (InlineeLines.empty()) + return Error::success(); + + DictScope D(P, "InlineeLines"); + for (const auto &IL : InlineeLines) { + P.printBoolean("HasExtraFiles", IL.hasExtraFiles()); + ListScope LS(P, "Lines"); + for (const auto &L : IL) { + DictScope DDD(P, "Inlinee"); + if (auto EC = printFileName("FileName", L.Header->FileID)) + return EC; + + if (auto EC = dumpTypeRecord("Function", IPI, L.Header->Inlinee)) + return EC; + P.printNumber("SourceLine", L.Header->SourceLineNum); + if (IL.hasExtraFiles()) { + ListScope DDDD(P, "ExtraFiles"); + for (const auto &EF : L.ExtraFiles) { + if (auto EC = printFileName("File", EF)) + return EC; + } + } + } + } + return Error::success(); + } + +private: + Error dumpTypeRecord(StringRef Label, TypeDatabase &DB, TypeIndex Index) { + CompactTypeDumpVisitor CTDV(DB, Index, &P); + CVTypeVisitor Visitor(CTDV); + DictScope D(P, Label); + if (DB.containsTypeIndex(Index)) { + CVType &Type = DB.getTypeRecord(Index); + if (auto EC = Visitor.visitTypeRecord(Type)) + return EC; + } else { + P.printString( + llvm::formatv("Index: {0:x} (unknown function)", Index.getIndex()) + .str()); + } + return Error::success(); + } + Error printFileName(StringRef Label, uint32_t Offset) { + if (auto Result = getNameFromChecksumsBuffer(Offset)) { + P.printString(Label, *Result); + return Error::success(); + } else + return Result.takeError(); + } + + ScopedPrinter &P; + TypeDatabase &IPI; +}; } static void recordKnownUsedPage(PageStats &Stats, uint32_t UsedIndex) { @@ -316,6 +443,27 @@ Error LLVMOutputStyle::dumpBlockRanges() { return Error::success(); } +static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset, + uint32_t &Size) { + if (Str.consumeInteger(0, SI)) + return make_error<RawError>(raw_error_code::invalid_format, + "Invalid Stream Specification"); + if (Str.consume_front(":")) { + if (Str.consumeInteger(0, Offset)) + return make_error<RawError>(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + if (Str.consume_front("@")) { + if (Str.consumeInteger(0, Size)) + return make_error<RawError>(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + if (!Str.empty()) + return make_error<RawError>(raw_error_code::invalid_format, + "Invalid Stream Specification"); + return Error::success(); +} + Error LLVMOutputStyle::dumpStreamBytes() { if (opts::raw::DumpStreamData.empty()) return Error::success(); @@ -324,7 +472,15 @@ Error LLVMOutputStyle::dumpStreamBytes() { discoverStreamPurposes(File, StreamPurposes); DictScope D(P, "Stream Data"); - for (uint32_t SI : opts::raw::DumpStreamData) { + for (auto &Str : opts::raw::DumpStreamData) { + uint32_t SI = 0; + uint32_t Begin = 0; + uint32_t Size = 0; + uint32_t End = 0; + + if (auto EC = parseStreamSpec(Str, SI, Begin, Size)) + return EC; + if (SI >= File.getNumStreams()) return make_error<RawError>(raw_error_code::no_stream); @@ -333,6 +489,14 @@ Error LLVMOutputStyle::dumpStreamBytes() { if (!S) continue; DictScope DD(P, "Stream"); + if (Size == 0) + End = S->getLength(); + else { + End = Begin + Size; + if (End >= S->getLength()) + return make_error<RawError>(raw_error_code::index_out_of_bounds, + "Stream is not long enough!"); + } P.printNumber("Index", SI); P.printString("Type", StreamPurposes[SI]); @@ -344,7 +508,9 @@ Error LLVMOutputStyle::dumpStreamBytes() { ArrayRef<uint8_t> StreamData; if (auto EC = R.readBytes(StreamData, S->getLength())) return EC; - P.printBinaryBlock("Data", StreamData); + Size = End - Begin; + StreamData = StreamData.slice(Begin, Size); + P.printBinaryBlock("Data", StreamData, Begin); } return Error::success(); } @@ -359,14 +525,17 @@ Error LLVMOutputStyle::dumpStringTable() { DictScope D(P, "String Table"); for (uint32_t I : IS->name_ids()) { - StringRef S = IS->getStringForID(I); - if (!S.empty()) { - llvm::SmallString<32> Str; - Str.append("'"); - Str.append(S); - Str.append("'"); - P.printString(Str); - } + auto ES = IS->getStringForID(I); + if (!ES) + return ES.takeError(); + + if (ES->empty()) + continue; + llvm::SmallString<32> Str; + Str.append("'"); + Str.append(*ES); + Str.append("'"); + P.printString(Str); } return Error::success(); } @@ -439,11 +608,12 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { Label = "Type Info Stream (IPI)"; VerLabel = "IPI Version"; } - if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash && - !opts::raw::DumpModuleSyms) - return Error::success(); bool IsSilentDatabaseBuild = !DumpRecordBytes && !DumpRecords && !DumpTpiHash; + if (IsSilentDatabaseBuild) { + outs().flush(); + errs() << "Building Type Information For " << Label << "\n"; + } auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream(); @@ -502,6 +672,7 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { if (auto EC = Visitor.visitTypeRecord(Type)) return EC; + T.setIndex(T.getIndex() + 1); } if (HadError) return make_error<RawError>(raw_error_code::corrupt_file, @@ -520,8 +691,11 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { const auto &ST = *ExpectedST; for (const auto &E : Tpi->getHashAdjusters()) { DictScope DHA(P); - StringRef Name = ST.getStringForID(E.first); - P.printString("Type", Name); + auto Name = ST.getStringForID(E.first); + if (!Name) + return Name.takeError(); + + P.printString("Type", *Name); P.printHex("TI", E.second); } } @@ -584,7 +758,7 @@ Error LLVMOutputStyle::dumpDbiStream() { P.printNumber("Num Files", Modi.Info.getNumberOfFiles()); P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex()); P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex()); - P.printNumber("Line Info Byte Size", Modi.Info.getLineInfoByteSize()); + P.printNumber("Line Info Byte Size", Modi.Info.getC11LineInfoByteSize()); P.printNumber("C13 Line Info Byte Size", Modi.Info.getC13LineInfoByteSize()); P.printNumber("Symbol Byte Size", Modi.Info.getSymbolDebugInfoByteSize()); @@ -606,7 +780,7 @@ Error LLVMOutputStyle::dumpDbiStream() { File.getMsfLayout(), File.getMsfBuffer(), Modi.Info.getModuleStreamIndex()); - ModStream ModS(Modi.Info, std::move(ModStreamData)); + ModuleDebugStreamRef ModS(Modi.Info, std::move(ModStreamData)); if (auto EC = ModS.reload()) return EC; @@ -633,97 +807,11 @@ Error LLVMOutputStyle::dumpDbiStream() { } if (opts::raw::DumpLineInfo) { ListScope SS(P, "LineInfo"); - bool HadError = false; - // Define a locally scoped visitor to print the different - // substream types types. - class RecordVisitor : public codeview::IModuleSubstreamVisitor { - public: - RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {} - Error visitUnknown(ModuleSubstreamKind Kind, - BinaryStreamRef Stream) override { - DictScope DD(P, "Unknown"); - ArrayRef<uint8_t> Data; - BinaryStreamReader R(Stream); - if (auto EC = R.readBytes(Data, R.bytesRemaining())) { - return make_error<RawError>( - raw_error_code::corrupt_file, - "DBI stream contained corrupt line info record"); - } - P.printBinaryBlock("Data", Data); - return Error::success(); - } - Error - visitFileChecksums(BinaryStreamRef Data, - const FileChecksumArray &Checksums) override { - DictScope DD(P, "FileChecksums"); - for (const auto &C : Checksums) { - DictScope DDD(P, "Checksum"); - if (auto Result = getFileNameForOffset(C.FileNameOffset)) - P.printString("FileName", Result.get()); - else - return Result.takeError(); - P.flush(); - P.printEnum("Kind", uint8_t(C.Kind), getFileChecksumNames()); - P.printBinaryBlock("Checksum", C.Checksum); - } - return Error::success(); - } - Error visitLines(BinaryStreamRef Data, - const LineSubstreamHeader *Header, - const LineInfoArray &Lines) override { - DictScope DD(P, "Lines"); - for (const auto &L : Lines) { - if (auto Result = getFileNameForOffset2(L.NameIndex)) - P.printString("FileName", Result.get()); - else - return Result.takeError(); - P.flush(); - for (const auto &N : L.LineNumbers) { - DictScope DDD(P, "Line"); - LineInfo LI(N.Flags); - P.printNumber("Offset", N.Offset); - if (LI.isAlwaysStepInto()) - P.printString("StepInto", StringRef("Always")); - else if (LI.isNeverStepInto()) - P.printString("StepInto", StringRef("Never")); - else - P.printNumber("LineNumberStart", LI.getStartLine()); - P.printNumber("EndDelta", LI.getLineDelta()); - P.printBoolean("IsStatement", LI.isStatement()); - } - for (const auto &C : L.Columns) { - DictScope DDD(P, "Column"); - P.printNumber("Start", C.StartColumn); - P.printNumber("End", C.EndColumn); - } - } - return Error::success(); - } - - private: - Expected<StringRef> getFileNameForOffset(uint32_t Offset) { - auto ST = F.getStringTable(); - if (!ST) - return ST.takeError(); - - return ST->getStringForID(Offset); - } - Expected<StringRef> getFileNameForOffset2(uint32_t Offset) { - auto DS = F.getPDBDbiStream(); - if (!DS) - return DS.takeError(); - return DS->getFileNameForIndex(Offset); - } - ScopedPrinter &P; - PDBFile &F; - }; - - RecordVisitor V(P, File); - for (const auto &L : ModS.lines(&HadError)) { - if (auto EC = codeview::visitModuleSubstream(L, V)) - return EC; - } + C13RawVisitor V(P, File, ItemDB); + if (auto EC = codeview::visitModuleDebugFragments( + ModS.linesAndChecksums(), V)) + return EC; } } } diff --git a/contrib/llvm/tools/llvm-pdbdump/PdbYaml.cpp b/contrib/llvm/tools/llvm-pdbdump/PdbYaml.cpp index 65a5a9142d20..d6ba7d645459 100644 --- a/contrib/llvm/tools/llvm-pdbdump/PdbYaml.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/PdbYaml.cpp @@ -40,6 +40,9 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSourceFileChecksumEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSourceLineEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSourceColumnEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSourceLineBlock) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSourceLineInfo) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbInlineeSite) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbInlineeInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSymbolRecord) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiRecord) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) @@ -162,8 +165,7 @@ template <> struct ScalarEnumerationTraits<llvm::codeview::FileChecksumKind> { template <> struct ScalarBitSetTraits<llvm::codeview::LineFlags> { static void bitset(IO &io, llvm::codeview::LineFlags &Flags) { - io.bitSetCase(Flags, "HasColumnInfo", - llvm::codeview::LineFlags::HaveColumns); + io.bitSetCase(Flags, "HasColumnInfo", llvm::codeview::LF_HaveColumns); io.enumFallback<Hex16>(Flags); } }; @@ -311,7 +313,7 @@ void MappingContextTraits<pdb::yaml::PdbSourceColumnEntry, pdb::yaml::SerializationContext &Context) { IO.mapRequired("StartColumn", Obj.StartColumn); IO.mapRequired("EndColumn", Obj.EndColumn); -}; +} void MappingContextTraits<pdb::yaml::PdbSourceLineBlock, pdb::yaml::SerializationContext>:: @@ -320,7 +322,7 @@ void MappingContextTraits<pdb::yaml::PdbSourceLineBlock, IO.mapRequired("FileName", Obj.FileName); IO.mapRequired("Lines", Obj.Lines, Context); IO.mapRequired("Columns", Obj.Columns, Context); -}; +} void MappingContextTraits<pdb::yaml::PdbSourceFileChecksumEntry, pdb::yaml::SerializationContext>:: @@ -329,26 +331,42 @@ void MappingContextTraits<pdb::yaml::PdbSourceFileChecksumEntry, IO.mapRequired("FileName", Obj.FileName); IO.mapRequired("Kind", Obj.Kind); IO.mapRequired("Checksum", Obj.ChecksumBytes); -}; +} void MappingContextTraits<pdb::yaml::PdbSourceLineInfo, pdb::yaml::SerializationContext>:: mapping(IO &IO, PdbSourceLineInfo &Obj, pdb::yaml::SerializationContext &Context) { IO.mapRequired("CodeSize", Obj.CodeSize); + IO.mapRequired("Flags", Obj.Flags); IO.mapRequired("RelocOffset", Obj.RelocOffset); IO.mapRequired("RelocSegment", Obj.RelocSegment); - IO.mapRequired("LineInfo", Obj.LineInfo, Context); -}; + IO.mapRequired("Blocks", Obj.Blocks, Context); +} void MappingContextTraits<pdb::yaml::PdbSourceFileInfo, pdb::yaml::SerializationContext>:: mapping(IO &IO, PdbSourceFileInfo &Obj, pdb::yaml::SerializationContext &Context) { - IO.mapOptionalWithContext("Lines", Obj.Lines, Context); IO.mapOptionalWithContext("Checksums", Obj.FileChecksums, Context); -}; + IO.mapOptionalWithContext("Lines", Obj.LineFragments, Context); + IO.mapOptionalWithContext("InlineeLines", Obj.Inlinees, Context); +} + +void MappingContextTraits<PdbInlineeSite, SerializationContext>::mapping( + IO &IO, PdbInlineeSite &Obj, SerializationContext &Context) { + IO.mapRequired("FileName", Obj.FileName); + IO.mapRequired("LineNum", Obj.SourceLineNum); + IO.mapRequired("Inlinee", Obj.Inlinee); + IO.mapOptional("ExtraFiles", Obj.ExtraFiles); +} + +void MappingContextTraits<PdbInlineeInfo, SerializationContext>::mapping( + IO &IO, PdbInlineeInfo &Obj, SerializationContext &Context) { + IO.mapRequired("HasExtraFiles", Obj.HasExtraFiles); + IO.mapRequired("Sites", Obj.Sites, Context); +} void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>:: mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj, diff --git a/contrib/llvm/tools/llvm-pdbdump/PdbYaml.h b/contrib/llvm/tools/llvm-pdbdump/PdbYaml.h index 96e0583ca23d..423845caeb31 100644 --- a/contrib/llvm/tools/llvm-pdbdump/PdbYaml.h +++ b/contrib/llvm/tools/llvm-pdbdump/PdbYaml.h @@ -99,12 +99,25 @@ struct PdbSourceLineInfo { codeview::LineFlags Flags; uint32_t CodeSize; - std::vector<PdbSourceLineBlock> LineInfo; + std::vector<PdbSourceLineBlock> Blocks; +}; + +struct PdbInlineeSite { + codeview::TypeIndex Inlinee; + StringRef FileName; + uint32_t SourceLineNum; + std::vector<StringRef> ExtraFiles; +}; + +struct PdbInlineeInfo { + bool HasExtraFiles; + std::vector<PdbInlineeSite> Sites; }; struct PdbSourceFileInfo { - PdbSourceLineInfo Lines; std::vector<PdbSourceFileChecksumEntry> FileChecksums; + std::vector<PdbSourceLineInfo> LineFragments; + std::vector<PdbInlineeInfo> Inlinees; }; struct PdbDbiModuleInfo { @@ -259,6 +272,20 @@ struct MappingContextTraits<pdb::yaml::PdbSourceFileInfo, }; template <> +struct MappingContextTraits<pdb::yaml::PdbInlineeInfo, + pdb::yaml::SerializationContext> { + static void mapping(IO &IO, pdb::yaml::PdbInlineeInfo &Obj, + pdb::yaml::SerializationContext &Context); +}; + +template <> +struct MappingContextTraits<pdb::yaml::PdbInlineeSite, + pdb::yaml::SerializationContext> { + static void mapping(IO &IO, pdb::yaml::PdbInlineeSite &Obj, + pdb::yaml::SerializationContext &Context); +}; + +template <> struct MappingContextTraits<pdb::yaml::PdbTpiRecord, pdb::yaml::SerializationContext> { static void mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj, diff --git a/contrib/llvm/tools/llvm-pdbdump/StreamUtil.cpp b/contrib/llvm/tools/llvm-pdbdump/StreamUtil.cpp index db1e01aa0154..6577702adac8 100644 --- a/contrib/llvm/tools/llvm-pdbdump/StreamUtil.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/StreamUtil.cpp @@ -11,9 +11,9 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/ModInfo.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" diff --git a/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp index b329de265e72..b94b5a4abf37 100644 --- a/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -9,21 +9,28 @@ #include "YAMLOutputStyle.h" +#include "C13DebugFragmentVisitor.h" #include "PdbYaml.h" #include "llvm-pdbdump.h" #include "llvm/DebugInfo/CodeView/Line.h" -#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/ModStream.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" using namespace llvm; +using namespace llvm::codeview; using namespace llvm::pdb; YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) @@ -46,6 +53,12 @@ Error YAMLOutputStyle::dump() { if (opts::pdb2yaml::DbiModuleInfo) opts::pdb2yaml::DbiStream = true; + // Some names from the module source file info get pulled from the string + // table, so if we're writing module source info, we have to write the string + // table as well. + if (opts::pdb2yaml::DbiModuleSourceLineInfo) + opts::pdb2yaml::StringTable = true; + if (auto EC = dumpFileHeaders()) return EC; @@ -75,22 +88,15 @@ Error YAMLOutputStyle::dump() { } namespace { -class C13SubstreamVisitor : public codeview::IModuleSubstreamVisitor { +class C13YamlVisitor : public C13DebugFragmentVisitor { public: - C13SubstreamVisitor(llvm::pdb::yaml::PdbSourceFileInfo &Info, PDBFile &F) - : Info(Info), F(F) {} - - Error visitUnknown(codeview::ModuleSubstreamKind Kind, - BinaryStreamRef Stream) override { - return Error::success(); - } + C13YamlVisitor(llvm::pdb::yaml::PdbSourceFileInfo &Info, PDBFile &F) + : C13DebugFragmentVisitor(F), Info(Info) {} - Error - visitFileChecksums(BinaryStreamRef Data, - const codeview::FileChecksumArray &Checksums) override { - for (const auto &C : Checksums) { + Error handleFileChecksums() override { + for (const auto &C : *Checksums) { llvm::pdb::yaml::PdbSourceFileChecksumEntry Entry; - if (auto Result = getGlobalString(C.FileNameOffset)) + if (auto Result = getNameFromStringTable(C.FileNameOffset)) Entry.FileName = *Result; else return Result.takeError(); @@ -102,80 +108,94 @@ public: return Error::success(); } - Error visitLines(BinaryStreamRef Data, - const codeview::LineSubstreamHeader *Header, - const codeview::LineInfoArray &Lines) override { - - Info.Lines.CodeSize = Header->CodeSize; - Info.Lines.Flags = - static_cast<codeview::LineFlags>(uint16_t(Header->Flags)); - Info.Lines.RelocOffset = Header->RelocOffset; - Info.Lines.RelocSegment = Header->RelocSegment; - - for (const auto &L : Lines) { - llvm::pdb::yaml::PdbSourceLineBlock Block; - - if (auto Result = getDbiFileName(L.NameIndex)) - Block.FileName = *Result; - else - return Result.takeError(); + Error handleLines() override { + for (const auto &LF : Lines) { + Info.LineFragments.emplace_back(); + auto &Fragment = Info.LineFragments.back(); + + Fragment.CodeSize = LF.header()->CodeSize; + Fragment.Flags = + static_cast<codeview::LineFlags>(uint16_t(LF.header()->Flags)); + Fragment.RelocOffset = LF.header()->RelocOffset; + Fragment.RelocSegment = LF.header()->RelocSegment; + + for (const auto &L : LF) { + Fragment.Blocks.emplace_back(); + auto &Block = Fragment.Blocks.back(); + + if (auto Result = getNameFromChecksumsBuffer(L.NameIndex)) + Block.FileName = *Result; + else + return Result.takeError(); + + for (const auto &N : L.LineNumbers) { + llvm::pdb::yaml::PdbSourceLineEntry Line; + Line.Offset = N.Offset; + codeview::LineInfo LI(N.Flags); + Line.LineStart = LI.getStartLine(); + Line.EndDelta = LI.getLineDelta(); + Line.IsStatement = LI.isStatement(); + Block.Lines.push_back(Line); + } - for (const auto &N : L.LineNumbers) { - llvm::pdb::yaml::PdbSourceLineEntry Line; - Line.Offset = N.Offset; - codeview::LineInfo LI(N.Flags); - Line.LineStart = LI.getStartLine(); - Line.EndDelta = LI.getEndLine(); - Line.IsStatement = LI.isStatement(); - Block.Lines.push_back(Line); + if (LF.hasColumnInfo()) { + for (const auto &C : L.Columns) { + llvm::pdb::yaml::PdbSourceColumnEntry Column; + Column.StartColumn = C.StartColumn; + Column.EndColumn = C.EndColumn; + Block.Columns.push_back(Column); + } + } } + } + return Error::success(); + } - if (Info.Lines.Flags & codeview::LineFlags::HaveColumns) { - for (const auto &C : L.Columns) { - llvm::pdb::yaml::PdbSourceColumnEntry Column; - Column.StartColumn = C.StartColumn; - Column.EndColumn = C.EndColumn; - Block.Columns.push_back(Column); + Error handleInlineeLines() override { + for (const auto &ILF : InlineeLines) { + Info.Inlinees.emplace_back(); + auto &Inlinee = Info.Inlinees.back(); + + Inlinee.HasExtraFiles = ILF.hasExtraFiles(); + for (const auto &IL : ILF) { + Inlinee.Sites.emplace_back(); + auto &Site = Inlinee.Sites.back(); + if (auto Result = getNameFromChecksumsBuffer(IL.Header->FileID)) + Site.FileName = *Result; + else + return Result.takeError(); + + Site.Inlinee = IL.Header->Inlinee; + Site.SourceLineNum = IL.Header->SourceLineNum; + if (ILF.hasExtraFiles()) { + for (const auto &EF : IL.ExtraFiles) { + if (auto Result = getNameFromChecksumsBuffer(EF)) + Site.ExtraFiles.push_back(*Result); + else + return Result.takeError(); + } } } - - Info.Lines.LineInfo.push_back(Block); } return Error::success(); } private: - Expected<StringRef> getGlobalString(uint32_t Offset) { - auto ST = F.getStringTable(); - if (!ST) - return ST.takeError(); - - return ST->getStringForID(Offset); - } - Expected<StringRef> getDbiFileName(uint32_t Offset) { - auto DS = F.getPDBDbiStream(); - if (!DS) - return DS.takeError(); - return DS->getFileNameForIndex(Offset); - } llvm::pdb::yaml::PdbSourceFileInfo &Info; - PDBFile &F; }; } Expected<Optional<llvm::pdb::yaml::PdbSourceFileInfo>> -YAMLOutputStyle::getFileLineInfo(const pdb::ModStream &ModS) { +YAMLOutputStyle::getFileLineInfo(const pdb::ModuleDebugStreamRef &ModS) { if (!ModS.hasLineInfo()) return None; yaml::PdbSourceFileInfo Info; - bool Error = false; - C13SubstreamVisitor Visitor(Info, File); - for (auto &Substream : ModS.lines(&Error)) { - if (auto E = codeview::visitModuleSubstream(Substream, Visitor)) - return std::move(E); - } + C13YamlVisitor Visitor(Info, File); + if (auto EC = codeview::visitModuleDebugFragments(ModS.linesAndChecksums(), + Visitor)) + return std::move(EC); return Info; } @@ -213,9 +233,12 @@ Error YAMLOutputStyle::dumpStringTable() { const auto &ST = ExpectedST.get(); for (auto ID : ST.name_ids()) { - StringRef S = ST.getStringForID(ID); - if (!S.empty()) - Obj.StringTable->push_back(S); + auto S = ST.getStringForID(ID); + if (!S) + return S.takeError(); + if (S->empty()) + continue; + Obj.StringTable->push_back(*S); } return Error::success(); } @@ -283,17 +306,22 @@ Error YAMLOutputStyle::dumpDbiStream() { Obj.DbiStream->VerHeader = DS.getDbiVersion(); if (opts::pdb2yaml::DbiModuleInfo) { for (const auto &MI : DS.modules()) { - yaml::PdbDbiModuleInfo DMI; + Obj.DbiStream->ModInfos.emplace_back(); + yaml::PdbDbiModuleInfo &DMI = Obj.DbiStream->ModInfos.back(); + DMI.Mod = MI.Info.getModuleName(); DMI.Obj = MI.Info.getObjFileName(); if (opts::pdb2yaml::DbiModuleSourceFileInfo) DMI.SourceFiles = MI.SourceFiles; + uint16_t ModiStream = MI.Info.getModuleStreamIndex(); + if (ModiStream == kInvalidStreamIndex) + continue; + auto ModStreamData = msf::MappedBlockStream::createIndexedStream( - File.getMsfLayout(), File.getMsfBuffer(), - MI.Info.getModuleStreamIndex()); + File.getMsfLayout(), File.getMsfBuffer(), ModiStream); - pdb::ModStream ModS(MI.Info, std::move(ModStreamData)); + pdb::ModuleDebugStreamRef ModS(MI.Info, std::move(ModStreamData)); if (auto EC = ModS.reload()) return EC; @@ -304,8 +332,7 @@ Error YAMLOutputStyle::dumpDbiStream() { DMI.FileLineInfo = *ExpectedInfo; } - if (opts::pdb2yaml::DbiModuleSyms && - MI.Info.getModuleStreamIndex() != kInvalidStreamIndex) { + if (opts::pdb2yaml::DbiModuleSyms) { DMI.Modi.emplace(); DMI.Modi->Signature = ModS.signature(); @@ -315,7 +342,6 @@ Error YAMLOutputStyle::dumpDbiStream() { DMI.Modi->Symbols.push_back(Record); } } - Obj.DbiStream->ModInfos.push_back(DMI); } } return Error::success(); diff --git a/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h b/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h index 263af776fa03..517c7d86d7ab 100644 --- a/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h +++ b/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h @@ -19,7 +19,7 @@ namespace llvm { namespace pdb { -class ModStream; +class ModuleDebugStreamRef; class YAMLOutputStyle : public OutputStyle { public: @@ -29,7 +29,7 @@ public: private: Expected<Optional<llvm::pdb::yaml::PdbSourceFileInfo>> - getFileLineInfo(const pdb::ModStream &ModS); + getFileLineInfo(const pdb::ModuleDebugStreamRef &ModS); Error dumpStringTable(); Error dumpFileHeaders(); diff --git a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp index 7337b1d28747..4cdd87620c86 100644 --- a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -28,24 +28,28 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/DebugInfo/PDB/PDB.h" @@ -261,9 +265,10 @@ cl::opt<std::string> cl::cat(MsfOptions), cl::sub(RawSubcommand)); llvm::Optional<BlockRange> DumpBlockRange; -cl::list<uint32_t> +cl::list<std::string> DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore, - cl::desc("Dump binary data from specified streams."), + cl::desc("Dump binary data from specified streams. Format " + "is SN[:Start][@Size]"), cl::cat(MsfOptions), cl::sub(RawSubcommand)); // TYPE OPTIONS @@ -470,6 +475,8 @@ static void yamlToPdb(StringRef Path) { for (auto F : Info.Features) InfoBuilder.addFeature(F); + auto &Strings = Builder.getStringTableBuilder().getStrings(); + const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream); auto &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setAge(Dbi.Age); @@ -490,6 +497,66 @@ static void yamlToPdb(StringRef Path) { for (auto Symbol : ModiStream.Symbols) ModiBuilder.addSymbol(Symbol.Record); } + if (MI.FileLineInfo.hasValue()) { + const auto &FLI = *MI.FileLineInfo; + + // File Checksums must be emitted before line information, because line + // info records use offsets into the checksum buffer to reference a file's + // source file name. + auto Checksums = + llvm::make_unique<ModuleDebugFileChecksumFragment>(Strings); + auto &ChecksumRef = *Checksums; + if (!FLI.FileChecksums.empty()) { + for (auto &FC : FLI.FileChecksums) + Checksums->addChecksum(FC.FileName, FC.Kind, FC.ChecksumBytes.Bytes); + } + ModiBuilder.setC13FileChecksums(std::move(Checksums)); + + for (const auto &Fragment : FLI.LineFragments) { + auto Lines = + llvm::make_unique<ModuleDebugLineFragment>(ChecksumRef, Strings); + Lines->setCodeSize(Fragment.CodeSize); + Lines->setRelocationAddress(Fragment.RelocSegment, + Fragment.RelocOffset); + Lines->setFlags(Fragment.Flags); + for (const auto &LC : Fragment.Blocks) { + Lines->createBlock(LC.FileName); + if (Lines->hasColumnInfo()) { + for (const auto &Item : zip(LC.Lines, LC.Columns)) { + auto &L = std::get<0>(Item); + auto &C = std::get<1>(Item); + uint32_t LE = L.LineStart + L.EndDelta; + Lines->addLineAndColumnInfo( + L.Offset, LineInfo(L.LineStart, LE, L.IsStatement), + C.StartColumn, C.EndColumn); + } + } else { + for (const auto &L : LC.Lines) { + uint32_t LE = L.LineStart + L.EndDelta; + Lines->addLineInfo(L.Offset, + LineInfo(L.LineStart, LE, L.IsStatement)); + } + } + } + ModiBuilder.addC13Fragment(std::move(Lines)); + } + + for (const auto &Inlinee : FLI.Inlinees) { + auto Inlinees = llvm::make_unique<ModuleDebugInlineeLineFragment>( + ChecksumRef, Inlinee.HasExtraFiles); + for (const auto &Site : Inlinee.Sites) { + Inlinees->addInlineSite(Site.Inlinee, Site.FileName, + Site.SourceLineNum); + if (!Inlinee.HasExtraFiles) + continue; + + for (auto EF : Site.ExtraFiles) { + Inlinees->addExtraFile(EF); + } + } + ModiBuilder.addC13Fragment(std::move(Inlinees)); + } + } } auto &TpiBuilder = Builder.getTpiBuilder(); diff --git a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h index f080d6d55250..8b1dde9399bf 100644 --- a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h @@ -60,7 +60,7 @@ struct BlockRange { }; extern llvm::Optional<BlockRange> DumpBlockRange; -extern llvm::cl::list<uint32_t> DumpStreamData; +extern llvm::cl::list<std::string> DumpStreamData; extern llvm::cl::opt<bool> CompactRecords; extern llvm::cl::opt<bool> DumpGlobals; diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp index 9836c137ed2c..04386875b95a 100644 --- a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -25,7 +25,11 @@ #include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h" +#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/StringTable.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" @@ -38,11 +42,12 @@ #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/COFF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/SourceMgr.h" @@ -78,6 +83,7 @@ public: void printCOFFDirectives() override; void printCOFFBaseReloc() override; void printCOFFDebugDirectory() override; + void printCOFFResources() override; void printCodeViewDebugInfo() override; void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs, llvm::codeview::TypeTableBuilder &CVTypes) override; @@ -119,7 +125,7 @@ private: StringRef SectionContents, StringRef Block); /// Given a .debug$S section, find the string table and file checksum table. - void initializeFileAndStringTables(StringRef Data); + void initializeFileAndStringTables(BinaryStreamReader &Reader); void cacheRelocations(); @@ -140,8 +146,12 @@ private: const llvm::object::COFFObjectFile *Obj; bool RelocCached = false; RelocMapTy RelocMap; - StringRef CVFileChecksumTable; - StringRef CVStringTable; + + BinaryByteStream ChecksumContents; + VarStreamArray<FileChecksumEntry> CVFileChecksumTable; + + BinaryByteStream StringTableContents; + StringTableRef CVStringTable; ScopedPrinter &Writer; TypeDatabase TypeDB; @@ -181,7 +191,7 @@ public: return CD.getFileNameForFileOffset(FileOffset); } - StringRef getStringTable() override { return CD.CVStringTable; } + StringTableRef getStringTable() override { return CD.CVStringTable; } private: COFFDumper &CD; @@ -496,19 +506,19 @@ WeakExternalCharacteristics[] = { }; static const EnumEntry<uint32_t> SubSectionTypes[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Symbols), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Lines), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, StringTable), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, FileChecksums), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, FrameData), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, InlineeLines), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeImports), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeExports), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, ILLines), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, FuncMDTokenMap), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, TypeMDTokenMap), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, MergedAssemblyInput), - LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CoffSymbolRVA), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, Symbols), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, Lines), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, StringTable), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, FileChecksums), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, FrameData), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, InlineeLines), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, CrossScopeImports), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, CrossScopeExports), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, ILLines), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, FuncMDTokenMap), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, TypeMDTokenMap), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, MergedAssemblyInput), + LLVM_READOBJ_ENUM_CLASS_ENT(ModuleDebugFragmentKind, CoffSymbolRVA), }; static const EnumEntry<uint32_t> FrameDataFlags[] = { @@ -720,30 +730,35 @@ void COFFDumper::printCodeViewDebugInfo() { } } -void COFFDumper::initializeFileAndStringTables(StringRef Data) { - while (!Data.empty() && (CVFileChecksumTable.data() == nullptr || - CVStringTable.data() == nullptr)) { +void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) { + while (Reader.bytesRemaining() > 0 && + (!CVFileChecksumTable.valid() || !CVStringTable.valid())) { // The section consists of a number of subsection in the following format: // |SubSectionType|SubSectionSize|Contents...| uint32_t SubType, SubSectionSize; - error(consume(Data, SubType)); - error(consume(Data, SubSectionSize)); - if (SubSectionSize > Data.size()) - return error(object_error::parse_failed); - switch (ModuleSubstreamKind(SubType)) { - case ModuleSubstreamKind::FileChecksums: - CVFileChecksumTable = Data.substr(0, SubSectionSize); - break; - case ModuleSubstreamKind::StringTable: - CVStringTable = Data.substr(0, SubSectionSize); + error(Reader.readInteger(SubType)); + error(Reader.readInteger(SubSectionSize)); + + StringRef Contents; + error(Reader.readFixedString(Contents, SubSectionSize)); + + switch (ModuleDebugFragmentKind(SubType)) { + case ModuleDebugFragmentKind::FileChecksums: { + ChecksumContents = BinaryByteStream(Contents, support::little); + BinaryStreamReader CSR(ChecksumContents); + error(CSR.readArray(CVFileChecksumTable, CSR.getLength())); break; + } + case ModuleDebugFragmentKind::StringTable: { + StringTableContents = BinaryByteStream(Contents, support::little); + error(CVStringTable.initialize(StringTableContents)); + } break; default: break; } + uint32_t PaddedSize = alignTo(SubSectionSize, 4); - if (PaddedSize > Data.size()) - error(object_error::parse_failed); - Data = Data.drop_front(PaddedSize); + error(Reader.skip(PaddedSize - SubSectionSize)); } } @@ -766,7 +781,9 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, if (Magic != COFF::DEBUG_SECTION_MAGIC) return error(object_error::parse_failed); - initializeFileAndStringTables(Data); + BinaryByteStream FileAndStrings(Data, support::little); + BinaryStreamReader FSReader(FileAndStrings); + initializeFileAndStringTables(FSReader); // TODO: Convert this over to using ModuleSubstreamVisitor. while (!Data.empty()) { @@ -800,20 +817,20 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, printBinaryBlockWithRelocs("SubSectionContents", Section, SectionContents, Contents); - switch (ModuleSubstreamKind(SubType)) { - case ModuleSubstreamKind::Symbols: + switch (ModuleDebugFragmentKind(SubType)) { + case ModuleDebugFragmentKind::Symbols: printCodeViewSymbolsSubsection(Contents, Section, SectionContents); break; - case ModuleSubstreamKind::InlineeLines: + case ModuleDebugFragmentKind::InlineeLines: printCodeViewInlineeLines(Contents); break; - case ModuleSubstreamKind::FileChecksums: + case ModuleDebugFragmentKind::FileChecksums: printCodeViewFileChecksums(Contents); break; - case ModuleSubstreamKind::Lines: { + case ModuleDebugFragmentKind::Lines: { // Holds a PC to file:line table. Some data to parse this subsection is // stored in the other subsections, so just check sanity and store the // pointers for deferred processing. @@ -839,7 +856,7 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, FunctionNames.push_back(LinkageName); break; } - case ModuleSubstreamKind::FrameData: { + case ModuleDebugFragmentKind::FrameData: { // First four bytes is a relocation against the function. BinaryByteStream S(Contents, llvm::support::little); BinaryStreamReader SR(S); @@ -856,11 +873,7 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, const FrameData *FD; error(SR.readObject(FD)); - if (FD->FrameFunc >= CVStringTable.size()) - error(object_error::parse_failed); - - StringRef FrameFunc = - CVStringTable.drop_front(FD->FrameFunc).split('\0').first; + StringRef FrameFunc = error(CVStringTable.getString(FD->FrameFunc)); DictScope S(W, "FrameData"); W.printHex("RvaStart", FD->RvaStart); @@ -890,45 +903,29 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, ListScope S(W, "FunctionLineTable"); W.printString("LinkageName", Name); - DataExtractor DE(FunctionLineTables[Name], true, 4); - uint32_t Offset = 6; // Skip relocations. - uint16_t Flags = DE.getU16(&Offset); - W.printHex("Flags", Flags); - bool HasColumnInformation = Flags & codeview::LineFlags::HaveColumns; - uint32_t FunctionSize = DE.getU32(&Offset); - W.printHex("CodeSize", FunctionSize); - while (DE.isValidOffset(Offset)) { - // For each range of lines with the same filename, we have a segment - // in the line table. The filename string is accessed using double - // indirection to the string table subsection using the index subsection. - uint32_t OffsetInIndex = DE.getU32(&Offset), - NumLines = DE.getU32(&Offset), - FullSegmentSize = DE.getU32(&Offset); - - uint32_t ColumnOffset = Offset + 8 * NumLines; - DataExtractor ColumnDE(DE.getData(), true, 4); - - if (FullSegmentSize != - 12 + 8 * NumLines + (HasColumnInformation ? 4 * NumLines : 0)) { - error(object_error::parse_failed); - return; - } + BinaryByteStream LineTableInfo(FunctionLineTables[Name], support::little); + BinaryStreamReader Reader(LineTableInfo); + + ModuleDebugLineFragmentRef LineInfo; + error(LineInfo.initialize(Reader)); + + W.printHex("Flags", LineInfo.header()->Flags); + W.printHex("CodeSize", LineInfo.header()->CodeSize); + for (const auto &Entry : LineInfo) { ListScope S(W, "FilenameSegment"); - printFileNameForOffset("Filename", OffsetInIndex); - for (unsigned LineIdx = 0; - LineIdx != NumLines && DE.isValidOffset(Offset); ++LineIdx) { - // Then go the (PC, LineNumber) pairs. The line number is stored in the - // least significant 31 bits of the respective word in the table. - uint32_t PC = DE.getU32(&Offset), LineData = DE.getU32(&Offset); - if (PC >= FunctionSize) { + printFileNameForOffset("Filename", Entry.NameIndex); + uint32_t ColumnIndex = 0; + for (const auto &Line : Entry.LineNumbers) { + if (Line.Offset >= LineInfo.header()->CodeSize) { error(object_error::parse_failed); return; } - char Buffer[32]; - format("+0x%X", PC).snprint(Buffer, 32); - ListScope PCScope(W, Buffer); - LineInfo LI(LineData); + + std::string PC = formatv("+{0:X}", uint32_t(Line.Offset)); + ListScope PCScope(W, PC); + codeview::LineInfo LI(Line.Flags); + if (LI.isAlwaysStepInto()) W.printString("StepInto", StringRef("Always")); else if (LI.isNeverStepInto()) @@ -937,19 +934,10 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, W.printNumber("LineNumberStart", LI.getStartLine()); W.printNumber("LineNumberEndDelta", LI.getLineDelta()); W.printBoolean("IsStatement", LI.isStatement()); - if (HasColumnInformation && - ColumnDE.isValidOffsetForDataOfSize(ColumnOffset, 4)) { - uint16_t ColStart = ColumnDE.getU16(&ColumnOffset); - W.printNumber("ColStart", ColStart); - uint16_t ColEnd = ColumnDE.getU16(&ColumnOffset); - W.printNumber("ColEnd", ColEnd); - } - } - // Skip over the column data. - if (HasColumnInformation) { - for (unsigned LineIdx = 0; - LineIdx != NumLines && DE.isValidOffset(Offset); ++LineIdx) { - DE.getU32(&Offset); + if (LineInfo.hasColumnInfo()) { + W.printNumber("ColStart", Entry.Columns[ColumnIndex].StartColumn); + W.printNumber("ColEnd", Entry.Columns[ColumnIndex].EndColumn); + ++ColumnIndex; } } } @@ -985,56 +973,39 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) { BinaryByteStream S(Subsection, llvm::support::little); BinaryStreamReader SR(S); - while (!SR.empty()) { + ModuleDebugFileChecksumFragmentRef Checksums; + error(Checksums.initialize(SR)); + + for (auto &FC : Checksums) { DictScope S(W, "FileChecksum"); - const FileChecksum *FC; - error(SR.readObject(FC)); - if (FC->FileNameOffset >= CVStringTable.size()) - error(object_error::parse_failed); - StringRef Filename = - CVStringTable.drop_front(FC->FileNameOffset).split('\0').first; - W.printHex("Filename", Filename, FC->FileNameOffset); - W.printHex("ChecksumSize", FC->ChecksumSize); - W.printEnum("ChecksumKind", uint8_t(FC->ChecksumKind), + + StringRef Filename = error(CVStringTable.getString(FC.FileNameOffset)); + W.printHex("Filename", Filename, FC.FileNameOffset); + W.printHex("ChecksumSize", FC.Checksum.size()); + W.printEnum("ChecksumKind", uint8_t(FC.Kind), makeArrayRef(FileChecksumKindNames)); - if (FC->ChecksumSize >= SR.bytesRemaining()) - error(object_error::parse_failed); - ArrayRef<uint8_t> ChecksumBytes; - error(SR.readBytes(ChecksumBytes, FC->ChecksumSize)); - W.printBinary("ChecksumBytes", ChecksumBytes); - unsigned PaddedSize = alignTo(FC->ChecksumSize + sizeof(FileChecksum), 4) - - sizeof(FileChecksum); - PaddedSize -= ChecksumBytes.size(); - if (PaddedSize > SR.bytesRemaining()) - error(object_error::parse_failed); - error(SR.skip(PaddedSize)); + + W.printBinary("ChecksumBytes", FC.Checksum); } } void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { BinaryByteStream S(Subsection, llvm::support::little); BinaryStreamReader SR(S); - uint32_t Signature; - error(SR.readInteger(Signature)); - bool HasExtraFiles = Signature == unsigned(InlineeLinesSignature::ExtraFiles); + ModuleDebugInlineeLineFragmentRef Lines; + error(Lines.initialize(SR)); - while (!SR.empty()) { - const InlineeSourceLine *ISL; - error(SR.readObject(ISL)); + for (auto &Line : Lines) { DictScope S(W, "InlineeSourceLine"); - printTypeIndex("Inlinee", ISL->Inlinee); - printFileNameForOffset("FileID", ISL->FileID); - W.printNumber("SourceLineNum", ISL->SourceLineNum); - - if (HasExtraFiles) { - uint32_t ExtraFileCount; - error(SR.readInteger(ExtraFileCount)); - W.printNumber("ExtraFileCount", ExtraFileCount); + printTypeIndex("Inlinee", Line.Header->Inlinee); + printFileNameForOffset("FileID", Line.Header->FileID); + W.printNumber("SourceLineNum", Line.Header->SourceLineNum); + + if (Lines.hasExtraFiles()) { + W.printNumber("ExtraFileCount", Line.ExtraFiles.size()); ListScope ExtraFiles(W, "ExtraFiles"); - for (unsigned I = 0; I < ExtraFileCount; ++I) { - uint32_t FileID; - error(SR.readInteger(FileID)); - printFileNameForOffset("FileID", FileID); + for (const auto &FID : Line.ExtraFiles) { + printFileNameForOffset("FileID", FID); } } } @@ -1042,23 +1013,16 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) { // The file checksum subsection should precede all references to it. - if (!CVFileChecksumTable.data() || !CVStringTable.data()) - error(object_error::parse_failed); - // Check if the file checksum table offset is valid. - if (FileOffset >= CVFileChecksumTable.size()) + if (!CVFileChecksumTable.valid() || !CVStringTable.valid()) error(object_error::parse_failed); - // The string table offset comes first before the file checksum. - StringRef Data = CVFileChecksumTable.drop_front(FileOffset); - uint32_t StringOffset; - error(consume(Data, StringOffset)); + auto Iter = CVFileChecksumTable.at(FileOffset); - // Check if the string table offset is valid. - if (StringOffset >= CVStringTable.size()) + // Check if the file checksum table offset is valid. + if (Iter == CVFileChecksumTable.end()) error(object_error::parse_failed); - // Return the null-terminated string. - return CVStringTable.drop_front(StringOffset).split('\0').first; + return error(CVStringTable.getString(Iter->FileNameOffset)); } void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) { @@ -1527,6 +1491,30 @@ void COFFDumper::printCOFFBaseReloc() { } } +void COFFDumper::printCOFFResources() { + ListScope ResourcesD(W, "Resources"); + for (const SectionRef &S : Obj->sections()) { + StringRef Name; + error(S.getName(Name)); + if (!Name.startswith(".rsrc")) + continue; + + StringRef Ref; + error(S.getContents(Ref)); + + if ((Name == ".rsrc") || (Name == ".rsrc$01")) { + auto Table = + reinterpret_cast<const coff_resource_dir_table *>(Ref.data()); + char FormattedTime[20]; + time_t TDS = time_t(Table->TimeDateStamp); + strftime(FormattedTime, sizeof(FormattedTime), "%Y-%m-%d %H:%M:%S", + gmtime(&TDS)); + W.printHex("Time/Date Stamp", FormattedTime, Table->TimeDateStamp); + } + W.printBinaryBlock(Name.str() + " Data", Ref); + } +} + void COFFDumper::printStackMap() const { object::SectionRef StackMapSection; for (auto Sec : Obj->sections()) { diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp index 7893eea5d220..2e9e01d9642b 100644 --- a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -983,57 +983,6 @@ static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = { { "AMDGPU_HSA_METADATA", ELF::STT_AMDGPU_HSA_METADATA } }; -static const char *getElfSectionType(unsigned Arch, unsigned Type) { - switch (Arch) { - case ELF::EM_ARM: - switch (Type) { - LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION); - } - case ELF::EM_HEXAGON: - switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); } - case ELF::EM_X86_64: - switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); } - case ELF::EM_MIPS: - case ELF::EM_MIPS_RS3_LE: - switch (Type) { - LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_DWARF); - } - } - - switch (Type) { - LLVM_READOBJ_ENUM_CASE(ELF, SHT_NULL ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_PROGBITS ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_STRTAB ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_RELA ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_HASH ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNAMIC ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOTE ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOBITS ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_REL ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_SHLIB ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNSYM ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_INIT_ARRAY ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_FINI_ARRAY ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_PREINIT_ARRAY ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_GROUP ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_HASH ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verdef ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verneed ); - LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_versym ); - default: return ""; - } -} - static const char *getGroupType(uint32_t Flag) { if (Flag & ELF::GRP_COMDAT) return "COMDAT"; @@ -3635,9 +3584,10 @@ template <class ELFT> void LLVMStyle<ELFT>::printSections(const ELFO *Obj) { DictScope SectionD(W, "Section"); W.printNumber("Index", SectionIndex); W.printNumber("Name", Name, Sec.sh_name); - W.printHex("Type", - getElfSectionType(Obj->getHeader()->e_machine, Sec.sh_type), - Sec.sh_type); + W.printHex( + "Type", + object::getELFSectionTypeName(Obj->getHeader()->e_machine, Sec.sh_type), + Sec.sh_type); std::vector<EnumEntry<unsigned>> SectionFlags(std::begin(ElfSectionFlags), std::end(ElfSectionFlags)); switch (Obj->getHeader()->e_machine) { diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h index ff780dae5784..48f825c527c1 100644 --- a/contrib/llvm/tools/llvm-readobj/ObjDumper.h +++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h @@ -67,6 +67,7 @@ public: virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } virtual void printCOFFDebugDirectory() { } + virtual void printCOFFResources() {} virtual void printCodeViewDebugInfo() { } virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs, llvm::codeview::TypeTableBuilder &CVTypes) {} diff --git a/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp b/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp index e27da3b96e5d..21614297e467 100644 --- a/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp @@ -81,17 +81,30 @@ void WasmDumper::printRelocation(const SectionRef &Section, Reloc.getTypeName(RelocTypeName); const wasm::WasmRelocation &WasmReloc = Obj->getWasmRelocation(Reloc); + bool HasAddend = false; + switch (RelocType) { + case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: + HasAddend = true; + break; + default: + break; + } if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); W.printNumber("Type", RelocTypeName, RelocType); W.printHex("Offset", Reloc.getOffset()); W.printHex("Index", WasmReloc.Index); - W.printHex("Addend", WasmReloc.Addend); + if (HasAddend) + W.printNumber("Addend", WasmReloc.Addend); } else { raw_ostream& OS = W.startLine(); OS << W.hex(Reloc.getOffset()) - << " " << RelocTypeName << "[" << WasmReloc.Index << "]" - << " " << W.hex(WasmReloc.Addend) << "\n"; + << " " << RelocTypeName << "[" << WasmReloc.Index << "]"; + if (HasAddend) + OS << " " << WasmReloc.Addend; + OS << "\n"; } } @@ -137,8 +150,20 @@ void WasmDumper::printSections() { W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes)); W.printNumber("Size", (uint64_t)WasmSec.Content.size()); W.printNumber("Offset", WasmSec.Offset); - if (WasmSec.Type == wasm::WASM_SEC_CUSTOM) { + switch (WasmSec.Type) { + case wasm::WASM_SEC_CUSTOM: W.printString("Name", WasmSec.Name); + break; + case wasm::WASM_SEC_MEMORY: + ListScope Group(W, "Memories"); + for (const wasm::WasmLimits &Memory : Obj->memories()) { + DictScope Group(W, "Memory"); + W.printNumber("InitialPages", Memory.Initial); + if (Memory.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) { + W.printNumber("MaxPages", WasmSec.Offset); + } + } + break; } if (opts::SectionRelocations) { diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp index bc2a62e799ab..8a9d7bc720c3 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -214,6 +214,10 @@ namespace opts { COFFDebugDirectory("coff-debug-directory", cl::desc("Display the PE/COFF debug directory")); + // -coff-resources + cl::opt<bool> COFFResources("coff-resources", + cl::desc("Display the PE/COFF .rsrc section")); + // -macho-data-in-code cl::opt<bool> MachODataInCode("macho-data-in-code", @@ -445,6 +449,8 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printCOFFBaseReloc(); if (opts::COFFDebugDirectory) Dumper->printCOFFDebugDirectory(); + if (opts::COFFResources) + Dumper->printCOFFResources(); if (opts::CodeView) Dumper->printCodeViewDebugInfo(); if (opts::CodeViewMergedTypes) diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h index 015692085e5e..840ddbabdc59 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h @@ -25,6 +25,11 @@ namespace llvm { LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg); void error(std::error_code EC); void error(llvm::Error EC); + template <typename T> T error(llvm::Expected<T> &&E) { + error(E.takeError()); + return std::move(*E); + } + template <class T> T unwrapOrError(ErrorOr<T> EO) { if (EO) return *EO; diff --git a/contrib/llvm/tools/opt/BreakpointPrinter.cpp b/contrib/llvm/tools/opt/BreakpointPrinter.cpp index 33b3edcd1237..e5614ed061e3 100644 --- a/contrib/llvm/tools/opt/BreakpointPrinter.cpp +++ b/contrib/llvm/tools/opt/BreakpointPrinter.cpp @@ -51,7 +51,7 @@ struct BreakpointPrinter : public ModulePass { if (!SP) continue; getContextName(SP->getScope().resolve(), Name); - Name = Name + SP->getDisplayName().str(); + Name = Name + SP->getName().str(); if (!Name.empty() && Processed.insert(Name).second) { Out << Name << "\n"; } |