diff options
Diffstat (limited to 'contrib/llvm-project/clang')
69 files changed, 1952 insertions, 656 deletions
diff --git a/contrib/llvm-project/clang/include/clang/AST/DeclBase.h b/contrib/llvm-project/clang/include/clang/AST/DeclBase.h index 10dcbdb262d8..5b1038582bc6 100644 --- a/contrib/llvm-project/clang/include/clang/AST/DeclBase.h +++ b/contrib/llvm-project/clang/include/clang/AST/DeclBase.h @@ -19,6 +19,7 @@ #include "clang/AST/SelectorLocationsKind.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/ArrayRef.h" @@ -488,6 +489,15 @@ public: // Return true if this is a FileContext Decl. bool isFileContextDecl() const; + /// Whether it resembles a flexible array member. This is a static member + /// because we want to be able to call it with a nullptr. That allows us to + /// perform non-Decl specific checks based on the object's type and strict + /// flex array level. + static bool isFlexibleArrayMemberLike( + ASTContext &Context, const Decl *D, QualType Ty, + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel, + bool IgnoreTemplateOrMacroSubstitution); + ASTContext &getASTContext() const LLVM_READONLY; /// Helper to get the language options from the ASTContext. diff --git a/contrib/llvm-project/clang/include/clang/AST/DeclCXX.h b/contrib/llvm-project/clang/include/clang/AST/DeclCXX.h index 984a4d8bab5e..648f5f946408 100644 --- a/contrib/llvm-project/clang/include/clang/AST/DeclCXX.h +++ b/contrib/llvm-project/clang/include/clang/AST/DeclCXX.h @@ -1425,6 +1425,9 @@ public: /// (C++11 [class]p6). bool isTriviallyCopyable() const; + /// Determine whether this class is considered trivially copyable per + bool isTriviallyCopyConstructible() const; + /// Determine whether this class is considered trivial. /// /// C++11 [class]p6: diff --git a/contrib/llvm-project/clang/include/clang/AST/Stmt.h b/contrib/llvm-project/clang/include/clang/AST/Stmt.h index da7b37ce0e12..e1fde24e6477 100644 --- a/contrib/llvm-project/clang/include/clang/AST/Stmt.h +++ b/contrib/llvm-project/clang/include/clang/AST/Stmt.h @@ -1631,8 +1631,10 @@ public: SourceLocation RB); // Build an empty compound statement with a location. - explicit CompoundStmt(SourceLocation Loc) - : Stmt(CompoundStmtClass), LBraceLoc(Loc), RBraceLoc(Loc) { + explicit CompoundStmt(SourceLocation Loc) : CompoundStmt(Loc, Loc) {} + + CompoundStmt(SourceLocation Loc, SourceLocation EndLoc) + : Stmt(CompoundStmtClass), LBraceLoc(Loc), RBraceLoc(EndLoc) { CompoundStmtBits.NumStmts = 0; CompoundStmtBits.HasFPFeatures = 0; } diff --git a/contrib/llvm-project/clang/include/clang/AST/Type.h b/contrib/llvm-project/clang/include/clang/AST/Type.h index 9e9f896ebef7..d4e5310fb3ab 100644 --- a/contrib/llvm-project/clang/include/clang/AST/Type.h +++ b/contrib/llvm-project/clang/include/clang/AST/Type.h @@ -917,6 +917,9 @@ public: /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) bool isTriviallyCopyableType(const ASTContext &Context) const; + /// Return true if this is a trivially copyable type + bool isTriviallyCopyConstructibleType(const ASTContext &Context) const; + /// Return true if this is a trivially relocatable type. bool isTriviallyRelocatableType(const ASTContext &Context) const; diff --git a/contrib/llvm-project/clang/include/clang/Basic/Attr.td b/contrib/llvm-project/clang/include/clang/Basic/Attr.td index d5eabaad4889..a03b0e44e15f 100644 --- a/contrib/llvm-project/clang/include/clang/Basic/Attr.td +++ b/contrib/llvm-project/clang/include/clang/Basic/Attr.td @@ -4372,3 +4372,21 @@ def CodeAlign: StmtAttr { static constexpr int MaximumAlignment = 4096; }]; } + +def CountedBy : InheritableAttr { + let Spellings = [Clang<"counted_by">]; + let Subjects = SubjectList<[Field]>; + let Args = [IdentifierArgument<"CountedByField">]; + let Documentation = [CountedByDocs]; + let LangOpts = [COnly]; + // FIXME: This is ugly. Let using a DeclArgument would be nice, but a Decl + // isn't yet available due to the fact that we're still parsing the + // structure. Maybe that code could be changed sometime in the future. + code AdditionalMembers = [{ + private: + SourceRange CountedByFieldLoc; + public: + SourceRange getCountedByFieldLoc() const { return CountedByFieldLoc; } + void setCountedByFieldLoc(SourceRange Loc) { CountedByFieldLoc = Loc; } + }]; +} diff --git a/contrib/llvm-project/clang/include/clang/Basic/AttrDocs.td b/contrib/llvm-project/clang/include/clang/Basic/AttrDocs.td index 5416a0cbdd07..2e8d7752c975 100644 --- a/contrib/llvm-project/clang/include/clang/Basic/AttrDocs.td +++ b/contrib/llvm-project/clang/include/clang/Basic/AttrDocs.td @@ -7749,3 +7749,81 @@ but do not pass them to the underlying coroutine or pass them by value. .. _`CRT`: https://clang.llvm.org/docs/AttributeReference.html#coro-return-type }]; } + +def CountedByDocs : Documentation { + let Category = DocCatField; + let Content = [{ +Clang supports the ``counted_by`` attribute on the flexible array member of a +structure in C. The argument for the attribute is the name of a field member +holding the count of elements in the flexible array. This information can be +used to improve the results of the array bound sanitizer and the +``__builtin_dynamic_object_size`` builtin. The ``count`` field member must be +within the same non-anonymous, enclosing struct as the flexible array member. + +This example specifies that the flexible array member ``array`` has the number +of elements allocated for it in ``count``: + +.. code-block:: c + + struct bar; + + struct foo { + size_t count; + char other; + struct bar *array[] __attribute__((counted_by(count))); + }; + +This establishes a relationship between ``array`` and ``count``. Specifically, +``array`` must have at least ``count`` number of elements available. It's the +user's responsibility to ensure that this relationship is maintained through +changes to the structure. + +In the following example, the allocated array erroneously has fewer elements +than what's specified by ``p->count``. This would result in an out-of-bounds +access not being detected. + +.. code-block:: c + + #define SIZE_INCR 42 + + struct foo *p; + + void foo_alloc(size_t count) { + p = malloc(MAX(sizeof(struct foo), + offsetof(struct foo, array[0]) + count * sizeof(struct bar *))); + p->count = count + SIZE_INCR; + } + +The next example updates ``p->count``, but breaks the relationship requirement +that ``p->array`` must have at least ``p->count`` number of elements available: + +.. code-block:: c + + #define SIZE_INCR 42 + + struct foo *p; + + void foo_alloc(size_t count) { + p = malloc(MAX(sizeof(struct foo), + offsetof(struct foo, array[0]) + count * sizeof(struct bar *))); + p->count = count; + } + + void use_foo(int index, int val) { + p->count += SIZE_INCR + 1; /* 'count' is now larger than the number of elements of 'array'. */ + p->array[index] = val; /* The sanitizer can't properly check this access. */ + } + +In this example, an update to ``p->count`` maintains the relationship +requirement: + +.. code-block:: c + + void use_foo(int index, int val) { + if (p->count == 0) + return; + --p->count; + p->array[index] = val; + } + }]; +} diff --git a/contrib/llvm-project/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/contrib/llvm-project/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 568000106a84..85ecfdf9de62 100644 --- a/contrib/llvm-project/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/contrib/llvm-project/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -167,7 +167,7 @@ def err_verify_no_such_marker : Error< def err_verify_missing_start : Error< "cannot find start ('{{') of expected %0">; def err_verify_missing_end : Error< - "cannot find end ('}}') of expected %0">; + "cannot find end ('%1') of expected %0">; def err_verify_invalid_content : Error< "invalid expected %0: %1">; def err_verify_missing_regex : Error< diff --git a/contrib/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td b/contrib/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td index e81d1a4fc288..e46779349475 100644 --- a/contrib/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/contrib/llvm-project/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2253,6 +2253,8 @@ def warn_cxx17_compat_aggregate_init_paren_list : Warning< def err_reference_bind_to_bitfield : Error< "%select{non-const|volatile}0 reference cannot bind to " "bit-field%select{| %1}2">; +def err_reference_bind_to_bitfield_in_cce : Error< + "reference cannot bind to bit-field in converted constant expression">; def err_reference_bind_to_vector_element : Error< "%select{non-const|volatile}0 reference cannot bind to vector element">; def err_reference_bind_to_matrix_element : Error< @@ -6439,6 +6441,19 @@ def warn_superclass_variable_sized_type_not_at_end : Warning< "field %0 can overwrite instance variable %1 with variable sized type %2" " in superclass %3">, InGroup<ObjCFlexibleArray>; +def err_flexible_array_count_not_in_same_struct : Error< + "'counted_by' field %0 isn't within the same struct as the flexible array">; +def err_counted_by_attr_not_on_flexible_array_member : Error< + "'counted_by' only applies to C99 flexible array members">; +def err_counted_by_attr_refers_to_flexible_array : Error< + "'counted_by' cannot refer to the flexible array %0">; +def err_counted_by_must_be_in_structure : Error< + "field %0 in 'counted_by' not inside structure">; +def err_flexible_array_counted_by_attr_field_not_integer : Error< + "field %0 in 'counted_by' must be a non-boolean integer type">; +def note_flexible_array_counted_by_attr_field : Note< + "field %0 declared here">; + let CategoryName = "ARC Semantic Issue" in { // ARC-mode diagnostics. diff --git a/contrib/llvm-project/clang/include/clang/Basic/LangOptions.def b/contrib/llvm-project/clang/include/clang/Basic/LangOptions.def index 21abc346cf17..0428b70c6020 100644 --- a/contrib/llvm-project/clang/include/clang/Basic/LangOptions.def +++ b/contrib/llvm-project/clang/include/clang/Basic/LangOptions.def @@ -457,6 +457,7 @@ ENUM_LANGOPT(SignReturnAddressKey, SignReturnAddressKeyKind, 1, SignReturnAddres "Key used for return address signing") LANGOPT(BranchTargetEnforcement, 1, 0, "Branch-target enforcement enabled") LANGOPT(BranchProtectionPAuthLR, 1, 0, "Use PC as a diversifier using PAuthLR NOP instructions.") +LANGOPT(GuardedControlStack, 1, 0, "Guarded control stack enabled") LANGOPT(SpeculativeLoadHardening, 1, 0, "Speculative load hardening enabled") diff --git a/contrib/llvm-project/clang/include/clang/Basic/TargetInfo.h b/contrib/llvm-project/clang/include/clang/Basic/TargetInfo.h index ac3c324c6c29..3eb23ebdacf0 100644 --- a/contrib/llvm-project/clang/include/clang/Basic/TargetInfo.h +++ b/contrib/llvm-project/clang/include/clang/Basic/TargetInfo.h @@ -1373,6 +1373,7 @@ public: LangOptions::SignReturnAddressKeyKind::AKey; bool BranchTargetEnforcement = false; bool BranchProtectionPAuthLR = false; + bool GuardedControlStack = false; }; /// Determine if the Architecture in this TargetInfo supports branch diff --git a/contrib/llvm-project/clang/include/clang/Basic/arm_sve.td b/contrib/llvm-project/clang/include/clang/Basic/arm_sve.td index 7f80fb0386cc..6f35e25617ad 100644 --- a/contrib/llvm-project/clang/include/clang/Basic/arm_sve.td +++ b/contrib/llvm-project/clang/include/clang/Basic/arm_sve.td @@ -454,11 +454,11 @@ let TargetGuard = "sve,bf16" in { let TargetGuard = "sve2p1" in { // Contiguous truncating store from quadword (single vector). - def SVST1UWQ : MInst<"svst1uwq[_{d}]", "vPcd", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1uwq">; - def SVST1UWQ_VNUM : MInst<"svst1uwq_vnum[_{d}]", "vPcld", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1uwq">; + def SVST1UWQ : MInst<"svst1wq[_{d}]", "vPcd", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1wq">; + def SVST1UWQ_VNUM : MInst<"svst1wq_vnum[_{d}]", "vPcld", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1wq">; - def SVST1UDQ : MInst<"svst1udq[_{d}]", "vPcd", "lUld", [IsStore], MemEltTyInt64, "aarch64_sve_st1udq">; - def SVST1UDQ_VNUM : MInst<"svst1udq_vnum[_{d}]", "vPcld", "lUld", [IsStore], MemEltTyInt64, "aarch64_sve_st1udq">; + def SVST1UDQ : MInst<"svst1dq[_{d}]", "vPcd", "lUld", [IsStore], MemEltTyInt64, "aarch64_sve_st1dq">; + def SVST1UDQ_VNUM : MInst<"svst1dq_vnum[_{d}]", "vPcld", "lUld", [IsStore], MemEltTyInt64, "aarch64_sve_st1dq">; // Store one vector (vector base + scalar offset) def SVST1Q_SCATTER_U64BASE_OFFSET : MInst<"svst1q_scatter[_{2}base]_offset[_{d}]", "vPgld", "cUcsUsiUilUlfhdb", [IsScatterStore, IsByteIndexed], MemEltTyDefault, "aarch64_sve_st1q_scatter_scalar_offset">; @@ -2040,12 +2040,12 @@ let TargetGuard = "sve2p1|sme2" in { } let TargetGuard = "sve2p1" in { -def SVDOT_X2_S : SInst<"svdot[_{d}_{2}_{3}]", "ddhh", "i", MergeNone, "aarch64_sve_sdot_x2", [], []>; -def SVDOT_X2_U : SInst<"svdot[_{d}_{2}_{3}]", "ddhh", "Ui", MergeNone, "aarch64_sve_udot_x2", [], []>; -def SVDOT_X2_F : SInst<"svdot[_{d}_{2}_{3}]", "ddhh", "f", MergeNone, "aarch64_sve_fdot_x2", [], []>; -def SVDOT_LANE_X2_S : SInst<"svdot_lane[_{d}_{2}_{3}]", "ddhhi", "i", MergeNone, "aarch64_sve_sdot_lane_x2", [], [ImmCheck<3, ImmCheck0_3>]>; -def SVDOT_LANE_X2_U : SInst<"svdot_lane[_{d}_{2}_{3}]", "ddhhi", "Ui", MergeNone, "aarch64_sve_udot_lane_x2", [], [ImmCheck<3, ImmCheck0_3>]>; -def SVDOT_LANE_X2_F : SInst<"svdot_lane[_{d}_{2}_{3}]", "ddhhi", "f", MergeNone, "aarch64_sve_fdot_lane_x2", [], [ImmCheck<3, ImmCheck0_3>]>; +def SVDOT_X2_S : SInst<"svdot[_{d}_{2}]", "ddhh", "i", MergeNone, "aarch64_sve_sdot_x2", [], []>; +def SVDOT_X2_U : SInst<"svdot[_{d}_{2}]", "ddhh", "Ui", MergeNone, "aarch64_sve_udot_x2", [], []>; +def SVDOT_X2_F : SInst<"svdot[_{d}_{2}]", "ddhh", "f", MergeNone, "aarch64_sve_fdot_x2", [], []>; +def SVDOT_LANE_X2_S : SInst<"svdot_lane[_{d}_{2}]", "ddhhi", "i", MergeNone, "aarch64_sve_sdot_lane_x2", [], [ImmCheck<3, ImmCheck0_3>]>; +def SVDOT_LANE_X2_U : SInst<"svdot_lane[_{d}_{2}]", "ddhhi", "Ui", MergeNone, "aarch64_sve_udot_lane_x2", [], [ImmCheck<3, ImmCheck0_3>]>; +def SVDOT_LANE_X2_F : SInst<"svdot_lane[_{d}_{2}]", "ddhhi", "f", MergeNone, "aarch64_sve_fdot_lane_x2", [], [ImmCheck<3, ImmCheck0_3>]>; } let TargetGuard = "sve2p1|sme2" in { @@ -2208,7 +2208,7 @@ let TargetGuard = "sve2p1" in { def SVTBLQ : SInst<"svtblq[_{d}]", "ddu", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_tblq">; def SVTBXQ : SInst<"svtbxq[_{d}]", "dddu", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_tbxq">; // EXTQ - def EXTQ : SInst<"svextq_lane[_{d}]", "dddk", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_extq_lane", [], [ImmCheck<2, ImmCheck0_15>]>; + def EXTQ : SInst<"svextq[_{d}]", "dddk", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_extq", [], [ImmCheck<2, ImmCheck0_15>]>; // PMOV // Move to Pred multiclass PMOV_TO_PRED<string name, string types, string intrinsic, list<FlagType> flags=[], ImmCheckType immCh > { diff --git a/contrib/llvm-project/clang/include/clang/Driver/Options.td b/contrib/llvm-project/clang/include/clang/Driver/Options.td index 84648c6d5500..7f97d6b6faa3 100644 --- a/contrib/llvm-project/clang/include/clang/Driver/Options.td +++ b/contrib/llvm-project/clang/include/clang/Driver/Options.td @@ -4267,7 +4267,7 @@ def iquote : JoinedOrSeparate<["-"], "iquote">, Group<clang_i_Group>, Visibility<[ClangOption, CC1Option]>, HelpText<"Add directory to QUOTE include search path">, MetaVarName<"<directory>">; def isysroot : JoinedOrSeparate<["-"], "isysroot">, Group<clang_i_Group>, - Visibility<[ClangOption, CC1Option]>, + Visibility<[ClangOption, CC1Option, FlangOption]>, HelpText<"Set the system root directory (usually /)">, MetaVarName<"<dir>">, MarshallingInfoString<HeaderSearchOpts<"Sysroot">, [{"/"}]>; def isystem : JoinedOrSeparate<["-"], "isystem">, Group<clang_i_Group>, @@ -4585,11 +4585,13 @@ let Flags = [TargetSpecific] in { def menable_experimental_extensions : Flag<["-"], "menable-experimental-extensions">, Group<m_Group>, HelpText<"Enable use of experimental RISC-V extensions.">; def mrvv_vector_bits_EQ : Joined<["-"], "mrvv-vector-bits=">, Group<m_Group>, - HelpText<"Specify the size in bits of an RVV vector register. Defaults to " - "the vector length agnostic value of \"scalable\". Accepts power of " - "2 values between 64 and 65536. Also accepts \"zvl\" " - "to use the value implied by -march/-mcpu. Value will be reflected " - "in __riscv_v_fixed_vlen preprocessor define (RISC-V only)">; + Visibility<[ClangOption, FlangOption]>, + HelpText<"Specify the size in bits of an RVV vector register">, + DocBrief<"Defaults to the vector length agnostic value of \"scalable\". " + "Accepts power of 2 values between 64 and 65536. Also accepts " + "\"zvl\" to use the value implied by -march/-mcpu. On Clang, value " + "will be reflected in __riscv_v_fixed_vlen preprocessor define " + "(RISC-V only)">; def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_Group>, HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64/LoongArch/RISC-V only)">; @@ -5197,7 +5199,7 @@ def nohipwrapperinc : Flag<["-"], "nohipwrapperinc">, Group<IncludePath_Group>, HelpText<"Do not include the default HIP wrapper headers and include paths">; def : Flag<["-"], "nocudainc">, Alias<nogpuinc>; def nogpulib : Flag<["-"], "nogpulib">, MarshallingInfoFlag<LangOpts<"NoGPULib">>, - Visibility<[ClangOption, CC1Option]>, + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, HelpText<"Do not link device library for CUDA/HIP device compilation">; def : Flag<["-"], "nocudalib">, Alias<nogpulib>; def gpulibc : Flag<["-"], "gpulibc">, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, @@ -7010,6 +7012,8 @@ def mbranch_target_enforce : Flag<["-"], "mbranch-target-enforce">, MarshallingInfoFlag<LangOpts<"BranchTargetEnforcement">>; def mbranch_protection_pauth_lr : Flag<["-"], "mbranch-protection-pauth-lr">, MarshallingInfoFlag<LangOpts<"BranchProtectionPAuthLR">>; +def mguarded_control_stack : Flag<["-"], "mguarded-control-stack">, + MarshallingInfoFlag<LangOpts<"GuardedControlStack">>; def fno_dllexport_inlines : Flag<["-"], "fno-dllexport-inlines">, MarshallingInfoNegativeFlag<LangOpts<"DllExportInlines">>; def cfguard_no_checks : Flag<["-"], "cfguard-no-checks">, diff --git a/contrib/llvm-project/clang/include/clang/Format/Format.h b/contrib/llvm-project/clang/include/clang/Format/Format.h index 8604dea689f9..59b645ecab71 100755 --- a/contrib/llvm-project/clang/include/clang/Format/Format.h +++ b/contrib/llvm-project/clang/include/clang/Format/Format.h @@ -225,6 +225,22 @@ struct FormatStyle { /// bbb = 2; /// \endcode bool AlignCompound; + /// Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + /// aligned. + /// \code + /// true: + /// unsigned i; + /// int &r; + /// int *p; + /// int (*f)(); + /// + /// false: + /// unsigned i; + /// int &r; + /// int *p; + /// int (*f)(); + /// \endcode + bool AlignFunctionPointers; /// Only for ``AlignConsecutiveAssignments``. Whether short assignment /// operators are left-padded to the same length as long ones in order to /// put all assignment operators to the right of the left hand side. @@ -247,7 +263,9 @@ struct FormatStyle { bool operator==(const AlignConsecutiveStyle &R) const { return Enabled == R.Enabled && AcrossEmptyLines == R.AcrossEmptyLines && AcrossComments == R.AcrossComments && - AlignCompound == R.AlignCompound && PadOperators == R.PadOperators; + AlignCompound == R.AlignCompound && + AlignFunctionPointers == R.AlignFunctionPointers && + PadOperators == R.PadOperators; } bool operator!=(const AlignConsecutiveStyle &R) const { return !(*this == R); diff --git a/contrib/llvm-project/clang/include/clang/Parse/Parser.h b/contrib/llvm-project/clang/include/clang/Parse/Parser.h index 2dbe090bd093..186dbb770858 100644 --- a/contrib/llvm-project/clang/include/clang/Parse/Parser.h +++ b/contrib/llvm-project/clang/include/clang/Parse/Parser.h @@ -234,6 +234,26 @@ class Parser : public CodeCompletionHandler { /// Parsing OpenACC directive mode. bool OpenACCDirectiveParsing = false; + /// Currently parsing a situation where an OpenACC array section could be + /// legal, such as a 'var-list'. + bool AllowOpenACCArraySections = false; + + /// RAII object to set reset OpenACC parsing a context where Array Sections + /// are allowed. + class OpenACCArraySectionRAII { + Parser &P; + + public: + OpenACCArraySectionRAII(Parser &P) : P(P) { + assert(!P.AllowOpenACCArraySections); + P.AllowOpenACCArraySections = true; + } + ~OpenACCArraySectionRAII() { + assert(P.AllowOpenACCArraySections); + P.AllowOpenACCArraySections = false; + } + }; + /// When true, we are directly inside an Objective-C message /// send expression. /// @@ -3546,8 +3566,8 @@ private: ExprResult ParseOpenACCIDExpression(); /// Parses the variable list for the `cache` construct. void ParseOpenACCCacheVarList(); - /// Parses a single variable in a variable list for the 'cache' construct. - bool ParseOpenACCCacheVar(); + /// Parses a single variable in a variable list for OpenACC. + bool ParseOpenACCVar(); bool ParseOpenACCWaitArgument(); private: diff --git a/contrib/llvm-project/clang/include/clang/Sema/Sema.h b/contrib/llvm-project/clang/include/clang/Sema/Sema.h index edaee4c4b66d..cf2d4fbe6d3b 100644 --- a/contrib/llvm-project/clang/include/clang/Sema/Sema.h +++ b/contrib/llvm-project/clang/include/clang/Sema/Sema.h @@ -4799,6 +4799,8 @@ public: bool CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt, const AttributeCommonInfo &A); + bool CheckCountedByAttr(Scope *Scope, const FieldDecl *FD); + /// Adjust the calling convention of a method to be the ABI default if it /// wasn't specified explicitly. This handles method types formed from /// function type typedefs and typename template arguments. @@ -5642,6 +5644,7 @@ public: CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, ArrayRef<Expr *> Args = std::nullopt, + DeclContext *LookupCtx = nullptr, TypoExpr **Out = nullptr); DeclResult LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S, diff --git a/contrib/llvm-project/clang/include/clang/Sema/TypoCorrection.h b/contrib/llvm-project/clang/include/clang/Sema/TypoCorrection.h index e0f8d152dbe5..09de164297e7 100644 --- a/contrib/llvm-project/clang/include/clang/Sema/TypoCorrection.h +++ b/contrib/llvm-project/clang/include/clang/Sema/TypoCorrection.h @@ -282,7 +282,7 @@ class CorrectionCandidateCallback { public: static const unsigned InvalidDistance = TypoCorrection::InvalidDistance; - explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr, + explicit CorrectionCandidateCallback(const IdentifierInfo *Typo = nullptr, NestedNameSpecifier *TypoNNS = nullptr) : Typo(Typo), TypoNNS(TypoNNS) {} @@ -319,7 +319,7 @@ public: /// this method. virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0; - void setTypoName(IdentifierInfo *II) { Typo = II; } + void setTypoName(const IdentifierInfo *II) { Typo = II; } void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; } // Flags for context-dependent keywords. WantFunctionLikeCasts is only @@ -345,13 +345,13 @@ protected: candidate.getCorrectionSpecifier() == TypoNNS; } - IdentifierInfo *Typo; + const IdentifierInfo *Typo; NestedNameSpecifier *TypoNNS; }; class DefaultFilterCCC final : public CorrectionCandidateCallback { public: - explicit DefaultFilterCCC(IdentifierInfo *Typo = nullptr, + explicit DefaultFilterCCC(const IdentifierInfo *Typo = nullptr, NestedNameSpecifier *TypoNNS = nullptr) : CorrectionCandidateCallback(Typo, TypoNNS) {} @@ -365,6 +365,10 @@ public: template <class C> class DeclFilterCCC final : public CorrectionCandidateCallback { public: + explicit DeclFilterCCC(const IdentifierInfo *Typo = nullptr, + NestedNameSpecifier *TypoNNS = nullptr) + : CorrectionCandidateCallback(Typo, TypoNNS) {} + bool ValidateCandidate(const TypoCorrection &candidate) override { return candidate.getCorrectionDeclAs<C>(); } diff --git a/contrib/llvm-project/clang/lib/AST/ASTContext.cpp b/contrib/llvm-project/clang/lib/AST/ASTContext.cpp index b60dcfaabfd1..d9cefcaa84d7 100644 --- a/contrib/llvm-project/clang/lib/AST/ASTContext.cpp +++ b/contrib/llvm-project/clang/lib/AST/ASTContext.cpp @@ -1318,6 +1318,13 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, InitBuiltinType(OMPArrayShapingTy, BuiltinType::OMPArrayShaping); InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator); } + // Placeholder type for OpenACC array sections. + if (LangOpts.OpenACC) { + // FIXME: Once we implement OpenACC array sections in Sema, this will either + // be combined with the OpenMP type, or given its own type. In the meantime, + // just use the OpenMP type so that parsing can work. + InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection); + } if (LangOpts.MatrixTypes) InitBuiltinType(IncompleteMatrixIdxTy, BuiltinType::IncompleteMatrixIdx); diff --git a/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp b/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp index 5e5570bb42a1..b762d6a4cd38 100644 --- a/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp +++ b/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp @@ -5929,15 +5929,22 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (ToD) return ToD; - bool IsFriendTemplate = D->getFriendObjectKind() != Decl::FOK_None; - bool IsDependentContext = DC != LexicalDC ? LexicalDC->isDependentContext() - : DC->isDependentContext(); - bool DependentFriend = IsFriendTemplate && IsDependentContext; + // Should check if a declaration is friend in a dependent context. + // Such templates are not linked together in a declaration chain. + // The ASTImporter strategy is to map existing forward declarations to + // imported ones only if strictly necessary, otherwise import these as new + // forward declarations. In case of the "dependent friend" declarations, new + // declarations are created, but not linked in a declaration chain. + auto IsDependentFriend = [](ClassTemplateDecl *TD) { + return TD->getFriendObjectKind() != Decl::FOK_None && + TD->getLexicalDeclContext()->isDependentContext(); + }; + bool DependentFriend = IsDependentFriend(D); ClassTemplateDecl *FoundByLookup = nullptr; // We may already have a template of the same name; try to find and match it. - if (!DependentFriend && !DC->isFunctionOrMethod()) { + if (!DC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { @@ -5953,10 +5960,13 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { // FIXME: sufficient conditon for 'IgnoreTemplateParmDepth'? bool IgnoreTemplateParmDepth = - FoundTemplate->getFriendObjectKind() != Decl::FOK_None && - !D->specializations().empty(); + (FoundTemplate->getFriendObjectKind() != Decl::FOK_None) != + (D->getFriendObjectKind() != Decl::FOK_None); if (IsStructuralMatch(D, FoundTemplate, /*Complain=*/true, IgnoreTemplateParmDepth)) { + if (DependentFriend || IsDependentFriend(FoundTemplate)) + continue; + ClassTemplateDecl *TemplateWithDef = getTemplateDefinition(FoundTemplate); if (D->isThisDeclarationADefinition() && TemplateWithDef) @@ -9030,6 +9040,10 @@ class AttrImporter { public: AttrImporter(ASTImporter &I) : Importer(I), NImporter(I) {} + // Useful for accessing the imported attribute. + template <typename T> T *castAttrAs() { return cast<T>(ToAttr); } + template <typename T> const T *castAttrAs() const { return cast<T>(ToAttr); } + // Create an "importer" for an attribute parameter. // Result of the 'value()' of that object is to be passed to the function // 'importAttr', in the order that is expected by the attribute class. @@ -9243,6 +9257,15 @@ Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) { From->args_size()); break; } + case attr::CountedBy: { + AI.cloneAttr(FromAttr); + const auto *CBA = cast<CountedByAttr>(FromAttr); + Expected<SourceRange> SR = Import(CBA->getCountedByFieldLoc()).get(); + if (!SR) + return SR.takeError(); + AI.castAttrAs<CountedByAttr>()->setCountedByFieldLoc(SR.get()); + break; + } default: { // The default branch works for attributes that have no arguments to import. diff --git a/contrib/llvm-project/clang/lib/AST/DeclBase.cpp b/contrib/llvm-project/clang/lib/AST/DeclBase.cpp index b1733c2d052a..8163f9bdaf8d 100644 --- a/contrib/llvm-project/clang/lib/AST/DeclBase.cpp +++ b/contrib/llvm-project/clang/lib/AST/DeclBase.cpp @@ -29,7 +29,6 @@ #include "clang/AST/Type.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" -#include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/PartialDiagnostic.h" @@ -411,6 +410,79 @@ bool Decl::isFileContextDecl() const { return DC && DC->isFileContext(); } +bool Decl::isFlexibleArrayMemberLike( + ASTContext &Ctx, const Decl *D, QualType Ty, + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel, + bool IgnoreTemplateOrMacroSubstitution) { + // For compatibility with existing code, we treat arrays of length 0 or + // 1 as flexible array members. + const auto *CAT = Ctx.getAsConstantArrayType(Ty); + if (CAT) { + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + + llvm::APInt Size = CAT->getSize(); + if (StrictFlexArraysLevel == FAMKind::IncompleteOnly) + return false; + + // GCC extension, only allowed to represent a FAM. + if (Size.isZero()) + return true; + + if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1)) + return false; + + if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2)) + return false; + } else if (!Ctx.getAsIncompleteArrayType(Ty)) { + return false; + } + + if (const auto *OID = dyn_cast_if_present<ObjCIvarDecl>(D)) + return OID->getNextIvar() == nullptr; + + const auto *FD = dyn_cast_if_present<FieldDecl>(D); + if (!FD) + return false; + + if (CAT) { + // GCC treats an array memeber of a union as an FAM if the size is one or + // zero. + llvm::APInt Size = CAT->getSize(); + if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne())) + return true; + } + + // Don't consider sizes resulting from macro expansions or template argument + // substitution to form C89 tail-padded arrays. + if (IgnoreTemplateOrMacroSubstitution) { + TypeSourceInfo *TInfo = FD->getTypeSourceInfo(); + while (TInfo) { + TypeLoc TL = TInfo->getTypeLoc(); + + // Look through typedefs. + if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) { + const TypedefNameDecl *TDL = TTL.getTypedefNameDecl(); + TInfo = TDL->getTypeSourceInfo(); + continue; + } + + if (auto CTL = TL.getAs<ConstantArrayTypeLoc>()) { + if (const Expr *SizeExpr = + dyn_cast_if_present<IntegerLiteral>(CTL.getSizeExpr()); + !SizeExpr || SizeExpr->getExprLoc().isMacroID()) + return false; + } + + break; + } + } + + // Test that the field is the last in the structure. + RecordDecl::field_iterator FI( + DeclContext::decl_iterator(const_cast<FieldDecl *>(FD))); + return ++FI == FD->getParent()->field_end(); +} + TranslationUnitDecl *Decl::getTranslationUnitDecl() { if (auto *TUD = dyn_cast<TranslationUnitDecl>(this)) return TUD; diff --git a/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp b/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp index c944862fcefe..98b0a6dc28ea 100644 --- a/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp +++ b/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp @@ -587,6 +587,19 @@ bool CXXRecordDecl::isTriviallyCopyable() const { return true; } +bool CXXRecordDecl::isTriviallyCopyConstructible() const { + + // A trivially copy constructible class is a class that: + // -- has no non-trivial copy constructors, + if (hasNonTrivialCopyConstructor()) + return false; + // -- has a trivial destructor. + if (!hasTrivialDestructor()) + return false; + + return true; +} + void CXXRecordDecl::markedVirtualFunctionPure() { // C++ [class.abstract]p2: // A class is abstract if it has at least one pure virtual function. diff --git a/contrib/llvm-project/clang/lib/AST/Expr.cpp b/contrib/llvm-project/clang/lib/AST/Expr.cpp index a90f92d07f86..b125fc676da8 100644 --- a/contrib/llvm-project/clang/lib/AST/Expr.cpp +++ b/contrib/llvm-project/clang/lib/AST/Expr.cpp @@ -205,85 +205,22 @@ bool Expr::isKnownToHaveBooleanValue(bool Semantic) const { } bool Expr::isFlexibleArrayMemberLike( - ASTContext &Context, + ASTContext &Ctx, LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel, bool IgnoreTemplateOrMacroSubstitution) const { - - // For compatibility with existing code, we treat arrays of length 0 or - // 1 as flexible array members. - const auto *CAT = Context.getAsConstantArrayType(getType()); - if (CAT) { - llvm::APInt Size = CAT->getSize(); - - using FAMKind = LangOptions::StrictFlexArraysLevelKind; - - if (StrictFlexArraysLevel == FAMKind::IncompleteOnly) - return false; - - // GCC extension, only allowed to represent a FAM. - if (Size == 0) - return true; - - if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1)) - return false; - - if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2)) - return false; - } else if (!Context.getAsIncompleteArrayType(getType())) - return false; - const Expr *E = IgnoreParens(); + const Decl *D = nullptr; - const NamedDecl *ND = nullptr; - if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) - ND = DRE->getDecl(); - else if (const auto *ME = dyn_cast<MemberExpr>(E)) - ND = ME->getMemberDecl(); + if (const auto *ME = dyn_cast<MemberExpr>(E)) + D = ME->getMemberDecl(); + else if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) + D = DRE->getDecl(); else if (const auto *IRE = dyn_cast<ObjCIvarRefExpr>(E)) - return IRE->getDecl()->getNextIvar() == nullptr; - - if (!ND) - return false; + D = IRE->getDecl(); - // A flexible array member must be the last member in the class. - // FIXME: If the base type of the member expr is not FD->getParent(), - // this should not be treated as a flexible array member access. - if (const auto *FD = dyn_cast<FieldDecl>(ND)) { - // GCC treats an array memeber of a union as an FAM if the size is one or - // zero. - if (CAT) { - llvm::APInt Size = CAT->getSize(); - if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne())) - return true; - } - - // Don't consider sizes resulting from macro expansions or template argument - // substitution to form C89 tail-padded arrays. - if (IgnoreTemplateOrMacroSubstitution) { - TypeSourceInfo *TInfo = FD->getTypeSourceInfo(); - while (TInfo) { - TypeLoc TL = TInfo->getTypeLoc(); - // Look through typedefs. - if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) { - const TypedefNameDecl *TDL = TTL.getTypedefNameDecl(); - TInfo = TDL->getTypeSourceInfo(); - continue; - } - if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) { - const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr()); - if (!SizeExpr || SizeExpr->getExprLoc().isMacroID()) - return false; - } - break; - } - } - - RecordDecl::field_iterator FI( - DeclContext::decl_iterator(const_cast<FieldDecl *>(FD))); - return ++FI == FD->getParent()->field_end(); - } - - return false; + return Decl::isFlexibleArrayMemberLike(Ctx, D, E->getType(), + StrictFlexArraysLevel, + IgnoreTemplateOrMacroSubstitution); } const ValueDecl * diff --git a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.cpp index e6b3097a80d8..7f8bbe787324 100644 --- a/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/contrib/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -114,6 +114,8 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { } case CK_FloatingCast: { + if (DiscardResult) + return this->discard(SubExpr); if (!this->visit(SubExpr)) return false; const auto *TargetSemantics = &Ctx.getFloatSemantics(CE->getType()); @@ -121,6 +123,8 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { } case CK_IntegralToFloating: { + if (DiscardResult) + return this->discard(SubExpr); std::optional<PrimType> FromT = classify(SubExpr->getType()); if (!FromT) return false; @@ -135,6 +139,9 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { case CK_FloatingToBoolean: case CK_FloatingToIntegral: { + if (DiscardResult) + return this->discard(SubExpr); + std::optional<PrimType> ToT = classify(CE->getType()); if (!ToT) diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp index 59a952135a2d..b330e54baf33 100644 --- a/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp +++ b/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.cpp @@ -275,8 +275,8 @@ Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD, } /// Unknown-size arrays of composite elements. -Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, - UnknownSize) +Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, + bool IsTemporary, UnknownSize) : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)), Size(UnknownSizeMark), MDSize(0), AllocSize(alignof(void *) + sizeof(InitMapPtr)), ElemDesc(Elem), @@ -286,7 +286,7 @@ Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, } /// Composite records. -Descriptor::Descriptor(const DeclTy &D, Record *R, MetadataSize MD, +Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst, bool IsTemporary, bool IsMutable) : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())), Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize), diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.h b/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.h index 8135f3d12f70..580c200f9095 100644 --- a/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.h +++ b/contrib/llvm-project/clang/lib/AST/Interp/Descriptor.h @@ -100,7 +100,7 @@ public: static constexpr MetadataSize InlineDescMD = sizeof(InlineDescriptor); /// Pointer to the record, if block contains records. - Record *const ElemRecord = nullptr; + const Record *const ElemRecord = nullptr; /// Descriptor of the array element. const Descriptor *const ElemDesc = nullptr; /// Flag indicating if the block is mutable. @@ -135,10 +135,11 @@ public: unsigned NumElems, bool IsConst, bool IsTemporary, bool IsMutable); /// Allocates a descriptor for an array of composites of unknown size. - Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, UnknownSize); + Descriptor(const DeclTy &D, const Descriptor *Elem, bool IsTemporary, + UnknownSize); /// Allocates a descriptor for a record. - Descriptor(const DeclTy &D, Record *R, MetadataSize MD, bool IsConst, + Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst, bool IsTemporary, bool IsMutable); Descriptor(const DeclTy &D, MetadataSize MD); diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp index 21ea2503b94b..9de0926b9dba 100644 --- a/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp +++ b/contrib/llvm-project/clang/lib/AST/Interp/Interp.cpp @@ -134,6 +134,18 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) { if (CurFunc->isUnevaluatedBuiltin()) return; + // Some builtin functions require us to only look at the call site, since + // the classified parameter types do not match. + if (CurFunc->isBuiltin()) { + const auto *CE = + cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC())); + for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) { + const Expr *A = CE->getArg(I); + popArg(S, A); + } + return; + } + if (S.Current->Caller && CurFunc->isVariadic()) { // CallExpr we're look for is at the return PC of the current function, i.e. // in the caller. diff --git a/contrib/llvm-project/clang/lib/AST/Interp/InterpBuiltin.cpp b/contrib/llvm-project/clang/lib/AST/Interp/InterpBuiltin.cpp index b55b1569a259..754ca96b0c64 100644 --- a/contrib/llvm-project/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/contrib/llvm-project/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -164,6 +164,8 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result, case X: \ return Ret<X>(S, OpPC, Result); switch (*T) { + RET_CASE(PT_Ptr); + RET_CASE(PT_FnPtr); RET_CASE(PT_Float); RET_CASE(PT_Bool); RET_CASE(PT_Sint8); @@ -613,15 +615,34 @@ static bool interp__builtin_ffs(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + PrimType PtrT = + S.getContext().classify(Call->getArg(0)->getType()).value_or(PT_Ptr); + + if (PtrT == PT_FnPtr) { + const FunctionPointer &Arg = S.Stk.peek<FunctionPointer>(); + S.Stk.push<FunctionPointer>(Arg); + } else if (PtrT == PT_Ptr) { + const Pointer &Arg = S.Stk.peek<Pointer>(); + S.Stk.push<Pointer>(Arg); + } else { + assert(false && "Unsupported pointer type passed to __builtin_addressof()"); + } + return true; +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; APValue Dummy; - QualType ReturnType = Call->getCallReturnType(S.getCtx()); - std::optional<PrimType> ReturnT = S.getContext().classify(ReturnType); + std::optional<PrimType> ReturnT = S.getContext().classify(Call->getType()); + // If classify failed, we assume void. - assert(ReturnT || ReturnType->isVoidType()); + assert(ReturnT || Call->getType()->isVoidType()); switch (F->getBuiltinID()) { case Builtin::BI__builtin_is_constant_evaluated: @@ -820,6 +841,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, if (!interp__builtin_ffs(S, OpPC, Frame, F, Call)) return false; break; + case Builtin::BIaddressof: + case Builtin::BI__addressof: + case Builtin::BI__builtin_addressof: + if (!interp__builtin_addressof(S, OpPC, Frame, F, Call)) + return false; + break; default: return false; diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp b/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp index 52e13398163e..1daefab4dcda 100644 --- a/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp +++ b/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp @@ -315,14 +315,14 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, bool IsConst, bool IsTemporary, bool IsMutable, const Expr *Init) { // Classes and structures. - if (auto *RT = Ty->getAs<RecordType>()) { - if (auto *Record = getOrCreateRecord(RT->getDecl())) + if (const auto *RT = Ty->getAs<RecordType>()) { + if (const auto *Record = getOrCreateRecord(RT->getDecl())) return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, IsMutable); } // Arrays. - if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) { + if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) { QualType ElemTy = ArrayType->getElementType(); // Array of well-known bounds. if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) { @@ -338,7 +338,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, } else { // Arrays of composites. In this case, the array is a list of pointers, // followed by the actual elements. - Descriptor *ElemDesc = createDescriptor( + const Descriptor *ElemDesc = createDescriptor( D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary); if (!ElemDesc) return nullptr; @@ -358,8 +358,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, return allocateDescriptor(D, *T, IsTemporary, Descriptor::UnknownSize{}); } else { - Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), MDSize, - IsConst, IsTemporary); + const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), + MDSize, IsConst, IsTemporary); if (!Desc) return nullptr; return allocateDescriptor(D, Desc, IsTemporary, @@ -369,14 +369,14 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, } // Atomic types. - if (auto *AT = Ty->getAs<AtomicType>()) { + if (const auto *AT = Ty->getAs<AtomicType>()) { const Type *InnerTy = AT->getValueType().getTypePtr(); return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary, IsMutable); } // Complex types - represented as arrays of elements. - if (auto *CT = Ty->getAs<ComplexType>()) { + if (const auto *CT = Ty->getAs<ComplexType>()) { PrimType ElemTy = *Ctx.classify(CT->getElementType()); return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary, IsMutable); diff --git a/contrib/llvm-project/clang/lib/AST/Type.cpp b/contrib/llvm-project/clang/lib/AST/Type.cpp index a894d3289eb1..b419fc8836b0 100644 --- a/contrib/llvm-project/clang/lib/AST/Type.cpp +++ b/contrib/llvm-project/clang/lib/AST/Type.cpp @@ -2604,19 +2604,22 @@ bool QualType::isTrivialType(const ASTContext &Context) const { return false; } -bool QualType::isTriviallyCopyableType(const ASTContext &Context) const { - if ((*this)->isArrayType()) - return Context.getBaseElementType(*this).isTriviallyCopyableType(Context); +static bool isTriviallyCopyableTypeImpl(const QualType &type, + const ASTContext &Context, + bool IsCopyConstructible) { + if (type->isArrayType()) + return isTriviallyCopyableTypeImpl(Context.getBaseElementType(type), + Context, IsCopyConstructible); - if (hasNonTrivialObjCLifetime()) + if (type.hasNonTrivialObjCLifetime()) return false; // C++11 [basic.types]p9 - See Core 2094 // Scalar types, trivially copyable class types, arrays of such types, and // cv-qualified versions of these types are collectively - // called trivially copyable types. + // called trivially copy constructible types. - QualType CanonicalType = getCanonicalType(); + QualType CanonicalType = type.getCanonicalType(); if (CanonicalType->isDependentType()) return false; @@ -2634,16 +2637,29 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const { if (const auto *RT = CanonicalType->getAs<RecordType>()) { if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { - if (!ClassDecl->isTriviallyCopyable()) return false; + if (IsCopyConstructible) { + return ClassDecl->isTriviallyCopyConstructible(); + } else { + return ClassDecl->isTriviallyCopyable(); + } } - return true; } - // No other types can match. return false; } +bool QualType::isTriviallyCopyableType(const ASTContext &Context) const { + return isTriviallyCopyableTypeImpl(*this, Context, + /*IsCopyConstructible=*/false); +} + +bool QualType::isTriviallyCopyConstructibleType( + const ASTContext &Context) const { + return isTriviallyCopyableTypeImpl(*this, Context, + /*IsCopyConstructible=*/true); +} + bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const { QualType BaseElementType = Context.getBaseElementType(*this); diff --git a/contrib/llvm-project/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/contrib/llvm-project/clang/lib/Analysis/ExprMutationAnalyzer.cpp index 624a643cc60e..c0de9277ff86 100644 --- a/contrib/llvm-project/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/contrib/llvm-project/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -15,6 +15,81 @@ namespace clang { using namespace ast_matchers; +// Check if result of Source expression could be a Target expression. +// Checks: +// - Implicit Casts +// - Binary Operators +// - ConditionalOperator +// - BinaryConditionalOperator +static bool canExprResolveTo(const Expr *Source, const Expr *Target) { + + const auto IgnoreDerivedToBase = [](const Expr *E, auto Matcher) { + if (Matcher(E)) + return true; + if (const auto *Cast = dyn_cast<ImplicitCastExpr>(E)) { + if ((Cast->getCastKind() == CK_DerivedToBase || + Cast->getCastKind() == CK_UncheckedDerivedToBase) && + Matcher(Cast->getSubExpr())) + return true; + } + return false; + }; + + const auto EvalCommaExpr = [](const Expr *E, auto Matcher) { + const Expr *Result = E; + while (const auto *BOComma = + dyn_cast_or_null<BinaryOperator>(Result->IgnoreParens())) { + if (!BOComma->isCommaOp()) + break; + Result = BOComma->getRHS(); + } + + return Result != E && Matcher(Result); + }; + + // The 'ConditionalOperatorM' matches on `<anything> ? <expr> : <expr>`. + // This matching must be recursive because `<expr>` can be anything resolving + // to the `InnerMatcher`, for example another conditional operator. + // The edge-case `BaseClass &b = <cond> ? DerivedVar1 : DerivedVar2;` + // is handled, too. The implicit cast happens outside of the conditional. + // This is matched by `IgnoreDerivedToBase(canResolveToExpr(InnerMatcher))` + // below. + const auto ConditionalOperatorM = [Target](const Expr *E) { + if (const auto *OP = dyn_cast<ConditionalOperator>(E)) { + if (const auto *TE = OP->getTrueExpr()->IgnoreParens()) + if (canExprResolveTo(TE, Target)) + return true; + if (const auto *FE = OP->getFalseExpr()->IgnoreParens()) + if (canExprResolveTo(FE, Target)) + return true; + } + return false; + }; + + const auto ElvisOperator = [Target](const Expr *E) { + if (const auto *OP = dyn_cast<BinaryConditionalOperator>(E)) { + if (const auto *TE = OP->getTrueExpr()->IgnoreParens()) + if (canExprResolveTo(TE, Target)) + return true; + if (const auto *FE = OP->getFalseExpr()->IgnoreParens()) + if (canExprResolveTo(FE, Target)) + return true; + } + return false; + }; + + const Expr *SourceExprP = Source->IgnoreParens(); + return IgnoreDerivedToBase(SourceExprP, + [&](const Expr *E) { + return E == Target || ConditionalOperatorM(E) || + ElvisOperator(E); + }) || + EvalCommaExpr(SourceExprP, [&](const Expr *E) { + return IgnoreDerivedToBase( + E->IgnoreParens(), [&](const Expr *EE) { return EE == Target; }); + }); +} + namespace { AST_MATCHER_P(LambdaExpr, hasCaptureInit, const Expr *, E) { @@ -27,56 +102,14 @@ AST_MATCHER_P(CXXForRangeStmt, hasRangeStmt, return InnerMatcher.matches(*Range, Finder, Builder); } -AST_MATCHER_P(Expr, maybeEvalCommaExpr, ast_matchers::internal::Matcher<Expr>, - InnerMatcher) { - const Expr *Result = &Node; - while (const auto *BOComma = - dyn_cast_or_null<BinaryOperator>(Result->IgnoreParens())) { - if (!BOComma->isCommaOp()) - break; - Result = BOComma->getRHS(); - } - return InnerMatcher.matches(*Result, Finder, Builder); -} - -AST_MATCHER_P(Stmt, canResolveToExpr, ast_matchers::internal::Matcher<Stmt>, - InnerMatcher) { +AST_MATCHER_P(Stmt, canResolveToExpr, const Stmt *, Inner) { auto *Exp = dyn_cast<Expr>(&Node); - if (!Exp) { - return stmt().matches(Node, Finder, Builder); - } - - auto DerivedToBase = [](const ast_matchers::internal::Matcher<Expr> &Inner) { - return implicitCastExpr(anyOf(hasCastKind(CK_DerivedToBase), - hasCastKind(CK_UncheckedDerivedToBase)), - hasSourceExpression(Inner)); - }; - auto IgnoreDerivedToBase = - [&DerivedToBase](const ast_matchers::internal::Matcher<Expr> &Inner) { - return ignoringParens(expr(anyOf(Inner, DerivedToBase(Inner)))); - }; - - // The 'ConditionalOperator' matches on `<anything> ? <expr> : <expr>`. - // This matching must be recursive because `<expr>` can be anything resolving - // to the `InnerMatcher`, for example another conditional operator. - // The edge-case `BaseClass &b = <cond> ? DerivedVar1 : DerivedVar2;` - // is handled, too. The implicit cast happens outside of the conditional. - // This is matched by `IgnoreDerivedToBase(canResolveToExpr(InnerMatcher))` - // below. - auto const ConditionalOperator = conditionalOperator(anyOf( - hasTrueExpression(ignoringParens(canResolveToExpr(InnerMatcher))), - hasFalseExpression(ignoringParens(canResolveToExpr(InnerMatcher))))); - auto const ElvisOperator = binaryConditionalOperator(anyOf( - hasTrueExpression(ignoringParens(canResolveToExpr(InnerMatcher))), - hasFalseExpression(ignoringParens(canResolveToExpr(InnerMatcher))))); - - auto const ComplexMatcher = ignoringParens( - expr(anyOf(IgnoreDerivedToBase(InnerMatcher), - maybeEvalCommaExpr(IgnoreDerivedToBase(InnerMatcher)), - IgnoreDerivedToBase(ConditionalOperator), - IgnoreDerivedToBase(ElvisOperator)))); - - return ComplexMatcher.matches(*Exp, Finder, Builder); + if (!Exp) + return true; + auto *Target = dyn_cast<Expr>(Inner); + if (!Target) + return false; + return canExprResolveTo(Exp, Target); } // Similar to 'hasAnyArgument', but does not work because 'InitListExpr' does @@ -121,6 +154,12 @@ AST_MATCHER_P(GenericSelectionExpr, hasControllingExpr, return InnerMatcher.matches(*Node.getControllingExpr(), Finder, Builder); } +template <typename T> +ast_matchers::internal::Matcher<T> +findFirst(const ast_matchers::internal::Matcher<T> &Matcher) { + return anyOf(Matcher, hasDescendant(Matcher)); +} + const auto nonConstReferenceType = [] { return hasUnqualifiedDesugaredType( referenceType(pointee(unless(isConstQualified())))); @@ -220,8 +259,8 @@ bool ExprMutationAnalyzer::isUnevaluated(const Stmt *Exp, const Stmt &Stm, return selectFirst<Stmt>( NodeID<Expr>::value, match( - findAll( - stmt(canResolveToExpr(equalsNode(Exp)), + findFirst( + stmt(canResolveToExpr(Exp), anyOf( // `Exp` is part of the underlying expression of // decltype/typeof if it has an ancestor of @@ -275,44 +314,41 @@ const Stmt *ExprMutationAnalyzer::findDeclPointeeMutation( const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) { // LHS of any assignment operators. - const auto AsAssignmentLhs = binaryOperator( - isAssignmentOperator(), hasLHS(canResolveToExpr(equalsNode(Exp)))); + const auto AsAssignmentLhs = + binaryOperator(isAssignmentOperator(), hasLHS(canResolveToExpr(Exp))); // Operand of increment/decrement operators. const auto AsIncDecOperand = unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")), - hasUnaryOperand(canResolveToExpr(equalsNode(Exp)))); + hasUnaryOperand(canResolveToExpr(Exp))); // Invoking non-const member function. // A member function is assumed to be non-const when it is unresolved. const auto NonConstMethod = cxxMethodDecl(unless(isConst())); const auto AsNonConstThis = expr(anyOf( - cxxMemberCallExpr(on(canResolveToExpr(equalsNode(Exp))), - unless(isConstCallee())), + cxxMemberCallExpr(on(canResolveToExpr(Exp)), unless(isConstCallee())), cxxOperatorCallExpr(callee(NonConstMethod), - hasArgument(0, canResolveToExpr(equalsNode(Exp)))), + hasArgument(0, canResolveToExpr(Exp))), // In case of a templated type, calling overloaded operators is not // resolved and modelled as `binaryOperator` on a dependent type. // Such instances are considered a modification, because they can modify // in different instantiations of the template. - binaryOperator( - hasEitherOperand(ignoringImpCasts(canResolveToExpr(equalsNode(Exp)))), - isTypeDependent()), + binaryOperator(isTypeDependent(), + hasEitherOperand(ignoringImpCasts(canResolveToExpr(Exp)))), // Within class templates and member functions the member expression might // not be resolved. In that case, the `callExpr` is considered to be a // modification. - callExpr( - callee(expr(anyOf(unresolvedMemberExpr(hasObjectExpression( - canResolveToExpr(equalsNode(Exp)))), - cxxDependentScopeMemberExpr(hasObjectExpression( - canResolveToExpr(equalsNode(Exp)))))))), + callExpr(callee(expr(anyOf( + unresolvedMemberExpr(hasObjectExpression(canResolveToExpr(Exp))), + cxxDependentScopeMemberExpr( + hasObjectExpression(canResolveToExpr(Exp))))))), // Match on a call to a known method, but the call itself is type // dependent (e.g. `vector<T> v; v.push(T{});` in a templated function). - callExpr(allOf(isTypeDependent(), - callee(memberExpr(hasDeclaration(NonConstMethod), - hasObjectExpression(canResolveToExpr( - equalsNode(Exp))))))))); + callExpr(allOf( + isTypeDependent(), + callee(memberExpr(hasDeclaration(NonConstMethod), + hasObjectExpression(canResolveToExpr(Exp)))))))); // Taking address of 'Exp'. // We're assuming 'Exp' is mutated as soon as its address is taken, though in @@ -322,11 +358,10 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) { unaryOperator(hasOperatorName("&"), // A NoOp implicit cast is adding const. unless(hasParent(implicitCastExpr(hasCastKind(CK_NoOp)))), - hasUnaryOperand(canResolveToExpr(equalsNode(Exp)))); - const auto AsPointerFromArrayDecay = - castExpr(hasCastKind(CK_ArrayToPointerDecay), - unless(hasParent(arraySubscriptExpr())), - has(canResolveToExpr(equalsNode(Exp)))); + hasUnaryOperand(canResolveToExpr(Exp))); + const auto AsPointerFromArrayDecay = castExpr( + hasCastKind(CK_ArrayToPointerDecay), + unless(hasParent(arraySubscriptExpr())), has(canResolveToExpr(Exp))); // Treat calling `operator->()` of move-only classes as taking address. // These are typically smart pointers with unique ownership so we treat // mutation of pointee as mutation of the smart pointer itself. @@ -334,7 +369,7 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) { hasOverloadedOperatorName("->"), callee( cxxMethodDecl(ofClass(isMoveOnly()), returns(nonConstPointerType()))), - argumentCountIs(1), hasArgument(0, canResolveToExpr(equalsNode(Exp)))); + argumentCountIs(1), hasArgument(0, canResolveToExpr(Exp))); // Used as non-const-ref argument when calling a function. // An argument is assumed to be non-const-ref when the function is unresolved. @@ -342,8 +377,8 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) { // findFunctionArgMutation which has additional smarts for handling forwarding // references. const auto NonConstRefParam = forEachArgumentWithParamType( - anyOf(canResolveToExpr(equalsNode(Exp)), - memberExpr(hasObjectExpression(canResolveToExpr(equalsNode(Exp))))), + anyOf(canResolveToExpr(Exp), + memberExpr(hasObjectExpression(canResolveToExpr(Exp)))), nonConstReferenceType()); const auto NotInstantiated = unless(hasDeclaration(isInstantiated())); const auto TypeDependentCallee = @@ -354,19 +389,17 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) { const auto AsNonConstRefArg = anyOf( callExpr(NonConstRefParam, NotInstantiated), cxxConstructExpr(NonConstRefParam, NotInstantiated), - callExpr(TypeDependentCallee, - hasAnyArgument(canResolveToExpr(equalsNode(Exp)))), - cxxUnresolvedConstructExpr( - hasAnyArgument(canResolveToExpr(equalsNode(Exp)))), + callExpr(TypeDependentCallee, hasAnyArgument(canResolveToExpr(Exp))), + cxxUnresolvedConstructExpr(hasAnyArgument(canResolveToExpr(Exp))), // Previous False Positive in the following Code: // `template <typename T> void f() { int i = 42; new Type<T>(i); }` // Where the constructor of `Type` takes its argument as reference. // The AST does not resolve in a `cxxConstructExpr` because it is // type-dependent. - parenListExpr(hasDescendant(expr(canResolveToExpr(equalsNode(Exp))))), + parenListExpr(hasDescendant(expr(canResolveToExpr(Exp)))), // If the initializer is for a reference type, there is no cast for // the variable. Values are cast to RValue first. - initListExpr(hasAnyInit(expr(canResolveToExpr(equalsNode(Exp)))))); + initListExpr(hasAnyInit(expr(canResolveToExpr(Exp))))); // Captured by a lambda by reference. // If we're initializing a capture with 'Exp' directly then we're initializing @@ -380,76 +413,72 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) { // For returning by const-ref there will be an ImplicitCastExpr <NoOp> (for // adding const.) const auto AsNonConstRefReturn = - returnStmt(hasReturnValue(canResolveToExpr(equalsNode(Exp)))); + returnStmt(hasReturnValue(canResolveToExpr(Exp))); // It is used as a non-const-reference for initalizing a range-for loop. - const auto AsNonConstRefRangeInit = cxxForRangeStmt( - hasRangeInit(declRefExpr(allOf(canResolveToExpr(equalsNode(Exp)), - hasType(nonConstReferenceType()))))); + const auto AsNonConstRefRangeInit = cxxForRangeStmt(hasRangeInit(declRefExpr( + allOf(canResolveToExpr(Exp), hasType(nonConstReferenceType()))))); const auto Matches = match( - traverse(TK_AsIs, - findAll(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand, - AsNonConstThis, AsAmpersandOperand, - AsPointerFromArrayDecay, AsOperatorArrowThis, - AsNonConstRefArg, AsLambdaRefCaptureInit, - AsNonConstRefReturn, AsNonConstRefRangeInit)) - .bind("stmt"))), + traverse( + TK_AsIs, + findFirst(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand, AsNonConstThis, + AsAmpersandOperand, AsPointerFromArrayDecay, + AsOperatorArrowThis, AsNonConstRefArg, + AsLambdaRefCaptureInit, AsNonConstRefReturn, + AsNonConstRefRangeInit)) + .bind("stmt"))), Stm, Context); return selectFirst<Stmt>("stmt", Matches); } const Stmt *ExprMutationAnalyzer::findMemberMutation(const Expr *Exp) { // Check whether any member of 'Exp' is mutated. - const auto MemberExprs = - match(findAll(expr(anyOf(memberExpr(hasObjectExpression( - canResolveToExpr(equalsNode(Exp)))), - cxxDependentScopeMemberExpr(hasObjectExpression( - canResolveToExpr(equalsNode(Exp)))), - binaryOperator(hasOperatorName(".*"), - hasLHS(equalsNode(Exp))))) - .bind(NodeID<Expr>::value)), - Stm, Context); + const auto MemberExprs = match( + findAll(expr(anyOf(memberExpr(hasObjectExpression(canResolveToExpr(Exp))), + cxxDependentScopeMemberExpr( + hasObjectExpression(canResolveToExpr(Exp))), + binaryOperator(hasOperatorName(".*"), + hasLHS(equalsNode(Exp))))) + .bind(NodeID<Expr>::value)), + Stm, Context); return findExprMutation(MemberExprs); } const Stmt *ExprMutationAnalyzer::findArrayElementMutation(const Expr *Exp) { // Check whether any element of an array is mutated. - const auto SubscriptExprs = - match(findAll(arraySubscriptExpr( - anyOf(hasBase(canResolveToExpr(equalsNode(Exp))), - hasBase(implicitCastExpr( - allOf(hasCastKind(CK_ArrayToPointerDecay), - hasSourceExpression(canResolveToExpr( - equalsNode(Exp)))))))) - .bind(NodeID<Expr>::value)), - Stm, Context); + const auto SubscriptExprs = match( + findAll(arraySubscriptExpr( + anyOf(hasBase(canResolveToExpr(Exp)), + hasBase(implicitCastExpr(allOf( + hasCastKind(CK_ArrayToPointerDecay), + hasSourceExpression(canResolveToExpr(Exp))))))) + .bind(NodeID<Expr>::value)), + Stm, Context); return findExprMutation(SubscriptExprs); } const Stmt *ExprMutationAnalyzer::findCastMutation(const Expr *Exp) { // If the 'Exp' is explicitly casted to a non-const reference type the // 'Exp' is considered to be modified. - const auto ExplicitCast = match( - findAll( - stmt(castExpr(hasSourceExpression(canResolveToExpr(equalsNode(Exp))), - explicitCastExpr( - hasDestinationType(nonConstReferenceType())))) - .bind("stmt")), - Stm, Context); + const auto ExplicitCast = + match(findFirst(stmt(castExpr(hasSourceExpression(canResolveToExpr(Exp)), + explicitCastExpr(hasDestinationType( + nonConstReferenceType())))) + .bind("stmt")), + Stm, Context); if (const auto *CastStmt = selectFirst<Stmt>("stmt", ExplicitCast)) return CastStmt; // If 'Exp' is casted to any non-const reference type, check the castExpr. const auto Casts = match( - findAll( - expr(castExpr(hasSourceExpression(canResolveToExpr(equalsNode(Exp))), - anyOf(explicitCastExpr( - hasDestinationType(nonConstReferenceType())), - implicitCastExpr(hasImplicitDestinationType( - nonConstReferenceType()))))) - .bind(NodeID<Expr>::value)), + findAll(expr(castExpr(hasSourceExpression(canResolveToExpr(Exp)), + anyOf(explicitCastExpr(hasDestinationType( + nonConstReferenceType())), + implicitCastExpr(hasImplicitDestinationType( + nonConstReferenceType()))))) + .bind(NodeID<Expr>::value)), Stm, Context); if (const Stmt *S = findExprMutation(Casts)) @@ -458,7 +487,7 @@ const Stmt *ExprMutationAnalyzer::findCastMutation(const Expr *Exp) { const auto Calls = match(findAll(callExpr(callee(namedDecl( hasAnyName("::std::move", "::std::forward"))), - hasArgument(0, canResolveToExpr(equalsNode(Exp)))) + hasArgument(0, canResolveToExpr(Exp))) .bind("expr")), Stm, Context); return findExprMutation(Calls); @@ -473,16 +502,16 @@ const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) { // array is considered modified if the loop-variable is a non-const reference. const auto DeclStmtToNonRefToArray = declStmt(hasSingleDecl(varDecl(hasType( hasUnqualifiedDesugaredType(referenceType(pointee(arrayType()))))))); - const auto RefToArrayRefToElements = - match(findAll(stmt(cxxForRangeStmt( - hasLoopVariable( - varDecl(anyOf(hasType(nonConstReferenceType()), - hasType(nonConstPointerType()))) - .bind(NodeID<Decl>::value)), - hasRangeStmt(DeclStmtToNonRefToArray), - hasRangeInit(canResolveToExpr(equalsNode(Exp))))) - .bind("stmt")), - Stm, Context); + const auto RefToArrayRefToElements = match( + findFirst(stmt(cxxForRangeStmt( + hasLoopVariable( + varDecl(anyOf(hasType(nonConstReferenceType()), + hasType(nonConstPointerType()))) + .bind(NodeID<Decl>::value)), + hasRangeStmt(DeclStmtToNonRefToArray), + hasRangeInit(canResolveToExpr(Exp)))) + .bind("stmt")), + Stm, Context); if (const auto *BadRangeInitFromArray = selectFirst<Stmt>("stmt", RefToArrayRefToElements)) @@ -505,12 +534,12 @@ const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) { hasSingleDecl(varDecl(hasType(hasUnqualifiedDesugaredType(referenceType( pointee(hasDeclaration(cxxRecordDecl(HasAnyNonConstIterator))))))))); - const auto RefToContainerBadIterators = - match(findAll(stmt(cxxForRangeStmt(allOf( - hasRangeStmt(DeclStmtToNonConstIteratorContainer), - hasRangeInit(canResolveToExpr(equalsNode(Exp)))))) - .bind("stmt")), - Stm, Context); + const auto RefToContainerBadIterators = match( + findFirst(stmt(cxxForRangeStmt(allOf( + hasRangeStmt(DeclStmtToNonConstIteratorContainer), + hasRangeInit(canResolveToExpr(Exp))))) + .bind("stmt")), + Stm, Context); if (const auto *BadIteratorsContainer = selectFirst<Stmt>("stmt", RefToContainerBadIterators)) @@ -522,7 +551,7 @@ const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) { match(findAll(cxxForRangeStmt( hasLoopVariable(varDecl(hasType(nonConstReferenceType())) .bind(NodeID<Decl>::value)), - hasRangeInit(canResolveToExpr(equalsNode(Exp))))), + hasRangeInit(canResolveToExpr(Exp)))), Stm, Context); return findDeclMutation(LoopVars); } @@ -531,31 +560,29 @@ const Stmt *ExprMutationAnalyzer::findReferenceMutation(const Expr *Exp) { // Follow non-const reference returned by `operator*()` of move-only classes. // These are typically smart pointers with unique ownership so we treat // mutation of pointee as mutation of the smart pointer itself. - const auto Ref = - match(findAll(cxxOperatorCallExpr( - hasOverloadedOperatorName("*"), - callee(cxxMethodDecl(ofClass(isMoveOnly()), - returns(nonConstReferenceType()))), - argumentCountIs(1), - hasArgument(0, canResolveToExpr(equalsNode(Exp)))) - .bind(NodeID<Expr>::value)), - Stm, Context); + const auto Ref = match( + findAll(cxxOperatorCallExpr( + hasOverloadedOperatorName("*"), + callee(cxxMethodDecl(ofClass(isMoveOnly()), + returns(nonConstReferenceType()))), + argumentCountIs(1), hasArgument(0, canResolveToExpr(Exp))) + .bind(NodeID<Expr>::value)), + Stm, Context); if (const Stmt *S = findExprMutation(Ref)) return S; // If 'Exp' is bound to a non-const reference, check all declRefExpr to that. const auto Refs = match( stmt(forEachDescendant( - varDecl( - hasType(nonConstReferenceType()), - hasInitializer(anyOf(canResolveToExpr(equalsNode(Exp)), - memberExpr(hasObjectExpression( - canResolveToExpr(equalsNode(Exp)))))), - hasParent(declStmt().bind("stmt")), - // Don't follow the reference in range statement, we've - // handled that separately. - unless(hasParent(declStmt(hasParent( - cxxForRangeStmt(hasRangeStmt(equalsBoundNode("stmt")))))))) + varDecl(hasType(nonConstReferenceType()), + hasInitializer(anyOf( + canResolveToExpr(Exp), + memberExpr(hasObjectExpression(canResolveToExpr(Exp))))), + hasParent(declStmt().bind("stmt")), + // Don't follow the reference in range statement, we've + // handled that separately. + unless(hasParent(declStmt(hasParent(cxxForRangeStmt( + hasRangeStmt(equalsBoundNode("stmt")))))))) .bind(NodeID<Decl>::value))), Stm, Context); return findDeclMutation(Refs); @@ -563,7 +590,7 @@ const Stmt *ExprMutationAnalyzer::findReferenceMutation(const Expr *Exp) { const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(const Expr *Exp) { const auto NonConstRefParam = forEachArgumentWithParam( - canResolveToExpr(equalsNode(Exp)), + canResolveToExpr(Exp), parmVarDecl(hasType(nonConstReferenceType())).bind("parm")); const auto IsInstantiated = hasDeclaration(isInstantiated()); const auto FuncDecl = hasDeclaration(functionDecl().bind("func")); diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.cpp index 2f8395cb8932..9ebaf4d40cd7 100644 --- a/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.cpp +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.cpp @@ -226,6 +226,7 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef, BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement; BPI.BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR; + BPI.GuardedControlStack = PBP.GuardedControlStack; return true; } @@ -532,6 +533,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, if (Opts.BranchTargetEnforcement) Builder.defineMacro("__ARM_FEATURE_BTI_DEFAULT", "1"); + if (Opts.GuardedControlStack) + Builder.defineMacro("__ARM_FEATURE_GCS_DEFAULT", "1"); + if (HasLS64) Builder.defineMacro("__ARM_FEATURE_LS64", "1"); @@ -544,6 +548,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasD128) Builder.defineMacro("__ARM_FEATURE_SYSREG128", "1"); + if (HasGCS) + Builder.defineMacro("__ARM_FEATURE_GCS", "1"); + if (*ArchInfo == llvm::AArch64::ARMV8_1A) getTargetDefinesARMV81A(Opts, Builder); else if (*ArchInfo == llvm::AArch64::ARMV8_2A) diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp index daaa8639ae83..fb312b6cf26e 100644 --- a/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp +++ b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp @@ -163,9 +163,8 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, auto ExtName = Extension.first; auto ExtInfo = Extension.second; - Builder.defineMacro( - Twine("__riscv_", ExtName), - Twine(getVersionValue(ExtInfo.MajorVersion, ExtInfo.MinorVersion))); + Builder.defineMacro(Twine("__riscv_", ExtName), + Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor))); } if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul")) diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp index f71dbf1729a1..998fcc3af581 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp @@ -25,6 +25,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/OSLog.h" +#include "clang/AST/OperationKinds.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" @@ -818,6 +819,238 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type, return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true); } +const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField( + ASTContext &Ctx, const RecordDecl *RD, StringRef Name, uint64_t &Offset) { + const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); + unsigned FieldNo = 0; + bool IsUnion = RD->isUnion(); + + for (const Decl *D : RD->decls()) { + if (const auto *Field = dyn_cast<FieldDecl>(D); + Field && (Name.empty() || Field->getNameAsString() == Name) && + Decl::isFlexibleArrayMemberLike( + Ctx, Field, Field->getType(), StrictFlexArraysLevel, + /*IgnoreTemplateOrMacroSubstitution=*/true)) { + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + Offset += Layout.getFieldOffset(FieldNo); + return Field; + } + + if (const auto *Record = dyn_cast<RecordDecl>(D)) + if (const FieldDecl *Field = + FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) { + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + Offset += Layout.getFieldOffset(FieldNo); + return Field; + } + + if (!IsUnion && isa<FieldDecl>(D)) + ++FieldNo; + } + + return nullptr; +} + +static unsigned CountCountedByAttrs(const RecordDecl *RD) { + unsigned Num = 0; + + for (const Decl *D : RD->decls()) { + if (const auto *FD = dyn_cast<FieldDecl>(D); + FD && FD->hasAttr<CountedByAttr>()) { + return ++Num; + } + + if (const auto *Rec = dyn_cast<RecordDecl>(D)) + Num += CountCountedByAttrs(Rec); + } + + return Num; +} + +llvm::Value * +CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, + llvm::IntegerType *ResType) { + // The code generated here calculates the size of a struct with a flexible + // array member that uses the counted_by attribute. There are two instances + // we handle: + // + // struct s { + // unsigned long flags; + // int count; + // int array[] __attribute__((counted_by(count))); + // } + // + // 1) bdos of the flexible array itself: + // + // __builtin_dynamic_object_size(p->array, 1) == + // p->count * sizeof(*p->array) + // + // 2) bdos of a pointer into the flexible array: + // + // __builtin_dynamic_object_size(&p->array[42], 1) == + // (p->count - 42) * sizeof(*p->array) + // + // 2) bdos of the whole struct, including the flexible array: + // + // __builtin_dynamic_object_size(p, 1) == + // max(sizeof(struct s), + // offsetof(struct s, array) + p->count * sizeof(*p->array)) + // + ASTContext &Ctx = getContext(); + const Expr *Base = E->IgnoreParenImpCasts(); + const Expr *Idx = nullptr; + + if (const auto *UO = dyn_cast<UnaryOperator>(Base); + UO && UO->getOpcode() == UO_AddrOf) { + Expr *SubExpr = UO->getSubExpr()->IgnoreParenImpCasts(); + if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(SubExpr)) { + Base = ASE->getBase()->IgnoreParenImpCasts(); + Idx = ASE->getIdx()->IgnoreParenImpCasts(); + + if (const auto *IL = dyn_cast<IntegerLiteral>(Idx)) { + int64_t Val = IL->getValue().getSExtValue(); + if (Val < 0) + return getDefaultBuiltinObjectSizeResult(Type, ResType); + + if (Val == 0) + // The index is 0, so we don't need to take it into account. + Idx = nullptr; + } + } else { + // Potential pointer to another element in the struct. + Base = SubExpr; + } + } + + // Get the flexible array member Decl. + const RecordDecl *OuterRD = nullptr; + std::string FAMName; + if (const auto *ME = dyn_cast<MemberExpr>(Base)) { + // Check if \p Base is referencing the FAM itself. + const ValueDecl *VD = ME->getMemberDecl(); + OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext(); + FAMName = VD->getNameAsString(); + } else if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { + // Check if we're pointing to the whole struct. + QualType Ty = DRE->getDecl()->getType(); + if (Ty->isPointerType()) + Ty = Ty->getPointeeType(); + OuterRD = Ty->getAsRecordDecl(); + + // If we have a situation like this: + // + // struct union_of_fams { + // int flags; + // union { + // signed char normal_field; + // struct { + // int count1; + // int arr1[] __counted_by(count1); + // }; + // struct { + // signed char count2; + // int arr2[] __counted_by(count2); + // }; + // }; + // }; + // + // We don't konw which 'count' to use in this scenario: + // + // size_t get_size(struct union_of_fams *p) { + // return __builtin_dynamic_object_size(p, 1); + // } + // + // Instead of calculating a wrong number, we give up. + if (OuterRD && CountCountedByAttrs(OuterRD) > 1) + return nullptr; + } + + if (!OuterRD) + return nullptr; + + uint64_t Offset = 0; + const FieldDecl *FAMDecl = + FindFlexibleArrayMemberField(Ctx, OuterRD, FAMName, Offset); + Offset = Ctx.toCharUnitsFromBits(Offset).getQuantity(); + + if (!FAMDecl || !FAMDecl->hasAttr<CountedByAttr>()) + // No flexible array member found or it doesn't have the "counted_by" + // attribute. + return nullptr; + + const FieldDecl *CountedByFD = FindCountedByField(FAMDecl); + if (!CountedByFD) + // Can't find the field referenced by the "counted_by" attribute. + return nullptr; + + // Build a load of the counted_by field. + bool IsSigned = CountedByFD->getType()->isSignedIntegerType(); + Value *CountedByInst = EmitCountedByFieldExpr(Base, FAMDecl, CountedByFD); + if (!CountedByInst) + return getDefaultBuiltinObjectSizeResult(Type, ResType); + + CountedByInst = Builder.CreateIntCast(CountedByInst, ResType, IsSigned); + + // Build a load of the index and subtract it from the count. + Value *IdxInst = nullptr; + if (Idx) { + if (Idx->HasSideEffects(getContext())) + // We can't have side-effects. + return getDefaultBuiltinObjectSizeResult(Type, ResType); + + bool IdxSigned = Idx->getType()->isSignedIntegerType(); + IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); + IdxInst = Builder.CreateIntCast(IdxInst, ResType, IdxSigned); + + // We go ahead with the calculation here. If the index turns out to be + // negative, we'll catch it at the end. + CountedByInst = + Builder.CreateSub(CountedByInst, IdxInst, "", !IsSigned, IsSigned); + } + + // Calculate how large the flexible array member is in bytes. + const ArrayType *ArrayTy = Ctx.getAsArrayType(FAMDecl->getType()); + CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); + llvm::Constant *ElemSize = + llvm::ConstantInt::get(ResType, Size.getQuantity(), IsSigned); + Value *FAMSize = + Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned); + FAMSize = Builder.CreateIntCast(FAMSize, ResType, IsSigned); + Value *Res = FAMSize; + + if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { + // The whole struct is specificed in the __bdos. + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD); + + // Get the offset of the FAM. + llvm::Constant *FAMOffset = ConstantInt::get(ResType, Offset, IsSigned); + Value *OffsetAndFAMSize = + Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned); + + // Get the full size of the struct. + llvm::Constant *SizeofStruct = + ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned); + + // max(sizeof(struct s), + // offsetof(struct s, array) + p->count * sizeof(*p->array)) + Res = IsSigned + ? Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax, + OffsetAndFAMSize, SizeofStruct) + : Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax, + OffsetAndFAMSize, SizeofStruct); + } + + // A negative \p IdxInst or \p CountedByInst means that the index lands + // outside of the flexible array member. If that's the case, we want to + // return 0. + Value *Cmp = Builder.CreateIsNotNeg(CountedByInst); + if (IdxInst) + Cmp = Builder.CreateAnd(Builder.CreateIsNotNeg(IdxInst), Cmp); + + return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, IsSigned)); +} + /// Returns a Value corresponding to the size of the given expression. /// This Value may be either of the following: /// - A llvm::Argument (if E is a param with the pass_object_size attribute on @@ -850,6 +1083,13 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, } } + if (IsDynamic) { + // Emit special code for a flexible array member with the "counted_by" + // attribute. + if (Value *V = emitFlexibleArrayMemberSize(E, Type, ResType)) + return V; + } + // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't // evaluate E for side-effects. In either case, we shouldn't lower to // @llvm.objectsize. @@ -9681,8 +9921,8 @@ Value *CodeGenFunction::EmitSVEMaskedStore(const CallExpr *E, bool IsQuadStore = false; switch (IntrinsicID) { - case Intrinsic::aarch64_sve_st1uwq: - case Intrinsic::aarch64_sve_st1udq: + case Intrinsic::aarch64_sve_st1wq: + case Intrinsic::aarch64_sve_st1dq: AddrMemoryTy = llvm::ScalableVectorType::get(MemEltTy, 1); PredTy = llvm::ScalableVectorType::get(IntegerType::get(getLLVMContext(), 1), 1); diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGCall.cpp index 51a43b5f85b3..13677cf150ae 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGCall.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGCall.cpp @@ -2612,6 +2612,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, if (IRFunctionArgs.hasSRetArg()) { llvm::AttrBuilder SRETAttrs(getLLVMContext()); SRETAttrs.addStructRetAttr(getTypes().ConvertTypeForMem(RetTy)); + SRETAttrs.addAttribute(llvm::Attribute::Writable); + SRETAttrs.addAttribute(llvm::Attribute::DeadOnUnwind); hasUsedSRet = true; if (RetAI.getInReg()) SRETAttrs.addAttribute(llvm::Attribute::InReg); diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp index 0d507da5c1ba..56a246eb65e0 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp @@ -156,7 +156,9 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target, case ObjCRuntime::WatchOS: return EHPersonality::NeXT_ObjC; case ObjCRuntime::GNUstep: - if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7)) + if (T.isOSCygMing()) + return EHPersonality::GNU_CPlusPlus_SEH; + else if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7)) return EHPersonality::GNUstep_ObjC; [[fallthrough]]; case ObjCRuntime::GCC: @@ -210,7 +212,8 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target, return getObjCPersonality(Target, L); case ObjCRuntime::GNUstep: - return EHPersonality::GNU_ObjCXX; + return Target.getTriple().isOSCygMing() ? EHPersonality::GNU_CPlusPlus_SEH + : EHPersonality::GNU_ObjCXX; // The GCC runtime's personality function inherently doesn't support // mixed EH. Use the ObjC personality just to avoid returning null. diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp index 3f277725d9e7..d12e85b48d0b 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp @@ -26,10 +26,12 @@ #include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/NSAPI.h" +#include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Intrinsics.h" @@ -925,16 +927,21 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, if (CE->getCastKind() == CK_ArrayToPointerDecay && !CE->getSubExpr()->isFlexibleArrayMemberLike(CGF.getContext(), StrictFlexArraysLevel)) { + CodeGenFunction::SanitizerScope SanScope(&CGF); + IndexedType = CE->getSubExpr()->getType(); const ArrayType *AT = IndexedType->castAsArrayTypeUnsafe(); if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) return CGF.Builder.getInt(CAT->getSize()); - else if (const auto *VAT = dyn_cast<VariableArrayType>(AT)) + + if (const auto *VAT = dyn_cast<VariableArrayType>(AT)) return CGF.getVLASize(VAT).NumElts; // Ignore pass_object_size here. It's not applicable on decayed pointers. } } + CodeGenFunction::SanitizerScope SanScope(&CGF); + QualType EltTy{Base->getType()->getPointeeOrArrayElementType(), 0}; if (llvm::Value *POS = CGF.LoadPassedObjectSize(Base, EltTy)) { IndexedType = Base->getType(); @@ -944,22 +951,248 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, return nullptr; } +namespace { + +/// \p StructAccessBase returns the base \p Expr of a field access. It returns +/// either a \p DeclRefExpr, representing the base pointer to the struct, i.e.: +/// +/// p in p-> a.b.c +/// +/// or a \p MemberExpr, if the \p MemberExpr has the \p RecordDecl we're +/// looking for: +/// +/// struct s { +/// struct s *ptr; +/// int count; +/// char array[] __attribute__((counted_by(count))); +/// }; +/// +/// If we have an expression like \p p->ptr->array[index], we want the +/// \p MemberExpr for \p p->ptr instead of \p p. +class StructAccessBase + : public ConstStmtVisitor<StructAccessBase, const Expr *> { + const RecordDecl *ExpectedRD; + + bool IsExpectedRecordDecl(const Expr *E) const { + QualType Ty = E->getType(); + if (Ty->isPointerType()) + Ty = Ty->getPointeeType(); + return ExpectedRD == Ty->getAsRecordDecl(); + } + +public: + StructAccessBase(const RecordDecl *ExpectedRD) : ExpectedRD(ExpectedRD) {} + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + // NOTE: If we build C++ support for counted_by, then we'll have to handle + // horrors like this: + // + // struct S { + // int x, y; + // int blah[] __attribute__((counted_by(x))); + // } s; + // + // int foo(int index, int val) { + // int (S::*IHatePMDs)[] = &S::blah; + // (s.*IHatePMDs)[index] = val; + // } + + const Expr *Visit(const Expr *E) { + return ConstStmtVisitor<StructAccessBase, const Expr *>::Visit(E); + } + + const Expr *VisitStmt(const Stmt *S) { return nullptr; } + + // These are the types we expect to return (in order of most to least + // likely): + // + // 1. DeclRefExpr - This is the expression for the base of the structure. + // It's exactly what we want to build an access to the \p counted_by + // field. + // 2. MemberExpr - This is the expression that has the same \p RecordDecl + // as the flexble array member's lexical enclosing \p RecordDecl. This + // allows us to catch things like: "p->p->array" + // 3. CompoundLiteralExpr - This is for people who create something + // heretical like (struct foo has a flexible array member): + // + // (struct foo){ 1, 2 }.blah[idx]; + const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { + return IsExpectedRecordDecl(E) ? E : nullptr; + } + const Expr *VisitMemberExpr(const MemberExpr *E) { + if (IsExpectedRecordDecl(E) && E->isArrow()) + return E; + const Expr *Res = Visit(E->getBase()); + return !Res && IsExpectedRecordDecl(E) ? E : Res; + } + const Expr *VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { + return IsExpectedRecordDecl(E) ? E : nullptr; + } + const Expr *VisitCallExpr(const CallExpr *E) { + return IsExpectedRecordDecl(E) ? E : nullptr; + } + + const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { + if (IsExpectedRecordDecl(E)) + return E; + return Visit(E->getBase()); + } + const Expr *VisitCastExpr(const CastExpr *E) { + return Visit(E->getSubExpr()); + } + const Expr *VisitParenExpr(const ParenExpr *E) { + return Visit(E->getSubExpr()); + } + const Expr *VisitUnaryAddrOf(const UnaryOperator *E) { + return Visit(E->getSubExpr()); + } + const Expr *VisitUnaryDeref(const UnaryOperator *E) { + return Visit(E->getSubExpr()); + } +}; + +} // end anonymous namespace + +using RecIndicesTy = + SmallVector<std::pair<const RecordDecl *, llvm::Value *>, 8>; + +static bool getGEPIndicesToField(CodeGenFunction &CGF, const RecordDecl *RD, + const FieldDecl *FD, RecIndicesTy &Indices) { + const CGRecordLayout &Layout = CGF.CGM.getTypes().getCGRecordLayout(RD); + int64_t FieldNo = -1; + for (const Decl *D : RD->decls()) { + if (const auto *Field = dyn_cast<FieldDecl>(D)) { + FieldNo = Layout.getLLVMFieldNo(Field); + if (FD == Field) { + Indices.emplace_back(std::make_pair(RD, CGF.Builder.getInt32(FieldNo))); + return true; + } + } + + if (const auto *Record = dyn_cast<RecordDecl>(D)) { + ++FieldNo; + if (getGEPIndicesToField(CGF, Record, FD, Indices)) { + if (RD->isUnion()) + FieldNo = 0; + Indices.emplace_back(std::make_pair(RD, CGF.Builder.getInt32(FieldNo))); + return true; + } + } + } + + return false; +} + +/// This method is typically called in contexts where we can't generate +/// side-effects, like in __builtin_dynamic_object_size. When finding +/// expressions, only choose those that have either already been emitted or can +/// be loaded without side-effects. +/// +/// - \p FAMDecl: the \p Decl for the flexible array member. It may not be +/// within the top-level struct. +/// - \p CountDecl: must be within the same non-anonymous struct as \p FAMDecl. +llvm::Value *CodeGenFunction::EmitCountedByFieldExpr( + const Expr *Base, const FieldDecl *FAMDecl, const FieldDecl *CountDecl) { + const RecordDecl *RD = CountDecl->getParent()->getOuterLexicalRecordContext(); + + // Find the base struct expr (i.e. p in p->a.b.c.d). + const Expr *StructBase = StructAccessBase(RD).Visit(Base); + if (!StructBase || StructBase->HasSideEffects(getContext())) + return nullptr; + + llvm::Value *Res = nullptr; + if (const auto *DRE = dyn_cast<DeclRefExpr>(StructBase)) { + Res = EmitDeclRefLValue(DRE).getPointer(*this); + Res = Builder.CreateAlignedLoad(ConvertType(DRE->getType()), Res, + getPointerAlign(), "dre.load"); + } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(StructBase)) { + LValue LV = EmitMemberExpr(ME); + Address Addr = LV.getAddress(*this); + Res = Addr.getPointer(); + } else if (StructBase->getType()->isPointerType()) { + LValueBaseInfo BaseInfo; + TBAAAccessInfo TBAAInfo; + Address Addr = EmitPointerWithAlignment(StructBase, &BaseInfo, &TBAAInfo); + Res = Addr.getPointer(); + } else { + return nullptr; + } + + llvm::Value *Zero = Builder.getInt32(0); + RecIndicesTy Indices; + + getGEPIndicesToField(*this, RD, CountDecl, Indices); + + for (auto I = Indices.rbegin(), E = Indices.rend(); I != E; ++I) + Res = Builder.CreateInBoundsGEP( + ConvertType(QualType(I->first->getTypeForDecl(), 0)), Res, + {Zero, I->second}, "..counted_by.gep"); + + return Builder.CreateAlignedLoad(ConvertType(CountDecl->getType()), Res, + getIntAlign(), "..counted_by.load"); +} + +const FieldDecl *CodeGenFunction::FindCountedByField(const FieldDecl *FD) { + if (!FD || !FD->hasAttr<CountedByAttr>()) + return nullptr; + + const auto *CBA = FD->getAttr<CountedByAttr>(); + if (!CBA) + return nullptr; + + auto GetNonAnonStructOrUnion = + [](const RecordDecl *RD) -> const RecordDecl * { + while (RD && RD->isAnonymousStructOrUnion()) { + const auto *R = dyn_cast<RecordDecl>(RD->getDeclContext()); + if (!R) + return nullptr; + RD = R; + } + return RD; + }; + const RecordDecl *EnclosingRD = GetNonAnonStructOrUnion(FD->getParent()); + if (!EnclosingRD) + return nullptr; + + DeclarationName DName(CBA->getCountedByField()); + DeclContext::lookup_result Lookup = EnclosingRD->lookup(DName); + + if (Lookup.empty()) + return nullptr; + + const NamedDecl *ND = Lookup.front(); + if (const auto *IFD = dyn_cast<IndirectFieldDecl>(ND)) + ND = IFD->getAnonField(); + + return dyn_cast<FieldDecl>(ND); +} + void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index, QualType IndexType, bool Accessed) { assert(SanOpts.has(SanitizerKind::ArrayBounds) && "should not be called unless adding bounds checks"); - SanitizerScope SanScope(this); - const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = - getLangOpts().getStrictFlexArraysLevel(); - + getLangOpts().getStrictFlexArraysLevel(); QualType IndexedType; llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType, StrictFlexArraysLevel); + + EmitBoundsCheckImpl(E, Bound, Index, IndexType, IndexedType, Accessed); +} + +void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound, + llvm::Value *Index, + QualType IndexType, + QualType IndexedType, bool Accessed) { if (!Bound) return; + SanitizerScope SanScope(this); + bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType(); llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned); llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false); @@ -975,7 +1208,6 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base, SanitizerHandler::OutOfBounds, StaticData, Index); } - CodeGenFunction::ComplexPairTy CodeGenFunction:: EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre) { @@ -3823,6 +4055,61 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, return Address(eltPtr, CGF.ConvertTypeForMem(eltType), eltAlign); } +/// The offset of a field from the beginning of the record. +static bool getFieldOffsetInBits(CodeGenFunction &CGF, const RecordDecl *RD, + const FieldDecl *FD, int64_t &Offset) { + ASTContext &Ctx = CGF.getContext(); + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + unsigned FieldNo = 0; + + for (const Decl *D : RD->decls()) { + if (const auto *Record = dyn_cast<RecordDecl>(D)) + if (getFieldOffsetInBits(CGF, Record, FD, Offset)) { + Offset += Layout.getFieldOffset(FieldNo); + return true; + } + + if (const auto *Field = dyn_cast<FieldDecl>(D)) + if (FD == Field) { + Offset += Layout.getFieldOffset(FieldNo); + return true; + } + + if (isa<FieldDecl>(D)) + ++FieldNo; + } + + return false; +} + +/// Returns the relative offset difference between \p FD1 and \p FD2. +/// \code +/// offsetof(struct foo, FD1) - offsetof(struct foo, FD2) +/// \endcode +/// Both fields must be within the same struct. +static std::optional<int64_t> getOffsetDifferenceInBits(CodeGenFunction &CGF, + const FieldDecl *FD1, + const FieldDecl *FD2) { + const RecordDecl *FD1OuterRec = + FD1->getParent()->getOuterLexicalRecordContext(); + const RecordDecl *FD2OuterRec = + FD2->getParent()->getOuterLexicalRecordContext(); + + if (FD1OuterRec != FD2OuterRec) + // Fields must be within the same RecordDecl. + return std::optional<int64_t>(); + + int64_t FD1Offset = 0; + if (!getFieldOffsetInBits(CGF, FD1OuterRec, FD1, FD1Offset)) + return std::optional<int64_t>(); + + int64_t FD2Offset = 0; + if (!getFieldOffsetInBits(CGF, FD2OuterRec, FD2, FD2Offset)) + return std::optional<int64_t>(); + + return std::make_optional<int64_t>(FD1Offset - FD2Offset); +} + LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, bool Accessed) { // The index must always be an integer, which is not an aggregate. Emit it @@ -3950,6 +4237,47 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, ArrayLV = EmitLValue(Array); auto *Idx = EmitIdxAfterBase(/*Promote*/true); + if (SanOpts.has(SanitizerKind::ArrayBounds)) { + // If the array being accessed has a "counted_by" attribute, generate + // bounds checking code. The "count" field is at the top level of the + // struct or in an anonymous struct, that's also at the top level. Future + // expansions may allow the "count" to reside at any place in the struct, + // but the value of "counted_by" will be a "simple" path to the count, + // i.e. "a.b.count", so we shouldn't need the full force of EmitLValue or + // similar to emit the correct GEP. + const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); + + if (const auto *ME = dyn_cast<MemberExpr>(Array); + ME && + ME->isFlexibleArrayMemberLike(getContext(), StrictFlexArraysLevel) && + ME->getMemberDecl()->hasAttr<CountedByAttr>()) { + const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()); + if (const FieldDecl *CountFD = FindCountedByField(FAMDecl)) { + if (std::optional<int64_t> Diff = + getOffsetDifferenceInBits(*this, CountFD, FAMDecl)) { + CharUnits OffsetDiff = CGM.getContext().toCharUnitsFromBits(*Diff); + + // Create a GEP with a byte offset between the FAM and count and + // use that to load the count value. + Addr = Builder.CreatePointerBitCastOrAddrSpaceCast( + ArrayLV.getAddress(*this), Int8PtrTy, Int8Ty); + + llvm::Type *CountTy = ConvertType(CountFD->getType()); + llvm::Value *Res = Builder.CreateInBoundsGEP( + Int8Ty, Addr.getPointer(), + Builder.getInt32(OffsetDiff.getQuantity()), ".counted_by.gep"); + Res = Builder.CreateAlignedLoad(CountTy, Res, getIntAlign(), + ".counted_by.load"); + + // Now emit the bounds checking. + EmitBoundsCheckImpl(E, Res, Idx, E->getIdx()->getType(), + Array->getType(), Accessed); + } + } + } + } + // Propagate the alignment from the array itself to the result. QualType arrayType = Array->getType(); Addr = emitArraySubscriptGEP( diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGObjCGNU.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGObjCGNU.cpp index 9443fecf9b79..cd1a0b6a130f 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGObjCGNU.cpp @@ -168,6 +168,8 @@ protected: /// Does the current target use SEH-based exceptions? False implies /// Itanium-style DWARF unwinding. bool usesSEHExceptions; + /// Does the current target uses C++-based exceptions? + bool usesCxxExceptions; /// Helper to check if we are targeting a specific runtime version or later. bool isRuntime(ObjCRuntime::Kind kind, unsigned major, unsigned minor=0) { @@ -819,12 +821,18 @@ class CGObjCGNUstep : public CGObjCGNU { SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy, PtrToObjCSuperTy, SelectorTy); // If we're in ObjC++ mode, then we want to make - if (usesSEHExceptions) { - llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); - // void objc_exception_rethrow(void) - ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy); + llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); + if (usesCxxExceptions) { + // void *__cxa_begin_catch(void *e) + EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy); + // void __cxa_end_catch(void) + ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy); + // void objc_exception_rethrow(void*) + ExceptionReThrowFn.init(&CGM, "__cxa_rethrow", PtrTy); + } else if (usesSEHExceptions) { + // void objc_exception_rethrow(void) + ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy); } else if (CGM.getLangOpts().CPlusPlus) { - llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); // void *__cxa_begin_catch(void *e) EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy); // void __cxa_end_catch(void) @@ -833,7 +841,6 @@ class CGObjCGNUstep : public CGObjCGNU { ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, PtrTy); } else if (R.getVersion() >= VersionTuple(1, 7)) { - llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); // id objc_begin_catch(void *e) EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy); // void objc_end_catch(void) @@ -841,7 +848,6 @@ class CGObjCGNUstep : public CGObjCGNU { // void _Unwind_Resume_or_Rethrow(void*) ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, PtrTy); } - llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy); SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy, @@ -2126,6 +2132,9 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend"); usesSEHExceptions = cgm.getContext().getTargetInfo().getTriple().isWindowsMSVCEnvironment(); + usesCxxExceptions = + cgm.getContext().getTargetInfo().getTriple().isOSCygMing() && + isRuntime(ObjCRuntime::GNUstep, 2); CodeGenTypes &Types = CGM.getTypes(); IntTy = cast<llvm::IntegerType>( @@ -2212,7 +2221,10 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, // void objc_exception_throw(id); ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy); - ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy); + ExceptionReThrowFn.init(&CGM, + usesCxxExceptions ? "objc_exception_rethrow" + : "objc_exception_throw", + VoidTy, IdTy); // int objc_sync_enter(id); SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy); // int objc_sync_exit(id); @@ -2389,7 +2401,7 @@ llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) { if (usesSEHExceptions) return CGM.getCXXABI().getAddrOfRTTIDescriptor(T); - if (!CGM.getLangOpts().CPlusPlus) + if (!CGM.getLangOpts().CPlusPlus && !usesCxxExceptions) return CGObjCGNU::GetEHType(T); // For Objective-C++, we want to provide the ability to catch both C++ and @@ -3995,7 +4007,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, ExceptionAsObject = CGF.ObjCEHValueStack.back(); isRethrow = true; } - if (isRethrow && usesSEHExceptions) { + if (isRethrow && (usesSEHExceptions || usesCxxExceptions)) { // For SEH, ExceptionAsObject may be undef, because the catch handler is // not passed it for catchalls and so it is not visible to the catch // funclet. The real thrown object will still be live on the stack at this @@ -4005,8 +4017,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, // argument. llvm::CallBase *Throw = CGF.EmitRuntimeCallOrInvoke(ExceptionReThrowFn); Throw->setDoesNotReturn(); - } - else { + } else { ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy); llvm::CallBase *Throw = CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject); diff --git a/contrib/llvm-project/clang/lib/CodeGen/CodeGenFunction.h b/contrib/llvm-project/clang/lib/CodeGen/CodeGenFunction.h index 07c7678df87e..143ad64e8816 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CodeGenFunction.h +++ b/contrib/llvm-project/clang/lib/CodeGen/CodeGenFunction.h @@ -3073,6 +3073,25 @@ public: /// this expression is used as an lvalue, for instance in "&Arr[Idx]". void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index, QualType IndexType, bool Accessed); + void EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound, + llvm::Value *Index, QualType IndexType, + QualType IndexedType, bool Accessed); + + // Find a struct's flexible array member. It may be embedded inside multiple + // sub-structs, but must still be the last field. + const FieldDecl *FindFlexibleArrayMemberField(ASTContext &Ctx, + const RecordDecl *RD, + StringRef Name, + uint64_t &Offset); + + /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns + /// \p nullptr if either the attribute or the field doesn't exist. + const FieldDecl *FindCountedByField(const FieldDecl *FD); + + /// Build an expression accessing the "counted_by" field. + llvm::Value *EmitCountedByFieldExpr(const Expr *Base, + const FieldDecl *FAMDecl, + const FieldDecl *CountDecl); llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); @@ -4873,6 +4892,9 @@ private: llvm::Value *EmittedE, bool IsDynamic); + llvm::Value *emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, + llvm::IntegerType *ResType); + void emitZeroOrPatternForAutoVarInit(QualType type, const VarDecl &D, Address Loc); diff --git a/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp index 4fd32337cccc..ad6fc71c1e50 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp @@ -1109,6 +1109,8 @@ void CodeGenModule::Release() { if (LangOpts.BranchProtectionPAuthLR) getModule().addModuleFlag(llvm::Module::Min, "branch-protection-pauth-lr", 1); + if (LangOpts.GuardedControlStack) + getModule().addModuleFlag(llvm::Module::Min, "guarded-control-stack", 1); if (LangOpts.hasSignReturnAddress()) getModule().addModuleFlag(llvm::Module::Min, "sign-return-address", 1); if (LangOpts.isSignReturnAddressScopeAll()) diff --git a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp index bf227386a71b..b245abd16c3f 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1712,7 +1712,11 @@ struct CounterCoverageMappingBuilder extendRegion(S->getCond()); Counter ParentCount = getRegion().getCounter(); - Counter ThenCount = getRegionCounter(S); + + // If this is "if !consteval" the then-branch will never be taken, we don't + // need to change counter + Counter ThenCount = + S->isNegatedConsteval() ? ParentCount : getRegionCounter(S); if (!S->isConsteval()) { // Emitting a counter for the condition makes it easier to interpret the @@ -1729,7 +1733,12 @@ struct CounterCoverageMappingBuilder extendRegion(S->getThen()); Counter OutCount = propagateCounts(ThenCount, S->getThen()); - Counter ElseCount = subtractCounters(ParentCount, ThenCount); + // If this is "if consteval" the else-branch will never be taken, we don't + // need to change counter + Counter ElseCount = S->isNonNegatedConsteval() + ? ParentCount + : subtractCounters(ParentCount, ThenCount); + if (const Stmt *Else = S->getElse()) { bool ThenHasTerminateStmt = HasTerminateStmt; HasTerminateStmt = false; diff --git a/contrib/llvm-project/clang/lib/CodeGen/Targets/AArch64.cpp b/contrib/llvm-project/clang/lib/CodeGen/Targets/AArch64.cpp index 7102d190fe00..ee7f95084d2e 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/Targets/AArch64.cpp @@ -138,6 +138,8 @@ public: BPI.BranchTargetEnforcement ? "true" : "false"); Fn->addFnAttr("branch-protection-pauth-lr", BPI.BranchProtectionPAuthLR ? "true" : "false"); + Fn->addFnAttr("guarded-control-stack", + BPI.GuardedControlStack ? "true" : "false"); } bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp index 2d8ef841d4f6..1ee7ae602f3c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp @@ -1508,7 +1508,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, << Triple.getArchName(); StringRef Scope, Key; - bool IndirectBranches, BranchProtectionPAuthLR; + bool IndirectBranches, BranchProtectionPAuthLR, GuardedControlStack; if (A->getOption().matches(options::OPT_msign_return_address_EQ)) { Scope = A->getValue(); @@ -1518,6 +1518,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, Key = "a_key"; IndirectBranches = false; BranchProtectionPAuthLR = false; + GuardedControlStack = false; } else { StringRef DiagMsg; llvm::ARM::ParsedBranchProtection PBP; @@ -1531,6 +1532,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, Key = PBP.Key; BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR; IndirectBranches = PBP.BranchTargetEnforcement; + GuardedControlStack = PBP.GuardedControlStack; } CmdArgs.push_back( @@ -1543,6 +1545,8 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, Args.MakeArgString(Twine("-mbranch-protection-pauth-lr"))); if (IndirectBranches) CmdArgs.push_back("-mbranch-target-enforce"); + if (GuardedControlStack) + CmdArgs.push_back("-mguarded-control-stack"); } void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp index 41eaad3bbad0..03d68c3df7fb 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Flang.h" +#include "Arch/RISCV.h" #include "CommonArgs.h" #include "clang/Basic/CodeGenOptions.h" @@ -14,6 +15,8 @@ #include "llvm/Frontend/Debug/Options.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/RISCVISAInfo.h" +#include "llvm/TargetParser/RISCVTargetParser.h" #include <cassert> @@ -203,6 +206,51 @@ void Flang::AddAArch64TargetArgs(const ArgList &Args, } } +void Flang::AddRISCVTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const llvm::Triple &Triple = getToolChain().getTriple(); + // Handle -mrvv-vector-bits=<bits> + if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) { + StringRef Val = A->getValue(); + const Driver &D = getToolChain().getDriver(); + + // Get minimum VLen from march. + unsigned MinVLen = 0; + StringRef Arch = riscv::getRISCVArch(Args, Triple); + auto ISAInfo = llvm::RISCVISAInfo::parseArchString( + Arch, /*EnableExperimentalExtensions*/ true); + // Ignore parsing error. + if (!errorToBool(ISAInfo.takeError())) + MinVLen = (*ISAInfo)->getMinVLen(); + + // If the value is "zvl", use MinVLen from march. Otherwise, try to parse + // as integer as long as we have a MinVLen. + unsigned Bits = 0; + if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) { + Bits = MinVLen; + } else if (!Val.getAsInteger(10, Bits)) { + // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that + // at least MinVLen. + if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock || + Bits > 65536 || !llvm::isPowerOf2_32(Bits)) + Bits = 0; + } + + // If we got a valid value try to use it. + if (Bits != 0) { + unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock; + CmdArgs.push_back( + Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin))); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin))); + } else if (!Val.equals("scalable")) { + // Handle the unsupported values passed to mrvv-vector-bits. + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Val; + } + } +} + static void addVSDefines(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { @@ -321,6 +369,9 @@ void Flang::addTargetOptions(const ArgList &Args, AddAMDGPUTargetArgs(Args, CmdArgs); break; case llvm::Triple::riscv64: + getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); + AddRISCVTargetArgs(Args, CmdArgs); + break; case llvm::Triple::x86_64: getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); break; @@ -352,12 +403,10 @@ void Flang::addTargetOptions(const ArgList &Args, if (A->getValue() == StringRef{"Accelerate"}) { CmdArgs.push_back("-framework"); CmdArgs.push_back("Accelerate"); - A->render(Args, CmdArgs); } } - } else { - A->render(Args, CmdArgs); } + A->render(Args, CmdArgs); } if (Triple.isKnownWindowsMSVCEnvironment()) { @@ -428,6 +477,8 @@ void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, CmdArgs.push_back("-fopenmp-assume-no-thread-state"); if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); + if (Args.hasArg(options::OPT_nogpulib)) + CmdArgs.push_back("-nogpulib"); } } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h index 8d35080e1c0c..ec2e545a1d0b 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.h @@ -70,6 +70,13 @@ private: void AddAMDGPUTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + /// Add specific options for RISC-V target. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void AddRISCVTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + /// Extract offload options from the driver arguments and add them to /// the command arguments. /// \param [in] C The current compilation for the driver invocation diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp index 24681dfdc99c..771240dac7a8 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2668,7 +2668,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( case llvm::Triple::arm: case llvm::Triple::thumb: LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); - if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::EABIHF) { TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); } else { TripleAliases.append(begin(ARMTriples), end(ARMTriples)); @@ -2677,7 +2679,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( case llvm::Triple::armeb: case llvm::Triple::thumbeb: LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); - if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF || + TargetTriple.getEnvironment() == llvm::Triple::EABIHF) { TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); } else { TripleAliases.append(begin(ARMebTriples), end(ARMebTriples)); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp index 735af54f114c..4300a2bdff17 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp @@ -61,12 +61,16 @@ std::string Linux::getMultiarchTriple(const Driver &D, case llvm::Triple::thumb: if (IsAndroid) return "arm-linux-androideabi"; - if (TargetEnvironment == llvm::Triple::GNUEABIHF) + if (TargetEnvironment == llvm::Triple::GNUEABIHF || + TargetEnvironment == llvm::Triple::MuslEABIHF || + TargetEnvironment == llvm::Triple::EABIHF) return "arm-linux-gnueabihf"; return "arm-linux-gnueabi"; case llvm::Triple::armeb: case llvm::Triple::thumbeb: - if (TargetEnvironment == llvm::Triple::GNUEABIHF) + if (TargetEnvironment == llvm::Triple::GNUEABIHF || + TargetEnvironment == llvm::Triple::MuslEABIHF || + TargetEnvironment == llvm::Triple::EABIHF) return "armeb-linux-gnueabihf"; return "armeb-linux-gnueabi"; case llvm::Triple::x86: diff --git a/contrib/llvm-project/clang/lib/Format/Format.cpp b/contrib/llvm-project/clang/lib/Format/Format.cpp index f798d555bf99..ff5ed6c306f3 100644 --- a/contrib/llvm-project/clang/lib/Format/Format.cpp +++ b/contrib/llvm-project/clang/lib/Format/Format.cpp @@ -76,41 +76,39 @@ template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> { FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/false, /*AcrossEmptyLines=*/false, /*AcrossComments=*/false, /*AlignCompound=*/false, - /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); IO.enumCase(Value, "Consecutive", FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/true, /*AcrossEmptyLines=*/false, /*AcrossComments=*/false, /*AlignCompound=*/false, - /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); IO.enumCase(Value, "AcrossEmptyLines", FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/true, /*AcrossEmptyLines=*/true, /*AcrossComments=*/false, /*AlignCompound=*/false, - /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); IO.enumCase(Value, "AcrossComments", - FormatStyle::AlignConsecutiveStyle({/*Enabled=*/true, - /*AcrossEmptyLines=*/false, - /*AcrossComments=*/true, - /*AlignCompound=*/false, - /*PadOperators=*/true})); + FormatStyle::AlignConsecutiveStyle( + {/*Enabled=*/true, /*AcrossEmptyLines=*/false, + /*AcrossComments=*/true, /*AlignCompound=*/false, + /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); IO.enumCase(Value, "AcrossEmptyLinesAndComments", - FormatStyle::AlignConsecutiveStyle({/*Enabled=*/true, - /*AcrossEmptyLines=*/true, - /*AcrossComments=*/true, - /*AlignCompound=*/false, - /*PadOperators=*/true})); + FormatStyle::AlignConsecutiveStyle( + {/*Enabled=*/true, /*AcrossEmptyLines=*/true, + /*AcrossComments=*/true, /*AlignCompound=*/false, + /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); // For backward compatibility. IO.enumCase(Value, "true", FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/true, /*AcrossEmptyLines=*/false, /*AcrossComments=*/false, /*AlignCompound=*/false, - /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); IO.enumCase(Value, "false", FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/false, /*AcrossEmptyLines=*/false, /*AcrossComments=*/false, /*AlignCompound=*/false, - /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); } static void mapping(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) { @@ -118,6 +116,7 @@ template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> { IO.mapOptional("AcrossEmptyLines", Value.AcrossEmptyLines); IO.mapOptional("AcrossComments", Value.AcrossComments); IO.mapOptional("AlignCompound", Value.AlignCompound); + IO.mapOptional("AlignFunctionPointers", Value.AlignFunctionPointers); IO.mapOptional("PadOperators", Value.PadOperators); } }; @@ -1432,6 +1431,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AlignConsecutiveAssignments.AcrossEmptyLines = false; LLVMStyle.AlignConsecutiveAssignments.AcrossComments = false; LLVMStyle.AlignConsecutiveAssignments.AlignCompound = false; + LLVMStyle.AlignConsecutiveAssignments.AlignFunctionPointers = false; LLVMStyle.AlignConsecutiveAssignments.PadOperators = true; LLVMStyle.AlignConsecutiveBitFields = {}; LLVMStyle.AlignConsecutiveDeclarations = {}; diff --git a/contrib/llvm-project/clang/lib/Format/FormatToken.cpp b/contrib/llvm-project/clang/lib/Format/FormatToken.cpp index 7a2df8c53952..b791c5a26bbe 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatToken.cpp +++ b/contrib/llvm-project/clang/lib/Format/FormatToken.cpp @@ -113,8 +113,8 @@ unsigned CommaSeparatedList::formatAfterToken(LineState &State, if (!State.NextToken || !State.NextToken->Previous) return 0; - if (Formats.size() == 1) - return 0; // Handled by formatFromToken + if (Formats.size() <= 1) + return 0; // Handled by formatFromToken (1) or avoid severe penalty (0). // Ensure that we start on the opening brace. const FormatToken *LBrace = diff --git a/contrib/llvm-project/clang/lib/Format/FormatToken.h b/contrib/llvm-project/clang/lib/Format/FormatToken.h index 3f9664f8f78a..981592aa094a 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatToken.h +++ b/contrib/llvm-project/clang/lib/Format/FormatToken.h @@ -275,14 +275,15 @@ class AnnotatedLine; struct FormatToken { FormatToken() : HasUnescapedNewline(false), IsMultiline(false), IsFirst(false), - MustBreakBefore(false), IsUnterminatedLiteral(false), - CanBreakBefore(false), ClosesTemplateDeclaration(false), - StartsBinaryExpression(false), EndsBinaryExpression(false), - PartOfMultiVariableDeclStmt(false), ContinuesLineCommentSection(false), - Finalized(false), ClosesRequiresClause(false), - EndsCppAttributeGroup(false), BlockKind(BK_Unknown), - Decision(FD_Unformatted), PackingKind(PPK_Inconclusive), - TypeIsFinalized(false), Type(TT_Unknown) {} + MustBreakBefore(false), MustBreakBeforeFinalized(false), + IsUnterminatedLiteral(false), CanBreakBefore(false), + ClosesTemplateDeclaration(false), StartsBinaryExpression(false), + EndsBinaryExpression(false), PartOfMultiVariableDeclStmt(false), + ContinuesLineCommentSection(false), Finalized(false), + ClosesRequiresClause(false), EndsCppAttributeGroup(false), + BlockKind(BK_Unknown), Decision(FD_Unformatted), + PackingKind(PPK_Inconclusive), TypeIsFinalized(false), + Type(TT_Unknown) {} /// The \c Token. Token Tok; @@ -318,6 +319,10 @@ struct FormatToken { /// before the token. unsigned MustBreakBefore : 1; + /// Whether MustBreakBefore is finalized during parsing and must not + /// be reset between runs. + unsigned MustBreakBeforeFinalized : 1; + /// Set to \c true if this token is an unterminated literal. unsigned IsUnterminatedLiteral : 1; @@ -416,10 +421,14 @@ public: /// to another one please use overwriteFixedType, or even better remove the /// need to reassign the type. void setFinalizedType(TokenType T) { + if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg) + return; Type = T; TypeIsFinalized = true; } void overwriteFixedType(TokenType T) { + if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg) + return; TypeIsFinalized = false; setType(T); } diff --git a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp index 8b43438c72df..227aa0b97af6 100644 --- a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp +++ b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp @@ -2769,13 +2769,6 @@ public: // Consume operators with higher precedence. parse(Precedence + 1); - // Do not assign fake parenthesis to tokens that are part of an - // unexpanded macro call. The line within the macro call contains - // the parenthesis and commas, and we will not find operators within - // that structure. - if (Current && Current->MacroParent) - break; - int CurrentPrecedence = getCurrentPrecedence(); if (Precedence == CurrentPrecedence && Current && @@ -2919,6 +2912,13 @@ private: void addFakeParenthesis(FormatToken *Start, prec::Level Precedence, FormatToken *End = nullptr) { + // Do not assign fake parenthesis to tokens that are part of an + // unexpanded macro call. The line within the macro call contains + // the parenthesis and commas, and we will not find operators within + // that structure. + if (Start->MacroParent) + return; + Start->FakeLParens.push_back(Precedence); if (Precedence > prec::Unknown) Start->StartsBinaryExpression = true; diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp b/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp index 56077499c39d..27983a330ac4 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -954,13 +954,15 @@ static void markFinalized(FormatToken *Tok) { // will be modified as unexpanded arguments (as part of the macro call // formatting) in the next pass. Tok->MacroCtx->Role = MR_UnexpandedArg; - // Reset whether spaces are required before this token, as that is context - // dependent, and that context may change when formatting the macro call. - // For example, given M(x) -> 2 * x, and the macro call M(var), - // the token 'var' will have SpacesRequiredBefore = 1 after being + // Reset whether spaces or a line break are required before this token, as + // that is context dependent, and that context may change when formatting + // the macro call. For example, given M(x) -> 2 * x, and the macro call + // M(var), the token 'var' will have SpacesRequiredBefore = 1 after being // formatted as part of the expanded macro, but SpacesRequiredBefore = 0 // for its position within the macro call. Tok->SpacesRequiredBefore = 0; + if (!Tok->MustBreakBeforeFinalized) + Tok->MustBreakBefore = 0; } else { Tok->Finalized = true; } diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp index 684609747a55..50d41c9f57a6 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp @@ -2308,7 +2308,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() { LeftSquare->isCppStructuredBinding(Style)) { return false; } - if (FormatTok->is(tok::l_square)) + if (FormatTok->is(tok::l_square) || tok::isLiteral(FormatTok->Tok.getKind())) return false; if (FormatTok->is(tok::r_square)) { const FormatToken *Next = Tokens->peekNextToken(/*SkipComment=*/true); @@ -4675,6 +4675,7 @@ void UnwrappedLineParser::readToken(int LevelDifference) { conditionalCompilationEnd(); FormatTok = Tokens->getNextToken(); FormatTok->MustBreakBefore = true; + FormatTok->MustBreakBeforeFinalized = true; } auto IsFirstNonCommentOnLine = [](bool FirstNonCommentOnLine, @@ -4891,6 +4892,7 @@ void UnwrappedLineParser::pushToken(FormatToken *Tok) { Line->Tokens.push_back(UnwrappedLineNode(Tok)); if (MustBreakBeforeNextToken) { Line->Tokens.back().Tok->MustBreakBefore = true; + Line->Tokens.back().Tok->MustBreakBeforeFinalized = true; MustBreakBeforeNextToken = false; } } diff --git a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp index 3bc6915b8df0..f1d176f182ff 100644 --- a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp +++ b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp @@ -978,7 +978,14 @@ void WhitespaceManager::alignConsecutiveDeclarations() { AlignTokens( Style, - [](Change const &C) { + [&](Change const &C) { + if (Style.AlignConsecutiveDeclarations.AlignFunctionPointers) { + for (const auto *Prev = C.Tok->Previous; Prev; Prev = Prev->Previous) + if (Prev->is(tok::equal)) + return false; + if (C.Tok->is(TT_FunctionTypeLParen)) + return true; + } if (C.Tok->is(TT_FunctionDeclarationName)) return true; if (C.Tok->isNot(TT_StartOfName)) diff --git a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.h b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.h index 24fe492dcb02..dc6f60e5deee 100644 --- a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.h +++ b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.h @@ -282,6 +282,7 @@ private: for (auto PrevIter = Start; PrevIter != End; ++PrevIter) { // If we broke the line the initial spaces are already // accounted for. + assert(PrevIter->Index < Changes.size()); if (Changes[PrevIter->Index].NewlinesBefore > 0) NetWidth = 0; NetWidth += diff --git a/contrib/llvm-project/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/contrib/llvm-project/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index 8a3d2286cd16..f508408ba706 100644 --- a/contrib/llvm-project/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/contrib/llvm-project/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -611,12 +611,19 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, diag::err_verify_missing_start) << KindStr; continue; } + llvm::SmallString<8> CloseBrace("}}"); + const char *const DelimBegin = PH.C; PH.Advance(); + // Count the number of opening braces for `string` kinds + for (; !D.RegexKind && PH.Next("{"); PH.Advance()) + CloseBrace += '}'; const char* const ContentBegin = PH.C; // mark content begin - // Search for token: }} - if (!PH.SearchClosingBrace("{{", "}}")) { - Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), - diag::err_verify_missing_end) << KindStr; + // Search for closing brace + StringRef OpenBrace(DelimBegin, ContentBegin - DelimBegin); + if (!PH.SearchClosingBrace(OpenBrace, CloseBrace)) { + Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin), + diag::err_verify_missing_end) + << KindStr << CloseBrace; continue; } const char* const ContentEnd = PH.P; // mark content end diff --git a/contrib/llvm-project/clang/lib/Headers/ia32intrin.h b/contrib/llvm-project/clang/lib/Headers/ia32intrin.h index f1904efd71c4..a8b59dfaad89 100644 --- a/contrib/llvm-project/clang/lib/Headers/ia32intrin.h +++ b/contrib/llvm-project/clang/lib/Headers/ia32intrin.h @@ -26,51 +26,48 @@ #define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS #endif -/** Find the first set bit starting from the lsb. Result is undefined if - * input is 0. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> BSF </c> instruction or the - * <c> TZCNT </c> instruction. - * - * \param __A - * A 32-bit integer operand. - * \returns A 32-bit integer containing the bit number. - */ +/// Find the first set bit starting from the lsb. Result is undefined if +/// input is 0. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c BSF instruction or the +/// \c TZCNT instruction. +/// +/// \param __A +/// A 32-bit integer operand. +/// \returns A 32-bit integer containing the bit number. static __inline__ int __DEFAULT_FN_ATTRS_CONSTEXPR __bsfd(int __A) { return __builtin_ctz((unsigned int)__A); } -/** Find the first set bit starting from the msb. Result is undefined if - * input is 0. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> BSR </c> instruction or the - * <c> LZCNT </c> instruction and an <c> XOR </c>. - * - * \param __A - * A 32-bit integer operand. - * \returns A 32-bit integer containing the bit number. - */ +/// Find the first set bit starting from the msb. Result is undefined if +/// input is 0. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c BSR instruction or the +/// \c LZCNT instruction and an \c XOR. +/// +/// \param __A +/// A 32-bit integer operand. +/// \returns A 32-bit integer containing the bit number. static __inline__ int __DEFAULT_FN_ATTRS_CONSTEXPR __bsrd(int __A) { return 31 - __builtin_clz((unsigned int)__A); } -/** Swaps the bytes in the input. Converting little endian to big endian or - * vice versa. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> BSWAP </c> instruction. - * - * \param __A - * A 32-bit integer operand. - * \returns A 32-bit integer containing the swapped bytes. - */ +/// Swaps the bytes in the input. Converting little endian to big endian or +/// vice versa. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c BSWAP instruction. +/// +/// \param __A +/// A 32-bit integer operand. +/// \returns A 32-bit integer containing the swapped bytes. static __inline__ int __DEFAULT_FN_ATTRS_CONSTEXPR __bswapd(int __A) { return (int)__builtin_bswap32((unsigned int)__A); @@ -85,51 +82,48 @@ _bswap(int __A) { #define _bit_scan_reverse(A) __bsrd((A)) #ifdef __x86_64__ -/** Find the first set bit starting from the lsb. Result is undefined if - * input is 0. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> BSF </c> instruction or the - * <c> TZCNT </c> instruction. - * - * \param __A - * A 64-bit integer operand. - * \returns A 32-bit integer containing the bit number. - */ +/// Find the first set bit starting from the lsb. Result is undefined if +/// input is 0. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c BSF instruction or the +/// \c TZCNT instruction. +/// +/// \param __A +/// A 64-bit integer operand. +/// \returns A 32-bit integer containing the bit number. static __inline__ int __DEFAULT_FN_ATTRS_CONSTEXPR __bsfq(long long __A) { return (long long)__builtin_ctzll((unsigned long long)__A); } -/** Find the first set bit starting from the msb. Result is undefined if - * input is 0. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> BSR </c> instruction or the - * <c> LZCNT </c> instruction and an <c> XOR </c>. - * - * \param __A - * A 64-bit integer operand. - * \returns A 32-bit integer containing the bit number. - */ +/// Find the first set bit starting from the msb. Result is undefined if +/// input is 0. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c BSR instruction or the +/// \c LZCNT instruction and an \c XOR. +/// +/// \param __A +/// A 64-bit integer operand. +/// \returns A 32-bit integer containing the bit number. static __inline__ int __DEFAULT_FN_ATTRS_CONSTEXPR __bsrq(long long __A) { return 63 - __builtin_clzll((unsigned long long)__A); } -/** Swaps the bytes in the input. Converting little endian to big endian or - * vice versa. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> BSWAP </c> instruction. - * - * \param __A - * A 64-bit integer operand. - * \returns A 64-bit integer containing the swapped bytes. - */ +/// Swaps the bytes in the input. Converting little endian to big endian or +/// vice versa. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c BSWAP instruction. +/// +/// \param __A +/// A 64-bit integer operand. +/// \returns A 64-bit integer containing the swapped bytes. static __inline__ long long __DEFAULT_FN_ATTRS_CONSTEXPR __bswapq(long long __A) { return (long long)__builtin_bswap64((unsigned long long)__A); @@ -138,18 +132,17 @@ __bswapq(long long __A) { #define _bswap64(A) __bswapq((A)) #endif -/** Counts the number of bits in the source operand having a value of 1. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> POPCNT </c> instruction or a - * a sequence of arithmetic and logic ops to calculate it. - * - * \param __A - * An unsigned 32-bit integer operand. - * \returns A 32-bit integer containing the number of bits with value 1 in the - * source operand. - */ +/// Counts the number of bits in the source operand having a value of 1. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c POPCNT instruction or a +/// a sequence of arithmetic and logic ops to calculate it. +/// +/// \param __A +/// An unsigned 32-bit integer operand. +/// \returns A 32-bit integer containing the number of bits with value 1 in the +/// source operand. static __inline__ int __DEFAULT_FN_ATTRS_CONSTEXPR __popcntd(unsigned int __A) { @@ -159,18 +152,17 @@ __popcntd(unsigned int __A) #define _popcnt32(A) __popcntd((A)) #ifdef __x86_64__ -/** Counts the number of bits in the source operand having a value of 1. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> POPCNT </c> instruction or a - * a sequence of arithmetic and logic ops to calculate it. - * - * \param __A - * An unsigned 64-bit integer operand. - * \returns A 64-bit integer containing the number of bits with value 1 in the - * source operand. - */ +/// Counts the number of bits in the source operand having a value of 1. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c POPCNT instruction or a +/// a sequence of arithmetic and logic ops to calculate it. +/// +/// \param __A +/// An unsigned 64-bit integer operand. +/// \returns A 64-bit integer containing the number of bits with value 1 in the +/// source operand. static __inline__ long long __DEFAULT_FN_ATTRS_CONSTEXPR __popcntq(unsigned long long __A) { @@ -207,123 +199,120 @@ __writeeflags(unsigned int __f) } #endif /* !__x86_64__ */ -/** Cast a 32-bit float value to a 32-bit unsigned integer value - * - * \headerfile <x86intrin.h> - * This intrinsic corresponds to the <c> VMOVD / MOVD </c> instruction in x86_64, - * and corresponds to the <c> VMOVL / MOVL </c> instruction in ia32. - * - * \param __A - * A 32-bit float value. - * \returns a 32-bit unsigned integer containing the converted value. - */ +/// Cast a 32-bit float value to a 32-bit unsigned integer value. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c VMOVD / \c MOVD instruction in x86_64, +/// and corresponds to the \c VMOVL / \c MOVL instruction in ia32. +/// +/// \param __A +/// A 32-bit float value. +/// \returns a 32-bit unsigned integer containing the converted value. static __inline__ unsigned int __DEFAULT_FN_ATTRS_CAST _castf32_u32(float __A) { return __builtin_bit_cast(unsigned int, __A); } -/** Cast a 64-bit float value to a 64-bit unsigned integer value - * - * \headerfile <x86intrin.h> - * This intrinsic corresponds to the <c> VMOVQ / MOVQ </c> instruction in x86_64, - * and corresponds to the <c> VMOVL / MOVL </c> instruction in ia32. - * - * \param __A - * A 64-bit float value. - * \returns a 64-bit unsigned integer containing the converted value. - */ +/// Cast a 64-bit float value to a 64-bit unsigned integer value. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c VMOVQ / \c MOVQ instruction in x86_64, +/// and corresponds to the \c VMOVL / \c MOVL instruction in ia32. +/// +/// \param __A +/// A 64-bit float value. +/// \returns a 64-bit unsigned integer containing the converted value. static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CAST _castf64_u64(double __A) { return __builtin_bit_cast(unsigned long long, __A); } -/** Cast a 32-bit unsigned integer value to a 32-bit float value - * - * \headerfile <x86intrin.h> - * This intrinsic corresponds to the <c> VMOVQ / MOVQ </c> instruction in x86_64, - * and corresponds to the <c> FLDS </c> instruction in ia32. - * - * \param __A - * A 32-bit unsigned integer value. - * \returns a 32-bit float value containing the converted value. - */ +/// Cast a 32-bit unsigned integer value to a 32-bit float value. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c VMOVQ / \c MOVQ instruction in x86_64, +/// and corresponds to the \c FLDS instruction in ia32. +/// +/// \param __A +/// A 32-bit unsigned integer value. +/// \returns a 32-bit float value containing the converted value. static __inline__ float __DEFAULT_FN_ATTRS_CAST _castu32_f32(unsigned int __A) { return __builtin_bit_cast(float, __A); } -/** Cast a 64-bit unsigned integer value to a 64-bit float value - * - * \headerfile <x86intrin.h> - * This intrinsic corresponds to the <c> VMOVQ / MOVQ </c> instruction in x86_64, - * and corresponds to the <c> FLDL </c> instruction in ia32. - * - * \param __A - * A 64-bit unsigned integer value. - * \returns a 64-bit float value containing the converted value. - */ +/// Cast a 64-bit unsigned integer value to a 64-bit float value. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c VMOVQ / \c MOVQ instruction in x86_64, +/// and corresponds to the \c FLDL instruction in ia32. +/// +/// \param __A +/// A 64-bit unsigned integer value. +/// \returns a 64-bit float value containing the converted value. static __inline__ double __DEFAULT_FN_ATTRS_CAST _castu64_f64(unsigned long long __A) { return __builtin_bit_cast(double, __A); } -/** Adds the unsigned integer operand to the CRC-32C checksum of the - * unsigned char operand. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> CRC32B </c> instruction. - * - * \param __C - * An unsigned integer operand to add to the CRC-32C checksum of operand - * \a __D. - * \param __D - * An unsigned 8-bit integer operand used to compute the CRC-32C checksum. - * \returns The result of adding operand \a __C to the CRC-32C checksum of - * operand \a __D. - */ +/// Adds the unsigned integer operand to the CRC-32C checksum of the +/// unsigned char operand. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c CRC32B instruction. +/// +/// \param __C +/// An unsigned integer operand to add to the CRC-32C checksum of operand +/// \a __D. +/// \param __D +/// An unsigned 8-bit integer operand used to compute the CRC-32C checksum. +/// \returns The result of adding operand \a __C to the CRC-32C checksum of +/// operand \a __D. static __inline__ unsigned int __DEFAULT_FN_ATTRS_CRC32 __crc32b(unsigned int __C, unsigned char __D) { return __builtin_ia32_crc32qi(__C, __D); } -/** Adds the unsigned integer operand to the CRC-32C checksum of the - * unsigned short operand. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> CRC32W </c> instruction. - * - * \param __C - * An unsigned integer operand to add to the CRC-32C checksum of operand - * \a __D. - * \param __D - * An unsigned 16-bit integer operand used to compute the CRC-32C checksum. - * \returns The result of adding operand \a __C to the CRC-32C checksum of - * operand \a __D. - */ +/// Adds the unsigned integer operand to the CRC-32C checksum of the +/// unsigned short operand. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c CRC32W instruction. +/// +/// \param __C +/// An unsigned integer operand to add to the CRC-32C checksum of operand +/// \a __D. +/// \param __D +/// An unsigned 16-bit integer operand used to compute the CRC-32C checksum. +/// \returns The result of adding operand \a __C to the CRC-32C checksum of +/// operand \a __D. static __inline__ unsigned int __DEFAULT_FN_ATTRS_CRC32 __crc32w(unsigned int __C, unsigned short __D) { return __builtin_ia32_crc32hi(__C, __D); } -/** Adds the unsigned integer operand to the CRC-32C checksum of the - * second unsigned integer operand. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> CRC32D </c> instruction. - * - * \param __C - * An unsigned integer operand to add to the CRC-32C checksum of operand - * \a __D. - * \param __D - * An unsigned 32-bit integer operand used to compute the CRC-32C checksum. - * \returns The result of adding operand \a __C to the CRC-32C checksum of - * operand \a __D. - */ +/// Adds the unsigned integer operand to the CRC-32C checksum of the +/// second unsigned integer operand. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c CRC32D instruction. +/// +/// \param __C +/// An unsigned integer operand to add to the CRC-32C checksum of operand +/// \a __D. +/// \param __D +/// An unsigned 32-bit integer operand used to compute the CRC-32C checksum. +/// \returns The result of adding operand \a __C to the CRC-32C checksum of +/// operand \a __D. static __inline__ unsigned int __DEFAULT_FN_ATTRS_CRC32 __crc32d(unsigned int __C, unsigned int __D) { @@ -331,21 +320,20 @@ __crc32d(unsigned int __C, unsigned int __D) } #ifdef __x86_64__ -/** Adds the unsigned integer operand to the CRC-32C checksum of the - * unsigned 64-bit integer operand. - * - * \headerfile <x86intrin.h> - * - * This intrinsic corresponds to the <c> CRC32Q </c> instruction. - * - * \param __C - * An unsigned integer operand to add to the CRC-32C checksum of operand - * \a __D. - * \param __D - * An unsigned 64-bit integer operand used to compute the CRC-32C checksum. - * \returns The result of adding operand \a __C to the CRC-32C checksum of - * operand \a __D. - */ +/// Adds the unsigned integer operand to the CRC-32C checksum of the +/// unsigned 64-bit integer operand. +/// +/// \headerfile <x86intrin.h> +/// +/// This intrinsic corresponds to the \c CRC32Q instruction. +/// +/// \param __C +/// An unsigned integer operand to add to the CRC-32C checksum of operand +/// \a __D. +/// \param __D +/// An unsigned 64-bit integer operand used to compute the CRC-32C checksum. +/// \returns The result of adding operand \a __C to the CRC-32C checksum of +/// operand \a __D. static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CRC32 __crc32q(unsigned long long __C, unsigned long long __D) { diff --git a/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp b/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp index c9fcef5b5b5a..734fe90d0d89 100644 --- a/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp +++ b/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp @@ -148,6 +148,7 @@ IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) { // We do C++ by default; append right after argv[0] if no "-x" given ClangArgv.insert(ClangArgv.end(), "-Xclang"); ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions"); + ClangArgv.insert(ClangArgv.end(), "-mcpu=native"); ClangArgv.insert(ClangArgv.end(), "-c"); // Put a dummy C++ file on to ensure there's at least one compile job for the diff --git a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp index b60ae293ef8c..ed684c5d57b1 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseDecl.cpp @@ -2661,7 +2661,12 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( // ProduceConstructorSignatureHelp only on VarDecls. ExpressionStarts = SetPreferredType; } - if (ParseExpressionList(Exprs, ExpressionStarts)) { + + bool SawError = ParseExpressionList(Exprs, ExpressionStarts); + + InitScope.pop(); + + if (SawError) { if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) { Actions.ProduceConstructorSignatureHelp( ThisVarDecl->getType()->getCanonicalTypeInternal(), @@ -2674,7 +2679,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } else { // Match the ')'. T.consumeClose(); - InitScope.pop(); ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), T.getCloseLocation(), diff --git a/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp index 897810557976..dcfd290d39cc 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp @@ -1974,10 +1974,11 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get()); // We try to parse a list of indexes in all language mode first - // and, in we find 0 or one index, we try to parse an OpenMP array + // and, in we find 0 or one index, we try to parse an OpenMP/OpenACC array // section. This allow us to support C++23 multi dimensional subscript and - // OpenMp sections in the same language mode. - if (!getLangOpts().OpenMP || Tok.isNot(tok::colon)) { + // OpenMP/OpenACC sections in the same language mode. + if ((!getLangOpts().OpenMP && !AllowOpenACCArraySections) || + Tok.isNot(tok::colon)) { if (!getLangOpts().CPlusPlus23) { ExprResult Idx; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { @@ -2001,7 +2002,18 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } } - if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) { + // Handle OpenACC first, since 'AllowOpenACCArraySections' is only enabled + // when actively parsing a 'var' in a 'var-list' during clause/'cache' + // parsing, so it is the most specific, and best allows us to handle + // OpenACC and OpenMP at the same time. + if (ArgExprs.size() <= 1 && AllowOpenACCArraySections) { + ColonProtectionRAIIObject RAII(*this); + if (Tok.is(tok::colon)) { + // Consume ':' + ColonLocFirst = ConsumeToken(); + Length = Actions.CorrectDelayedTyposInExpr(ParseExpression()); + } + } else if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) { ColonProtectionRAIIObject RAII(*this); if (Tok.is(tok::colon)) { // Consume ':' @@ -2031,6 +2043,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (!LHS.isInvalid() && !HasError && !Length.isInvalid() && !Stride.isInvalid() && Tok.is(tok::r_square)) { if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) { + // FIXME: OpenACC hasn't implemented Sema/Array section handling at a + // semantic level yet. For now, just reuse the OpenMP implementation + // as it gets the parsing/type management mostly right, and we can + // replace this call to ActOnOpenACCArraySectionExpr in the future. + // Eventually we'll genericize the OPenMPArraySectionExpr type as + // well. LHS = Actions.ActOnOMPArraySectionExpr( LHS.get(), Loc, ArgExprs.empty() ? nullptr : ArgExprs[0], ColonLocFirst, ColonLocSecond, Length.get(), Stride.get(), RLoc); diff --git a/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp b/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp index c9224d3ae910..fc82324e235d 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseOpenACC.cpp @@ -554,49 +554,17 @@ ExprResult Parser::ParseOpenACCIDExpression() { return getActions().CorrectDelayedTyposInExpr(Res); } -/// OpenACC 3.3, section 2.10: -/// A 'var' in a cache directive must be a single array element or a simple -/// subarray. In C and C++, a simple subarray is an array name followed by an -/// extended array range specification in brackets, with a start and length such -/// as: -/// -/// arr[lower:length] -/// -bool Parser::ParseOpenACCCacheVar() { - ExprResult ArrayName = ParseOpenACCIDExpression(); - if (ArrayName.isInvalid()) - return true; - - // If the expression is invalid, just continue parsing the brackets, there - // is likely other useful diagnostics we can emit inside of those. - - BalancedDelimiterTracker SquareBrackets(*this, tok::l_square, - tok::annot_pragma_openacc_end); - - // Square brackets are required, so error here, and try to recover by moving - // until the next comma, or the close paren/end of pragma. - if (SquareBrackets.expectAndConsume()) { - SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end, - Parser::StopBeforeMatch); - return true; - } - - ExprResult Lower = getActions().CorrectDelayedTyposInExpr(ParseExpression()); - if (Lower.isInvalid()) - return true; - - // The 'length' expression is optional, as this could be a single array - // element. If there is no colon, we can treat it as that. - if (getCurToken().is(tok::colon)) { - ConsumeToken(); - ExprResult Length = - getActions().CorrectDelayedTyposInExpr(ParseExpression()); - if (Length.isInvalid()) - return true; - } - - // Diagnose the square bracket being in the wrong place and continue. - return SquareBrackets.consumeClose(); +/// OpenACC 3.3, section 1.6: +/// In this spec, a 'var' (in italics) is one of the following: +/// - a variable name (a scalar, array, or compisite variable name) +/// - a subarray specification with subscript ranges +/// - an array element +/// - a member of a composite variable +/// - a common block name between slashes (fortran only) +bool Parser::ParseOpenACCVar() { + OpenACCArraySectionRAII ArraySections(*this); + ExprResult Res = ParseAssignmentExpression(); + return Res.isInvalid(); } /// OpenACC 3.3, section 2.10: @@ -627,7 +595,16 @@ void Parser::ParseOpenACCCacheVarList() { if (!FirstArray) ExpectAndConsume(tok::comma); FirstArray = false; - if (ParseOpenACCCacheVar()) + + // OpenACC 3.3, section 2.10: + // A 'var' in a cache directive must be a single array element or a simple + // subarray. In C and C++, a simple subarray is an array name followed by + // an extended array range specification in brackets, with a start and + // length such as: + // + // arr[lower:length] + // + if (ParseOpenACCVar()) SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma, StopBeforeMatch); } diff --git a/contrib/llvm-project/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm-project/clang/lib/Sema/SemaDecl.cpp index 8e46c4984d93..e92fd104d78e 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaDecl.cpp @@ -2315,6 +2315,12 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { } ShadowingDecls.erase(ShadowI); } + + if (!getLangOpts().CPlusPlus && S->isClassScope()) { + if (auto *FD = dyn_cast<FieldDecl>(TmpD); + FD && FD->hasAttr<CountedByAttr>()) + CheckCountedByAttr(S, FD); + } } llvm::sort(DeclDiags, diff --git a/contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp index d059b406ef86..1a58cfd8e417 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaDeclAttr.cpp @@ -8460,6 +8460,135 @@ static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(ZeroCallUsedRegsAttr::Create(S.Context, Kind, AL)); } +static void handleCountedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *IL = AL.getArgAsIdent(0); + CountedByAttr *CBA = + ::new (S.Context) CountedByAttr(S.Context, AL, IL->Ident); + CBA->setCountedByFieldLoc(IL->Loc); + D->addAttr(CBA); +} + +static const FieldDecl * +FindFieldInTopLevelOrAnonymousStruct(const RecordDecl *RD, + const IdentifierInfo *FieldName) { + for (const Decl *D : RD->decls()) { + if (const auto *FD = dyn_cast<FieldDecl>(D)) + if (FD->getName() == FieldName->getName()) + return FD; + + if (const auto *R = dyn_cast<RecordDecl>(D)) + if (const FieldDecl *FD = + FindFieldInTopLevelOrAnonymousStruct(R, FieldName)) + return FD; + } + + return nullptr; +} + +bool Sema::CheckCountedByAttr(Scope *S, const FieldDecl *FD) { + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + LangOptions::StrictFlexArraysLevelKind::IncompleteOnly; + if (!Decl::isFlexibleArrayMemberLike(Context, FD, FD->getType(), + StrictFlexArraysLevel, true)) { + // The "counted_by" attribute must be on a flexible array member. + SourceRange SR = FD->getLocation(); + Diag(SR.getBegin(), diag::err_counted_by_attr_not_on_flexible_array_member) + << SR; + return true; + } + + const auto *CBA = FD->getAttr<CountedByAttr>(); + const IdentifierInfo *FieldName = CBA->getCountedByField(); + + auto GetNonAnonStructOrUnion = [](const RecordDecl *RD) { + while (RD && !RD->getDeclName()) + if (const auto *R = dyn_cast<RecordDecl>(RD->getDeclContext())) + RD = R; + else + break; + + return RD; + }; + + const RecordDecl *EnclosingRD = GetNonAnonStructOrUnion(FD->getParent()); + const FieldDecl *CountFD = + FindFieldInTopLevelOrAnonymousStruct(EnclosingRD, FieldName); + + if (!CountFD) { + DeclarationNameInfo NameInfo(FieldName, + CBA->getCountedByFieldLoc().getBegin()); + LookupResult MemResult(*this, NameInfo, Sema::LookupMemberName); + LookupName(MemResult, S); + + if (!MemResult.empty()) { + SourceRange SR = CBA->getCountedByFieldLoc(); + Diag(SR.getBegin(), diag::err_flexible_array_count_not_in_same_struct) + << CBA->getCountedByField() << SR; + + if (auto *ND = MemResult.getAsSingle<NamedDecl>()) { + SR = ND->getLocation(); + Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field) + << ND << SR; + } + + return true; + } else { + // The "counted_by" field needs to exist in the struct. + LookupResult OrdResult(*this, NameInfo, Sema::LookupOrdinaryName); + LookupName(OrdResult, S); + + if (!OrdResult.empty()) { + SourceRange SR = FD->getLocation(); + Diag(SR.getBegin(), diag::err_counted_by_must_be_in_structure) + << FieldName << SR; + + if (auto *ND = OrdResult.getAsSingle<NamedDecl>()) { + SR = ND->getLocation(); + Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field) + << ND << SR; + } + + return true; + } + } + + CXXScopeSpec SS; + DeclFilterCCC<FieldDecl> Filter(FieldName); + return DiagnoseEmptyLookup(S, SS, MemResult, Filter, nullptr, std::nullopt, + const_cast<DeclContext *>(FD->getDeclContext())); + } + + if (CountFD->hasAttr<CountedByAttr>()) { + // The "counted_by" field can't point to the flexible array member. + SourceRange SR = CBA->getCountedByFieldLoc(); + Diag(SR.getBegin(), diag::err_counted_by_attr_refers_to_flexible_array) + << CBA->getCountedByField() << SR; + return true; + } + + if (!CountFD->getType()->isIntegerType() || + CountFD->getType()->isBooleanType()) { + // The "counted_by" field must have an integer type. + SourceRange SR = CBA->getCountedByFieldLoc(); + Diag(SR.getBegin(), + diag::err_flexible_array_counted_by_attr_field_not_integer) + << CBA->getCountedByField() << SR; + + SR = CountFD->getLocation(); + Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field) + << CountFD << SR; + return true; + } + + return false; +} + static void handleFunctionReturnThunksAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef KindStr; @@ -9420,6 +9549,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleAvailableOnlyInDefaultEvalMethod(S, D, AL); break; + case ParsedAttr::AT_CountedBy: + handleCountedByAttr(S, D, AL); + break; + // Microsoft attributes: case ParsedAttr::AT_LayoutVersion: handleLayoutVersion(S, D, AL); diff --git a/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp index 60ad035570c8..2f48ea237cdf 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp @@ -2469,7 +2469,8 @@ bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) { bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef<Expr *> Args, TypoExpr **Out) { + ArrayRef<Expr *> Args, DeclContext *LookupCtx, + TypoExpr **Out) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; @@ -2485,7 +2486,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // unqualified lookup. This is useful when (for example) the // original lookup would not have found something because it was a // dependent name. - DeclContext *DC = SS.isEmpty() ? CurContext : nullptr; + DeclContext *DC = + LookupCtx ? LookupCtx : (SS.isEmpty() ? CurContext : nullptr); while (DC) { if (isa<CXXRecordDecl>(DC)) { LookupQualifiedName(R, DC); @@ -2528,12 +2530,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args, diagnostic, diagnostic_suggest); }, - nullptr, CTK_ErrorRecovery); + nullptr, CTK_ErrorRecovery, LookupCtx); if (*Out) return true; - } else if (S && - (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), - S, &SS, CCC, CTK_ErrorRecovery))) { + } else if (S && (Corrected = + CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, + &SS, CCC, CTK_ErrorRecovery, LookupCtx))) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; @@ -2823,7 +2825,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // a template name, but we happen to have always already looked up the name // before we get here if it must be a template name. if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr, - std::nullopt, &TE)) { + std::nullopt, nullptr, &TE)) { if (TE && KeywordReplacement) { auto &State = getTypoExprState(TE); auto BestTC = State.Consumer->getNextCorrection(); diff --git a/contrib/llvm-project/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm-project/clang/lib/Sema/SemaExprMember.cpp index 2abec3d86a27..32998ae60eaf 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaExprMember.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaExprMember.cpp @@ -782,7 +782,8 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs) { if (BaseType->isDependentType() || - (SS.isSet() && isDependentScopeSpecifier(SS))) + (SS.isSet() && isDependentScopeSpecifier(SS)) || + NameInfo.getName().isDependentName()) return ActOnDependentMemberExpr(Base, BaseType, IsArrow, OpLoc, SS, TemplateKWLoc, FirstQualifierInScope, diff --git a/contrib/llvm-project/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm-project/clang/lib/Sema/SemaOverload.cpp index e6c267bb79e6..64bc38519802 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaOverload.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaOverload.cpp @@ -6056,6 +6056,16 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, diag::err_typecheck_converted_constant_expression_indirect) << From->getType() << From->getSourceRange() << T; } + // 'TryCopyInitialization' returns incorrect info for attempts to bind + // a reference to a bit-field due to C++ [over.ics.ref]p4. Namely, + // 'SCS->DirectBinding' occurs to be set to 'true' despite it is not + // the direct binding according to C++ [dcl.init.ref]p5. Hence, check this + // case explicitly. + if (From->refersToBitField() && T.getTypePtr()->isReferenceType()) { + return S.Diag(From->getBeginLoc(), + diag::err_reference_bind_to_bitfield_in_cce) + << From->getSourceRange(); + } // Usually we can simply apply the ImplicitConversionSequence we formed // earlier, but that's not guaranteed to work when initializing an object of diff --git a/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp index f0b03db69084..21efe25ed84a 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaStmt.cpp @@ -3200,7 +3200,7 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef, // (The function `getTypeSize` returns the size in bits.) ASTContext &Ctx = SemaRef.Context; if (Ctx.getTypeSize(VariableType) <= 64 * 8 && - (VariableType.isTriviallyCopyableType(Ctx) || + (VariableType.isTriviallyCopyConstructibleType(Ctx) || hasTrivialABIAttr(VariableType))) return; diff --git a/contrib/llvm-project/clang/lib/Sema/TreeTransform.h b/contrib/llvm-project/clang/lib/Sema/TreeTransform.h index c8c5a51bf9f9..1a1bc87d2b32 100644 --- a/contrib/llvm-project/clang/lib/Sema/TreeTransform.h +++ b/contrib/llvm-project/clang/lib/Sema/TreeTransform.h @@ -6192,6 +6192,13 @@ bool TreeTransform<Derived>::TransformExceptionSpec( // Instantiate a dynamic noexcept expression, if any. if (isComputedNoexcept(ESI.Type)) { + // Update this scrope because ContextDecl in Sema will be used in + // TransformExpr. + auto *Method = dyn_cast_if_present<CXXMethodDecl>(ESI.SourceTemplate); + Sema::CXXThisScopeRAII ThisScope( + SemaRef, Method ? Method->getParent() : nullptr, + Method ? Method->getMethodQualifiers() : Qualifiers{}, + Method != nullptr); EnterExpressionEvaluationContext Unevaluated( getSema(), Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult NoexceptExpr = getDerived().TransformExpr(ESI.NoexceptExpr); @@ -7732,7 +7739,11 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { if (Then.isInvalid()) return StmtError(); } else { - Then = new (getSema().Context) NullStmt(S->getThen()->getBeginLoc()); + // Discarded branch is replaced with empty CompoundStmt so we can keep + // proper source location for start and end of original branch, so + // subsequent transformations like CoverageMapping work properly + Then = new (getSema().Context) + CompoundStmt(S->getThen()->getBeginLoc(), S->getThen()->getEndLoc()); } // Transform the "else" branch. @@ -7741,6 +7752,13 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { Else = getDerived().TransformStmt(S->getElse()); if (Else.isInvalid()) return StmtError(); + } else if (S->getElse() && ConstexprConditionValue && + *ConstexprConditionValue) { + // Same thing here as with <then> branch, we are discarding it, we can't + // replace it with NULL nor NullStmt as we need to keep for source location + // range, for CoverageMapping + Else = new (getSema().Context) + CompoundStmt(S->getElse()->getBeginLoc(), S->getElse()->getEndLoc()); } if (!getDerived().AlwaysRebuild() && diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 034825d88a44..3b36565681a7 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -2201,6 +2201,25 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( ErrnoNEZeroIrrelevant, GenericFailureMsg) .ArgConstraint(NotNull(ArgNo(0)))); + // int ungetc(int c, FILE *stream); + addToFunctionSummaryMap( + "ungetc", Signature(ArgTypes{IntTy, FilePtrTy}, RetType{IntTy}), + Summary(NoEvalCall) + .Case({ReturnValueCondition(BO_EQ, ArgNo(0)), + ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})}, + ErrnoMustNotBeChecked, GenericSuccessMsg) + .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)), + ArgumentCondition(0, WithinRange, {{EOFv, EOFv}})}, + ErrnoNEZeroIrrelevant, + "Assuming that 'ungetc' fails because EOF was passed as " + "character") + .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv)), + ArgumentCondition(0, WithinRange, {{0, UCharRangeMax}})}, + ErrnoNEZeroIrrelevant, GenericFailureMsg) + .ArgConstraint(ArgumentCondition( + 0, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})) + .ArgConstraint(NotNull(ArgNo(1)))); + // int fseek(FILE *stream, long offset, int whence); // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use // these for condition of arg 2. @@ -2255,7 +2274,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( addToFunctionSummaryMap( "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}), Summary(NoEvalCall) - .Case({ReturnValueCondition(WithinRange, Range(1, LongMax))}, + .Case({ReturnValueCondition(WithinRange, Range(0, LongMax))}, ErrnoUnchanged, GenericSuccessMsg) .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg) .ArgConstraint(NotNull(ArgNo(0)))); diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 25da3c18e851..742426a628e0 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -263,10 +263,17 @@ private: {{{"fputs"}, 2}, {std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, false), std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, false), 1}}, + {{{"ungetc"}, 2}, + {std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, false), + std::bind(&StreamChecker::evalUngetc, _1, _2, _3, _4), 1}}, {{{"fseek"}, 3}, {&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}}, + {{{"fseeko"}, 3}, + {&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}}, {{{"ftell"}, 1}, {&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}}, + {{{"ftello"}, 1}, + {&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}}, {{{"fflush"}, 1}, {&StreamChecker::preFflush, &StreamChecker::evalFflush, 0}}, {{{"rewind"}, 1}, @@ -332,6 +339,9 @@ private: void evalFputx(const FnDescription *Desc, const CallEvent &Call, CheckerContext &C, bool IsSingleChar) const; + void evalUngetc(const FnDescription *Desc, const CallEvent &Call, + CheckerContext &C) const; + void preFseek(const FnDescription *Desc, const CallEvent &Call, CheckerContext &C) const; void evalFseek(const FnDescription *Desc, const CallEvent &Call, @@ -916,6 +926,45 @@ void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call, C.addTransition(StateFailed); } +void StreamChecker::evalUngetc(const FnDescription *Desc, const CallEvent &Call, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol(); + if (!StreamSym) + return; + + const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); + if (!CE) + return; + + const StreamState *OldSS = State->get<StreamMap>(StreamSym); + if (!OldSS) + return; + + assertStreamStateOpened(OldSS); + + // Generate a transition for the success state. + std::optional<NonLoc> PutVal = Call.getArgSVal(0).getAs<NonLoc>(); + if (!PutVal) + return; + ProgramStateRef StateNotFailed = + State->BindExpr(CE, C.getLocationContext(), *PutVal); + StateNotFailed = + StateNotFailed->set<StreamMap>(StreamSym, StreamState::getOpened(Desc)); + C.addTransition(StateNotFailed); + + // Add transition for the failed state. + // Failure of 'ungetc' does not result in feof or ferror state. + // If the PutVal has value of EofVal the function should "fail", but this is + // the same transition as the success state. + // In this case only one state transition is added by the analyzer (the two + // new states may be similar). + ProgramStateRef StateFailed = bindInt(*EofVal, State, C, CE); + StateFailed = + StateFailed->set<StreamMap>(StreamSym, StreamState::getOpened(Desc)); + C.addTransition(StateFailed); +} + void StreamChecker::preFseek(const FnDescription *Desc, const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); @@ -1068,10 +1117,10 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call, NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>(); ProgramStateRef StateNotFailed = State->BindExpr(CE, C.getLocationContext(), RetVal); - auto Cond = SVB.evalBinOp(State, BO_GE, RetVal, - SVB.makeZeroVal(C.getASTContext().LongTy), - SVB.getConditionType()) - .getAs<DefinedOrUnknownSVal>(); + auto Cond = + SVB.evalBinOp(State, BO_GE, RetVal, SVB.makeZeroVal(Call.getResultType()), + SVB.getConditionType()) + .getAs<DefinedOrUnknownSVal>(); if (!Cond) return; StateNotFailed = StateNotFailed->assume(*Cond, true); @@ -1079,7 +1128,7 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call, return; ProgramStateRef StateFailed = State->BindExpr( - CE, C.getLocationContext(), SVB.makeIntVal(-1, C.getASTContext().LongTy)); + CE, C.getLocationContext(), SVB.makeIntVal(-1, Call.getResultType())); // This function does not affect the stream state. // Still we add success and failure state with the appropriate return value. diff --git a/contrib/llvm-project/clang/tools/clang-format/ClangFormat.cpp b/contrib/llvm-project/clang/tools/clang-format/ClangFormat.cpp index be34dbbe886a..49ab7677a3ee 100644 --- a/contrib/llvm-project/clang/tools/clang-format/ClangFormat.cpp +++ b/contrib/llvm-project/clang/tools/clang-format/ClangFormat.cpp @@ -571,6 +571,11 @@ static int dumpConfig(bool IsSTDIN) { return 0; } +using String = SmallString<128>; +static String IgnoreDir; // Directory of .clang-format-ignore file. +static String PrevDir; // Directory of previous `FilePath`. +static SmallVector<String> Patterns; // Patterns in .clang-format-ignore file. + // Check whether `FilePath` is ignored according to the nearest // .clang-format-ignore file based on the rules below: // - A blank line is skipped. @@ -586,33 +591,50 @@ static bool isIgnored(StringRef FilePath) { if (!is_regular_file(FilePath)) return false; - using namespace llvm::sys::path; - SmallString<128> Path, AbsPath{FilePath}; + String Path; + String AbsPath{FilePath}; + using namespace llvm::sys::path; make_absolute(AbsPath); remove_dots(AbsPath, /*remove_dot_dot=*/true); - StringRef IgnoreDir{AbsPath}; - do { - IgnoreDir = parent_path(IgnoreDir); - if (IgnoreDir.empty()) + if (StringRef Dir{parent_path(AbsPath)}; PrevDir != Dir) { + PrevDir = Dir; + + for (;;) { + Path = Dir; + append(Path, ".clang-format-ignore"); + if (is_regular_file(Path)) + break; + Dir = parent_path(Dir); + if (Dir.empty()) + return false; + } + + IgnoreDir = convert_to_slash(Dir); + + std::ifstream IgnoreFile{Path.c_str()}; + if (!IgnoreFile.good()) return false; - Path = IgnoreDir; - append(Path, ".clang-format-ignore"); - } while (!is_regular_file(Path)); + Patterns.clear(); - std::ifstream IgnoreFile{Path.c_str()}; - if (!IgnoreFile.good()) - return false; + for (std::string Line; std::getline(IgnoreFile, Line);) { + if (const auto Pattern{StringRef{Line}.trim()}; + // Skip empty and comment lines. + !Pattern.empty() && Pattern[0] != '#') { + Patterns.push_back(Pattern); + } + } + } - const auto Pathname = convert_to_slash(AbsPath); - for (std::string Line; std::getline(IgnoreFile, Line);) { - auto Pattern = StringRef(Line).trim(); - if (Pattern.empty() || Pattern[0] == '#') - continue; + if (IgnoreDir.empty()) + return false; - const bool IsNegated = Pattern[0] == '!'; + const auto Pathname{convert_to_slash(AbsPath)}; + for (const auto &Pat : Patterns) { + const bool IsNegated = Pat[0] == '!'; + StringRef Pattern{Pat}; if (IsNegated) Pattern = Pattern.drop_front(); @@ -620,11 +642,14 @@ static bool isIgnored(StringRef FilePath) { continue; Pattern = Pattern.ltrim(); + + // `Pattern` is relative to `IgnoreDir` unless it starts with a slash. + // This doesn't support patterns containing drive names (e.g. `C:`). if (Pattern[0] != '/') { - Path = convert_to_slash(IgnoreDir); + Path = IgnoreDir; append(Path, Style::posix, Pattern); remove_dots(Path, /*remove_dot_dot=*/true, Style::posix); - Pattern = Path.str(); + Pattern = Path; } if (clang::format::matchFilePath(Pattern, Pathname) == !IsNegated) |