diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2019-01-27 16:55:49 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2019-01-27 16:55:49 +0000 |
commit | d2b88c64b549558966af5953df1c67566469d7f6 (patch) | |
tree | fde23164f74edc9d75011244cc82cefe9fae7b31 /gnu/llvm/tools | |
parent | b6a478d7aa2abf7e6e7aeb293b0c77a6b00edb64 (diff) |
Merge LLVM 7.0.1 release.
With fixes from mortimer@ (thanks!)
Tested by many, especially naddy@ (thanks!)
Diffstat (limited to 'gnu/llvm/tools')
39 files changed, 11706 insertions, 7478 deletions
diff --git a/gnu/llvm/tools/clang/docs/CommandGuide/clang.rst b/gnu/llvm/tools/clang/docs/CommandGuide/clang.rst index ec702c3bbac..0725bf04e2c 100644 --- a/gnu/llvm/tools/clang/docs/CommandGuide/clang.rst +++ b/gnu/llvm/tools/clang/docs/CommandGuide/clang.rst @@ -98,10 +98,129 @@ Language Selection and Mode Options Treat subsequent input files as having type language. -.. option:: -std=<language> +.. option:: -std=<standard> Specify the language standard to compile for. + Supported values for the C language are: + + | ``c89`` + | ``c90`` + | ``iso9899:1990`` + + ISO C 1990 + + | ``iso9899:199409`` + + ISO C 1990 with amendment 1 + + | ``gnu89`` + | ``gnu90`` + + ISO C 1990 with GNU extensions + + | ``c99`` + | ``iso9899:1999`` + + ISO C 1999 + + | ``gnu99`` + + ISO C 1999 with GNU extensions + + | ``c11`` + | ``iso9899:2011`` + + ISO C 2011 + + | ``gnu11`` + + ISO C 2011 with GNU extensions + + | ``c17`` + | ``iso9899:2017`` + + ISO C 2017 + + | ``gnu17`` + + ISO C 2017 with GNU extensions + + The default C language standard is ``gnu11``, except on PS4, where it is + ``gnu99``. + + Supported values for the C++ language are: + + | ``c++98`` + | ``c++03`` + + ISO C++ 1998 with amendments + + | ``gnu++98`` + | ``gnu++03`` + + ISO C++ 1998 with amendments and GNU extensions + + | ``c++11`` + + ISO C++ 2011 with amendments + + | ``gnu++11`` + + ISO C++ 2011 with amendments and GNU extensions + + | ``c++14`` + + ISO C++ 2014 with amendments + + | ``gnu++14`` + + ISO C++ 2014 with amendments and GNU extensions + + | ``c++17`` + + ISO C++ 2017 with amendments + + | ``gnu++17`` + + ISO C++ 2017 with amendments and GNU extensions + + | ``c++2a`` + + Working draft for ISO C++ 2020 + + | ``gnu++2a`` + + Working draft for ISO C++ 2020 with GNU extensions + + The default C++ language standard is ``gnu++14``. + + Supported values for the OpenCL language are: + + | ``cl1.0`` + + OpenCL 1.0 + + | ``cl1.1`` + + OpenCL 1.1 + + | ``cl1.2`` + + OpenCL 1.2 + + | ``cl2.0`` + + OpenCL 2.0 + + The default OpenCL language standard is ``cl1.0``. + + Supported values for the CUDA language are: + + | ``cuda`` + + NVIDIA CUDA(tm) + .. option:: -stdlib=<library> Specify the C++ standard library to use; supported options are libstdc++ and diff --git a/gnu/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h b/gnu/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h index e9f77f5dec6..f9d2eb786ff 100644 --- a/gnu/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h +++ b/gnu/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h @@ -238,7 +238,7 @@ public: const char *toString() const; bool isPrintfKind() const { return IsPrintf; } - + Optional<ConversionSpecifier> getStandardSpecifier() const; protected: @@ -258,18 +258,26 @@ public: private: const Kind K; QualType T; - const char *Name; - bool Ptr; + const char *Name = nullptr; + bool Ptr = false; + + /// The TypeKind identifies certain well-known types like size_t and + /// ptrdiff_t. + enum class TypeKind { DontCare, SizeT, PtrdiffT }; + TypeKind TK = TypeKind::DontCare; + public: - ArgType(Kind k = UnknownTy, const char *n = nullptr) - : K(k), Name(n), Ptr(false) {} - ArgType(QualType t, const char *n = nullptr) - : K(SpecificTy), T(t), Name(n), Ptr(false) {} - ArgType(CanQualType t) : K(SpecificTy), T(t), Name(nullptr), Ptr(false) {} + ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {} + ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {} + ArgType(CanQualType T) : K(SpecificTy), T(T) {} static ArgType Invalid() { return ArgType(InvalidTy); } bool isValid() const { return K != InvalidTy; } + bool isSizeT() const { return TK == TypeKind::SizeT; } + + bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; } + /// Create an ArgType which corresponds to the type pointer to A. static ArgType PtrTo(const ArgType& A) { assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown"); @@ -278,6 +286,21 @@ public: return Res; } + /// Create an ArgType which corresponds to the size_t/ssize_t type. + static ArgType makeSizeT(const ArgType &A) { + ArgType Res = A; + Res.TK = TypeKind::SizeT; + return Res; + } + + /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t + /// type. + static ArgType makePtrdiffT(const ArgType &A) { + ArgType Res = A; + Res.TK = TypeKind::PtrdiffT; + return Res; + } + MatchKind matchesType(ASTContext &C, QualType argTy) const; QualType getRepresentativeType(ASTContext &C) const; @@ -512,7 +535,7 @@ public: return getConversionSpecifier().consumesDataArgument(); } - /// \brief Returns the builtin type that a data argument + /// Returns the builtin type that a data argument /// paired with this format specifier should have. This method /// will return null if the format specifier does not have /// a matching data argument or the matching argument matches diff --git a/gnu/llvm/tools/clang/include/clang/Basic/Builtins.def b/gnu/llvm/tools/clang/include/clang/Basic/Builtins.def index 3d4deb5ed30..9089ce1b659 100644 --- a/gnu/llvm/tools/clang/include/clang/Basic/Builtins.def +++ b/gnu/llvm/tools/clang/include/clang/Basic/Builtins.def @@ -48,8 +48,8 @@ // . -> "...". This may only occur at the end of the function list. // // Types may be prefixed with the following modifiers: -// L -> long (e.g. Li for 'long int') -// LL -> long long +// L -> long (e.g. Li for 'long int', Ld for 'long double') +// LL -> long long (e.g. LLi for 'long long int', LLd for __float128) // LLL -> __int128_t (e.g. LLLi) // W -> int64_t // N -> 'int' size if target is LP64, 'L' otherwise. @@ -89,9 +89,10 @@ // S:N: -> similar to the s:N: attribute, but the function is like vscanf // in that it accepts its arguments as a va_list rather than // through an ellipsis -// e -> const, but only when -fmath-errno=0 +// e -> const, but only when -fno-math-errno // j -> returns_twice (like setjmp) // u -> arguments are not evaluated for their side-effects +// V:N: -> requires vectors of at least N bits to be legal // FIXME: gcc has nonnull #if defined(BUILTIN) && !defined(LIBBUILTIN) @@ -110,9 +111,11 @@ BUILTIN(__builtin_abs , "ii" , "ncF") BUILTIN(__builtin_copysign, "ddd", "ncF") BUILTIN(__builtin_copysignf, "fff", "ncF") BUILTIN(__builtin_copysignl, "LdLdLd", "ncF") +BUILTIN(__builtin_copysignf128, "LLdLLdLLd", "ncF") BUILTIN(__builtin_fabs , "dd" , "ncF") BUILTIN(__builtin_fabsf, "ff" , "ncF") BUILTIN(__builtin_fabsl, "LdLd", "ncF") +BUILTIN(__builtin_fabsf128, "LLdLLd", "ncF") BUILTIN(__builtin_fmod , "ddd" , "Fne") BUILTIN(__builtin_fmodf, "fff" , "Fne") BUILTIN(__builtin_fmodl, "LdLdLd", "Fne") @@ -122,9 +125,11 @@ BUILTIN(__builtin_frexpl, "LdLdi*", "Fn") BUILTIN(__builtin_huge_val, "d", "nc") BUILTIN(__builtin_huge_valf, "f", "nc") BUILTIN(__builtin_huge_vall, "Ld", "nc") +BUILTIN(__builtin_huge_valf128, "LLd", "nc") BUILTIN(__builtin_inf , "d" , "nc") BUILTIN(__builtin_inff , "f" , "nc") BUILTIN(__builtin_infl , "Ld" , "nc") +BUILTIN(__builtin_inff128 , "LLd" , "nc") BUILTIN(__builtin_labs , "LiLi" , "Fnc") BUILTIN(__builtin_llabs, "LLiLLi", "Fnc") BUILTIN(__builtin_ldexp , "ddi" , "Fne") @@ -133,12 +138,14 @@ BUILTIN(__builtin_ldexpl, "LdLdi", "Fne") BUILTIN(__builtin_modf , "ddd*" , "Fn") BUILTIN(__builtin_modff, "fff*" , "Fn") BUILTIN(__builtin_modfl, "LdLdLd*", "Fn") -BUILTIN(__builtin_nan, "dcC*" , "ncF") -BUILTIN(__builtin_nanf, "fcC*" , "ncF") -BUILTIN(__builtin_nanl, "LdcC*", "ncF") -BUILTIN(__builtin_nans, "dcC*" , "ncF") -BUILTIN(__builtin_nansf, "fcC*" , "ncF") -BUILTIN(__builtin_nansl, "LdcC*", "ncF") +BUILTIN(__builtin_nan, "dcC*" , "FnU") +BUILTIN(__builtin_nanf, "fcC*" , "FnU") +BUILTIN(__builtin_nanl, "LdcC*", "FnU") +BUILTIN(__builtin_nanf128, "LLdcC*", "FnU") +BUILTIN(__builtin_nans, "dcC*" , "FnU") +BUILTIN(__builtin_nansf, "fcC*" , "FnU") +BUILTIN(__builtin_nansl, "LdcC*", "FnU") +BUILTIN(__builtin_nansf128, "LLdcC*", "FnU") BUILTIN(__builtin_powi , "ddi" , "Fnc") BUILTIN(__builtin_powif, "ffi" , "Fnc") BUILTIN(__builtin_powil, "LdLdi", "Fnc") @@ -715,6 +722,10 @@ ATOMIC_BUILTIN(__opencl_atomic_fetch_xor, "v.", "t") ATOMIC_BUILTIN(__opencl_atomic_fetch_min, "v.", "t") ATOMIC_BUILTIN(__opencl_atomic_fetch_max, "v.", "t") +// GCC does not support these, they are a Clang extension. +ATOMIC_BUILTIN(__atomic_fetch_min, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_max, "v.", "t") + #undef ATOMIC_BUILTIN // Non-overloaded atomic builtins. @@ -734,6 +745,14 @@ BUILTIN(__builtin_rindex, "c*cC*i", "Fn") LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__annotation, "wC*.","n", ALL_MS_LANGUAGES) LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_bittest, "UcNiC*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_bittestandcomplement, "UcNi*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_bittestandreset, "UcNi*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_bittestandset, "UcNi*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_bittest64, "UcWiC*Wi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_bittestandcomplement64, "UcWi*Wi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_bittestandreset64, "UcWi*Wi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_bittestandset64, "UcWi*Wi", "n", ALL_MS_LANGUAGES) LIBBUILTIN(_byteswap_ushort, "UsUs", "fnc", "stdlib.h", ALL_MS_LANGUAGES) LIBBUILTIN(_byteswap_ulong, "UNiUNi", "fnc", "stdlib.h", ALL_MS_LANGUAGES) LIBBUILTIN(_byteswap_uint64, "ULLiULLi", "fnc", "stdlib.h", ALL_MS_LANGUAGES) @@ -773,7 +792,16 @@ LANGBUILTIN(_InterlockedOr, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedXor8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedXor16, "ssD*s", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedXor, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_interlockedbittestandset, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandreset, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandreset64, "UcWiD*Wi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandreset_acq, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandreset_nf, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandreset_rel, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandset, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandset64, "UcWiD*Wi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandset_acq, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandset_nf, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandset_rel, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES) LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES) @@ -796,6 +824,10 @@ LANGBUILTIN(__fastfail, "vUi", "nr", ALL_MS_LANGUAGES) LIBBUILTIN(_setjmpex, "iJ", "fj", "setjmpex.h", ALL_MS_LANGUAGES) // C99 library functions +// C99 stdarg.h +LIBBUILTIN(va_start, "vA.", "fn", "stdarg.h", ALL_LANGUAGES) +LIBBUILTIN(va_end, "vA", "fn", "stdarg.h", ALL_LANGUAGES) +LIBBUILTIN(va_copy, "vAA", "fn", "stdarg.h", ALL_LANGUAGES) // C99 stdlib.h LIBBUILTIN(abort, "v", "fr", "stdlib.h", ALL_LANGUAGES) LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h", ALL_LANGUAGES) @@ -803,6 +835,13 @@ LIBBUILTIN(exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES) LIBBUILTIN(_Exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES) LIBBUILTIN(malloc, "v*z", "f", "stdlib.h", ALL_LANGUAGES) LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(strtod, "dcC*c**", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(strtof, "fcC*c**", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(strtold, "LdcC*c**", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(strtol, "LicC*c**i", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(strtoll, "LLicC*c**i", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(strtoul, "ULicC*c**i", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(strtoull, "ULLicC*c**i", "f", "stdlib.h", ALL_LANGUAGES) // C99 string.h LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(memcmp, "ivC*vC*z", "f", "string.h", ALL_LANGUAGES) @@ -826,6 +865,7 @@ LIBBUILTIN(memset, "v*v*iz", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(strerror, "c*i", "f", "string.h", ALL_LANGUAGES) LIBBUILTIN(strlen, "zcC*", "f", "string.h", ALL_LANGUAGES) // C99 stdio.h +// FIXME: This list is incomplete. LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h", ALL_LANGUAGES) LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES) LIBBUILTIN(snprintf, "ic*zcC*.", "fp:2:", "stdio.h", ALL_LANGUAGES) @@ -840,6 +880,10 @@ LIBBUILTIN(sscanf, "icC*RcC*R.", "fs:1:", "stdio.h", ALL_LANGUAGES) LIBBUILTIN(vscanf, "icC*Ra", "fS:0:", "stdio.h", ALL_LANGUAGES) LIBBUILTIN(vfscanf, "iP*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES) LIBBUILTIN(vsscanf, "icC*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(fopen, "P*cC*cC*", "f", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(fread, "zv*zzP*", "f", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(fwrite, "zvC*zzP*", "f", "stdio.h", ALL_LANGUAGES) + // C99 ctype.h LIBBUILTIN(isalnum, "ii", "fnU", "ctype.h", ALL_LANGUAGES) LIBBUILTIN(isalpha, "ii", "fnU", "ctype.h", ALL_LANGUAGES) @@ -912,7 +956,7 @@ LIBBUILTIN(strlcpy, "zc*cC*z", "f", "string.h", ALL_GNU_LANGUAGES) LIBBUILTIN(strlcat, "zc*cC*z", "f", "string.h", ALL_GNU_LANGUAGES) // id objc_msgSend(id, SEL, ...) LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG) -// long double objc_msgSend_fpret(id self, SEL op, ...) +// long double objc_msgSend_fpret(id self, SEL op, ...) LIBBUILTIN(objc_msgSend_fpret, "LdGH.", "f", "objc/message.h", OBJC_LANG) // _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...) LIBBUILTIN(objc_msgSend_fp2ret, "XLdGH.", "f", "objc/message.h", OBJC_LANG) @@ -1361,12 +1405,15 @@ BUILTIN(__builtin_smulll_overflow, "bSLLiCSLLiCSLLi*", "n") // Clang builtins (not available in GCC). BUILTIN(__builtin_addressof, "v*v&", "nct") -BUILTIN(__builtin_operator_new, "v*z", "c") -BUILTIN(__builtin_operator_delete, "vv*", "n") +BUILTIN(__builtin_operator_new, "v*z", "tc") +BUILTIN(__builtin_operator_delete, "vv*", "tn") BUILTIN(__builtin_char_memchr, "c*cC*iz", "n") +BUILTIN(__builtin_dump_struct, "ivC*v*", "tn") // Safestack builtins BUILTIN(__builtin___get_unsafe_stack_start, "v*", "Fn") +BUILTIN(__builtin___get_unsafe_stack_bottom, "v*", "Fn") +BUILTIN(__builtin___get_unsafe_stack_top, "v*", "Fn") BUILTIN(__builtin___get_unsafe_stack_ptr, "v*", "Fn") // Nontemporal loads/stores builtins @@ -1381,6 +1428,7 @@ BUILTIN(__builtin_coro_promise, "v*v*IiIb", "n") BUILTIN(__builtin_coro_size, "z", "n") BUILTIN(__builtin_coro_frame, "v*", "n") +BUILTIN(__builtin_coro_noop, "v*", "n") BUILTIN(__builtin_coro_free, "v*v*", "n") BUILTIN(__builtin_coro_id, "v*Iiv*v*v*", "n") @@ -1443,6 +1491,7 @@ LANGBUILTIN(omp_is_initial_device, "i", "nc", OMP_LANG) // Builtins for XRay BUILTIN(__xray_customevent, "vcC*z", "") +BUILTIN(__xray_typedevent, "vzcC*z", "") // Win64-compatible va_list functions BUILTIN(__builtin_ms_va_start, "vc*&.", "nt") diff --git a/gnu/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td b/gnu/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td index 2d471f1fa5a..c0128f56a59 100644 --- a/gnu/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td +++ b/gnu/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td @@ -31,6 +31,10 @@ def AutoDisableVptrSanitizer : DiagGroup<"auto-disable-vptr-sanitizer">; def Availability : DiagGroup<"availability">; def Section : DiagGroup<"section">; def AutoImport : DiagGroup<"auto-import">; +def FrameworkHdrQuotedInclude : DiagGroup<"quoted-include-in-framework-header">; +def FrameworkIncludePrivateFromPublic : + DiagGroup<"framework-include-private-from-public">; +def FrameworkHdrAtImport : DiagGroup<"atimport-in-framework-header">; def CXX14BinaryLiteral : DiagGroup<"c++14-binary-literal">; def CXXPre14CompatBinaryLiteral : DiagGroup<"c++98-c++11-compat-binary-literal">; def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">; @@ -68,6 +72,7 @@ def UnsupportedNan : DiagGroup<"unsupported-nan">; def UnsupportedAbs : DiagGroup<"unsupported-abs">; def UnsupportedCB : DiagGroup<"unsupported-cb">; def UnsupportedGPOpt : DiagGroup<"unsupported-gpopt">; +def UnsupportedTargetOpt : DiagGroup<"unsupported-target-opt">; def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">; def NullConversion : DiagGroup<"null-conversion">; def ImplicitConversionFloatingPointToBool : @@ -116,6 +121,7 @@ def DeprecatedDynamicExceptionSpec def DeprecatedImplementations :DiagGroup<"deprecated-implementations">; def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">; def DeprecatedRegister : DiagGroup<"deprecated-register">; +def DeprecatedThisCapture : DiagGroup<"deprecated-this-capture">; def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings", [CXX11CompatDeprecatedWritableStr]>; // FIXME: Why is DeprecatedImplementations not in this group? @@ -124,6 +130,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAttributes, DeprecatedDynamicExceptionSpec, DeprecatedIncrementBool, DeprecatedRegister, + DeprecatedThisCapture, DeprecatedWritableStr]>, DiagCategory<"Deprecations">; @@ -151,8 +158,10 @@ def Exceptions : DiagGroup<"exceptions">; def GNUEmptyInitializer : DiagGroup<"gnu-empty-initializer">; def GNUEmptyStruct : DiagGroup<"gnu-empty-struct">; def ExtraTokens : DiagGroup<"extra-tokens">; +def CXX98CompatExtraSemi : DiagGroup<"c++98-compat-extra-semi">; def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">; -def ExtraSemi : DiagGroup<"extra-semi", [CXX11ExtraSemi]>; +def ExtraSemi : DiagGroup<"extra-semi", [CXX98CompatExtraSemi, + CXX11ExtraSemi]>; def GNUFlexibleArrayInitializer : DiagGroup<"gnu-flexible-array-initializer">; def GNUFlexibleArrayUnionMember : DiagGroup<"gnu-flexible-array-union-member">; @@ -196,6 +205,7 @@ def CXX98Compat : DiagGroup<"c++98-compat", def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat, CXX98CompatBindToTemporaryCopy, + CXX98CompatExtraSemi, CXXPre14CompatPedantic, CXXPre17CompatPedantic, CXXPre2aCompatPedantic]>; @@ -263,6 +273,11 @@ def ShiftOpParentheses: DiagGroup<"shift-op-parentheses">; def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">; def DanglingElse: DiagGroup<"dangling-else">; def DanglingField : DiagGroup<"dangling-field">; +def DanglingInitializerList : DiagGroup<"dangling-initializer-list">; +def ReturnStackAddress : DiagGroup<"return-stack-address">; +def Dangling : DiagGroup<"dangling", [DanglingField, + DanglingInitializerList, + ReturnStackAddress]>; def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">; def ExpansionToDefined : DiagGroup<"expansion-to-defined">; def FlagEnum : DiagGroup<"flag-enum">; @@ -273,7 +288,7 @@ def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">; def : DiagGroup<"import">; def GNUIncludeNext : DiagGroup<"gnu-include-next">; def IncompatibleMSStruct : DiagGroup<"incompatible-ms-struct">; -def IncompatiblePointerTypesDiscardsQualifiers +def IncompatiblePointerTypesDiscardsQualifiers : DiagGroup<"incompatible-pointer-types-discards-qualifiers">; def IncompatibleFunctionPointerTypes : DiagGroup<"incompatible-function-pointer-types">; @@ -282,6 +297,8 @@ def IncompatiblePointerTypes [IncompatiblePointerTypesDiscardsQualifiers, IncompatibleFunctionPointerTypes]>; def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">; +def IncompleteFrameworkModuleDeclaration + : DiagGroup<"incomplete-framework-module-declaration">; def NonModularIncludeInFrameworkModule : DiagGroup<"non-modular-include-in-framework-module">; def NonModularIncludeInModule : DiagGroup<"non-modular-include-in-module", @@ -347,7 +364,6 @@ def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; def NullPointerArithmetic : DiagGroup<"null-pointer-arithmetic">; def : DiagGroup<"effc++", [NonVirtualDtor]>; def OveralignedType : DiagGroup<"over-aligned">; -def AlignedAllocationUnavailable : DiagGroup<"aligned-allocation-unavailable">; def OldStyleCast : DiagGroup<"old-style-cast">; def : DiagGroup<"old-style-definition">; def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">; @@ -380,7 +396,11 @@ def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; def Packed : DiagGroup<"packed">; def Padded : DiagGroup<"padded">; + def PessimizingMove : DiagGroup<"pessimizing-move">; +def ReturnStdMoveInCXX11 : DiagGroup<"return-std-move-in-c++11">; +def ReturnStdMove : DiagGroup<"return-std-move">; + def PointerArith : DiagGroup<"pointer-arith">; def PoundWarning : DiagGroup<"#warnings">; def PoundPragmaMessage : DiagGroup<"#pragma-messages">, @@ -391,13 +411,13 @@ def RedeclaredClassMember : DiagGroup<"redeclared-class-member">; def GNURedeclaredEnum : DiagGroup<"gnu-redeclared-enum">; def RedundantMove : DiagGroup<"redundant-move">; def Register : DiagGroup<"register", [DeprecatedRegister]>; -def ReturnStackAddress : DiagGroup<"return-stack-address">; def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">; def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>; def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy", [CXX98CompatBindToTemporaryCopy]>; def SelfAssignmentField : DiagGroup<"self-assign-field">; -def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentField]>; +def SelfAssignmentOverloaded : DiagGroup<"self-assign-overloaded">; +def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentOverloaded, SelfAssignmentField]>; def SelfMove : DiagGroup<"self-move">; def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">; def Sentinel : DiagGroup<"sentinel">; @@ -426,6 +446,13 @@ def : DiagGroup<"synth">; def SizeofArrayArgument : DiagGroup<"sizeof-array-argument">; def SizeofArrayDecay : DiagGroup<"sizeof-array-decay">; def SizeofPointerMemaccess : DiagGroup<"sizeof-pointer-memaccess">; +def MemsetTransposedArgs : DiagGroup<"memset-transposed-args">; +def DynamicClassMemaccess : DiagGroup<"dynamic-class-memaccess">; +def NonTrivialMemaccess : DiagGroup<"nontrivial-memaccess">; +def SuspiciousBzero : DiagGroup<"suspicious-bzero">; +def SuspiciousMemaccess : DiagGroup<"suspicious-memaccess", + [SizeofPointerMemaccess, DynamicClassMemaccess, + NonTrivialMemaccess, MemsetTransposedArgs, SuspiciousBzero]>; def StaticInInline : DiagGroup<"static-in-inline">; def StaticLocalInInline : DiagGroup<"static-local-in-inline">; def GNUStaticFloatInit : DiagGroup<"gnu-static-float-init">; @@ -512,8 +539,13 @@ def UninitializedStaticSelfInit : DiagGroup<"static-self-init">; def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes, UninitializedStaticSelfInit]>; def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">; +// #pragma optimize is often used to avoid to work around MSVC codegen bugs or +// to disable inlining. It's not completely clear what alternative to suggest +// (#pragma clang optimize, noinline) so suggest nothing for now. +def IgnoredPragmaOptimize : DiagGroup<"ignored-pragma-optimize">; def UnknownPragmas : DiagGroup<"unknown-pragmas">; -def IgnoredPragmas : DiagGroup<"ignored-pragmas", [IgnoredPragmaIntrinsic]>; +def IgnoredPragmas : DiagGroup<"ignored-pragmas", + [IgnoredPragmaIntrinsic, IgnoredPragmaOptimize]>; def PragmaClangAttribute : DiagGroup<"pragma-clang-attribute">; def PragmaPackSuspiciousInclude : DiagGroup<"pragma-pack-suspicious-include">; def PragmaPack : DiagGroup<"pragma-pack", [PragmaPackSuspiciousInclude]>; @@ -715,7 +747,12 @@ def IntToVoidPointerCast : DiagGroup<"int-to-void-pointer-cast">; def IntToPointerCast : DiagGroup<"int-to-pointer-cast", [IntToVoidPointerCast]>; -def Move : DiagGroup<"move", [PessimizingMove, RedundantMove, SelfMove]>; +def Move : DiagGroup<"move", [ + PessimizingMove, + RedundantMove, + ReturnStdMove, + SelfMove + ]>; def Extra : DiagGroup<"extra", [ MissingFieldInitializers, @@ -762,14 +799,14 @@ def Most : DiagGroup<"most", [ UserDefinedWarnings ]>; -// Thread Safety warnings +// Thread Safety warnings def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">; def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">; def ThreadSafetyPrecise : DiagGroup<"thread-safety-precise">; def ThreadSafetyReference : DiagGroup<"thread-safety-reference">; def ThreadSafetyNegative : DiagGroup<"thread-safety-negative">; def ThreadSafety : DiagGroup<"thread-safety", - [ThreadSafetyAttributes, + [ThreadSafetyAttributes, ThreadSafetyAnalysis, ThreadSafetyPrecise, ThreadSafetyReference]>; @@ -988,3 +1025,7 @@ def SpirCompat : DiagGroup<"spir-compat">; // Warning for the experimental-isel options. def ExperimentalISel : DiagGroup<"experimental-isel">; + +// A warning group specifically for warnings related to function +// multiversioning. +def FunctionMultiVersioning : DiagGroup<"function-multiversion">; diff --git a/gnu/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/gnu/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index b15d6990b3b..653bc00e6ce 100644 --- a/gnu/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/gnu/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -203,6 +203,8 @@ def ext_imaginary_constant : Extension< def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup<GNUComplexInteger>; +def err_invalid_saturation_spec : Error<"'_Sat' specifier is only valid on " + "'_Fract' or '_Accum', not '%0'">; def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">; def err_invalid_width_spec : Error< "'%select{|short|long|long long}0 %1' is invalid">; @@ -241,7 +243,7 @@ def err_invalid_vector_double_decl_spec : Error < "(available on POWER7 or later)">; def err_invalid_vector_long_long_decl_spec : Error < "use of 'long long' with '__vector bool' requires VSX support (available on " - "POWER7 or later) or extended Altivec support (available on POWER8 or later) " + "POWER7 or later) or extended Altivec support (available on POWER8 or later) " "to be enabled">; def err_invalid_vector_long_double_decl_spec : Error< "cannot use 'long double' with '__vector'">; @@ -272,6 +274,14 @@ def warn_mips_interrupt_attribute : Warning< "MIPS 'interrupt' attribute only applies to functions that have " "%select{no parameters|a 'void' return type}0">, InGroup<IgnoredAttributes>; +def warn_riscv_repeated_interrupt_attribute : Warning< + "repeated RISC-V 'interrupt' attribute">, InGroup<IgnoredAttributes>; +def note_riscv_repeated_interrupt_attribute : Note< + "repeated RISC-V 'interrupt' attribute is here">; +def warn_riscv_interrupt_attribute : Warning< + "RISC-V 'interrupt' attribute only applies to functions that have " + "%select{no parameters|a 'void' return type}0">, + InGroup<IgnoredAttributes>; def warn_unused_parameter : Warning<"unused parameter %0">, InGroup<UnusedParameter>, DefaultIgnore; def warn_unused_variable : Warning<"unused variable %0">, @@ -279,7 +289,7 @@ def warn_unused_variable : Warning<"unused variable %0">, def warn_unused_local_typedef : Warning< "unused %select{typedef|type alias}0 %1">, InGroup<UnusedLocalTypedef>, DefaultIgnore; -def warn_unused_property_backing_ivar : +def warn_unused_property_backing_ivar : Warning<"ivar %0 which backs the property is not " "referenced in this property's accessor">, InGroup<UnusedPropertyIvar>, DefaultIgnore; @@ -378,7 +388,7 @@ def err_inline_non_function : Error< "'inline' can only appear on functions%select{| and non-local variables}0">; def err_noreturn_non_function : Error< "'_Noreturn' can only appear on functions">; -def warn_qual_return_type : Warning< +def warn_qual_return_type : Warning< "'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">, InGroup<IgnoredQualifiers>, DefaultIgnore; def warn_deprecated_redundant_constexpr_static_def : Warning< @@ -602,9 +612,12 @@ def warn_redecl_library_builtin : Warning< "incompatible redeclaration of library function %0">, InGroup<DiagGroup<"incompatible-library-redeclaration">>; def err_builtin_definition : Error<"definition of builtin function %0">; +def err_builtin_redeclare : Error<"cannot redeclare builtin function %0">; def err_arm_invalid_specialreg : Error<"invalid special register for builtin">; def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">; def err_invalid_cpu_is : Error<"invalid cpu name for builtin">; +def err_invalid_cpu_specific_dispatch_value : Error< +"invalid option '%0' for %select{cpu_specific|cpu_dispatch}1">; def err_builtin_needs_feature : Error<"%0 needs target feature %1">; def err_function_needs_feature : Error<"always_inline function %1 requires target feature '%2', but would " @@ -612,16 +625,23 @@ def err_function_needs_feature "'%2'">; def warn_builtin_unknown : Warning<"use of unknown builtin %0">, InGroup<ImplicitFunctionDeclare>, DefaultError; +def warn_cstruct_memaccess : Warning< + "%select{destination for|source of|first operand of|second operand of}0 this " + "%1 call is a pointer to record %2 that is not trivial to " + "%select{primitive-default-initialize|primitive-copy}3">, + InGroup<NonTrivialMemaccess>; +def note_nontrivial_field : Note< + "field is non-trivial to %select{copy|default-initialize}0">; def warn_dyn_class_memaccess : Warning< "%select{destination for|source of|first operand of|second operand of}0 this " "%1 call is a pointer to %select{|class containing a }2dynamic class %3; " "vtable pointer will be %select{overwritten|copied|moved|compared}4">, - InGroup<DiagGroup<"dynamic-class-memaccess">>; + InGroup<DynamicClassMemaccess>; def note_bad_memaccess_silence : Note< "explicitly cast the pointer to silence this warning">; def warn_sizeof_pointer_expr_memaccess : Warning< - "'%0' call operates on objects of type %1 while the size is based on a " - "different type %2">, + "'%0' call operates on objects of type %1 while the size is based on a " + "different type %2">, InGroup<SizeofPointerMemaccess>; def warn_sizeof_pointer_expr_memaccess_note : Note< "did you mean to %select{dereference the argument to 'sizeof' (and multiply " @@ -645,16 +665,28 @@ def note_memsize_comparison_paren : Note< "did you mean to compare the result of %0 instead?">; def note_memsize_comparison_cast_silence : Note< "explicitly cast the argument to size_t to silence this warning">; - +def warn_suspicious_sizeof_memset : Warning< + "%select{'size' argument to memset is '0'|" + "setting buffer to a 'sizeof' expression}0" + "; did you mean to transpose the last two arguments?">, + InGroup<MemsetTransposedArgs>; +def note_suspicious_sizeof_memset_silence : Note< + "%select{parenthesize the third argument|" + "cast the second argument to 'int'}0 to silence">; +def warn_suspicious_bzero_size : Warning<"'size' argument to bzero is '0'">, + InGroup<SuspiciousBzero>; +def note_suspicious_bzero_size_silence : Note< + "parenthesize the second argument to silence">; + def warn_strncat_large_size : Warning< - "the value of the size argument in 'strncat' is too large, might lead to a " + "the value of the size argument in 'strncat' is too large, might lead to a " "buffer overflow">, InGroup<StrncatSize>; -def warn_strncat_src_size : Warning<"size argument in 'strncat' call appears " +def warn_strncat_src_size : Warning<"size argument in 'strncat' call appears " "to be size of the source">, InGroup<StrncatSize>; def warn_strncat_wrong_size : Warning< "the value of the size argument to 'strncat' is wrong">, InGroup<StrncatSize>; def note_strncat_wrong_size : Note< - "change the argument to be the free space in the destination buffer minus " + "change the argument to be the free space in the destination buffer minus " "the terminating null byte">; def warn_assume_side_effects : Warning< @@ -751,7 +783,7 @@ def note_pragma_pack_pop_instead_reset : Note< "did you intend to use '#pragma pack (pop)' instead of '#pragma pack()'?">; // Follow the Microsoft implementation. def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">; -def warn_pragma_pack_pop_identifer_and_alignment : Warning< +def warn_pragma_pack_pop_identifier_and_alignment : Warning< "specifying both a name and alignment to 'pop' is undefined">; def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">, InGroup<IgnoredPragmas>; @@ -759,6 +791,10 @@ def warn_cxx_ms_struct : Warning<"ms_struct may not produce Microsoft-compatible layouts for classes " "with base classes or virtual functions">, DefaultError, InGroup<IncompatibleMSStruct>; +def warn_npot_ms_struct : + Warning<"ms_struct may not produce Microsoft-compatible layouts with fundamental " + "data types with sizes that aren't a power of two">, + DefaultError, InGroup<IncompatibleMSStruct>; def err_section_conflict : Error<"%0 causes a section type conflict with %1">; def err_no_base_classes : Error<"invalid use of '__super', %0 has no base classes">; def err_invalid_super_scope : Error<"invalid use of '__super', " @@ -994,15 +1030,15 @@ def note_property_attribute : Note<"property %0 is declared " "%select{deprecated|unavailable|partial}1 here">; def err_setter_type_void : Error<"type of setter must be void">; def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; -def warn_duplicate_method_decl : - Warning<"multiple declarations of method %0 found and ignored">, +def warn_duplicate_method_decl : + Warning<"multiple declarations of method %0 found and ignored">, InGroup<MethodDuplicate>, DefaultIgnore; def warn_objc_cdirective_format_string : Warning<"using %0 directive in %select{NSString|CFString}1 " "which is being passed as a formatting argument to the formatting " "%select{method|CFfunction}2">, InGroup<ObjCCStringFormat>, DefaultIgnore; -def err_objc_var_decl_inclass : +def err_objc_var_decl_inclass : Error<"cannot declare variable inside @interface or @protocol">; def err_missing_method_context : Error< "missing context for method declaration">; @@ -1027,7 +1063,7 @@ def warn_objc_pointer_masking : Warning< def warn_objc_pointer_masking_performSelector : Warning<warn_objc_pointer_masking.Text>, InGroup<ObjCPointerIntrospectPerformSelector>; def warn_objc_property_default_assign_on_object : Warning< - "default property attribute 'assign' not appropriate for non-GC object">, + "default property attribute 'assign' not appropriate for object">, InGroup<ObjCPropertyNoAttribute>; def warn_property_attr_mismatch : Warning< "property attribute in class extension does not match the primary class">, @@ -1214,7 +1250,7 @@ def warn_auto_implicit_atomic_property : Warning< "property is assumed atomic when auto-synthesizing the property">, InGroup<ImplicitAtomic>, DefaultIgnore; def warn_unimplemented_selector: Warning< - "no method with selector %0 is implemented in this translation unit">, + "no method with selector %0 is implemented in this translation unit">, InGroup<Selector>, DefaultIgnore; def warn_unimplemented_protocol_method : Warning< "method %0 in protocol %1 not implemented">, InGroup<Protocol>; @@ -1325,7 +1361,7 @@ def err_invalid_member_in_interface : Error< "nested class }0%1 is not permitted within an interface type">; def err_invalid_base_in_interface : Error< "interface type cannot inherit from " - "%select{'struct|non-public 'interface|'class}0 %1'">; + "%select{struct|non-public interface|class}0 %1">; def err_abstract_type_in_decl : Error< "%select{return|parameter|variable|field|instance variable|" @@ -1343,7 +1379,7 @@ def err_capture_default_non_local : Error< "non-local lambda expression cannot have a capture-default">; def err_multiple_final_overriders : Error< - "virtual function %q0 has more than one final overrider in %1">; + "virtual function %q0 has more than one final overrider in %1">; def note_final_overrider : Note<"final overrider of %q0 in %1">; def err_type_defined_in_type_specifier : Error< @@ -1385,7 +1421,7 @@ def warn_weak_template_vtable : Warning< def ext_using_undefined_std : ExtWarn< "using directive refers to implicitly-defined namespace 'std'">; - + // C++ exception specifications def err_exception_spec_in_typedef : Error< "exception specifications are not allowed in %select{typedefs|type aliases}0">; @@ -1439,7 +1475,7 @@ def ext_ms_using_declaration_inaccessible : ExtWarn< "to accessible member '%1') is a Microsoft compatibility extension">, AccessControl, InGroup<MicrosoftUsingDecl>; def err_access_ctor : Error< - "calling a %select{private|protected}0 constructor of class %2">, + "calling a %select{private|protected}0 constructor of class %2">, AccessControl; def ext_rvalue_to_reference_access_ctor : Extension< "C++98 requires an accessible copy constructor for class %2 when binding " @@ -1462,7 +1498,7 @@ def err_access_friend_function : Error< AccessControl; def err_access_dtor : Error< - "calling a %select{private|protected}1 destructor of class %0">, + "calling a %select{private|protected}1 destructor of class %0">, AccessControl; def err_access_dtor_base : Error<"base class %0 has %select{private|protected}1 destructor">, @@ -1504,7 +1540,7 @@ def note_access_protected_restricted_object : Note< def warn_cxx98_compat_sfinae_access_control : Warning< "substitution failure due to access control is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore, NoSFINAE; - + // C++ name lookup def err_incomplete_nested_name_spec : Error< "incomplete type %0 named in nested name specifier">; @@ -1582,6 +1618,8 @@ def err_not_integral_type_bitfield : Error< "bit-field %0 has non-integral type %1">; def err_not_integral_type_anon_bitfield : Error< "anonymous bit-field has non-integral type %0">; +def err_anon_bitfield_qualifiers : Error< + "anonymous bit-field cannot have qualifiers">; def err_member_function_initialization : Error< "initializer on function does not look like a pure-specifier">; def err_non_virtual_pure : Error< @@ -1608,13 +1646,16 @@ def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning< "overrides of %0 in subclasses are not available in the " "%select{constructor|destructor}1 of %2">; +def select_special_member_kind : TextSubstitution< + "%select{default constructor|copy constructor|move constructor|" + "copy assignment operator|move assignment operator|destructor}0">; + def note_member_declared_at : Note<"member is declared here">; def note_ivar_decl : Note<"instance variable is declared here">; def note_bitfield_decl : Note<"bit-field is declared here">; def note_implicit_param_decl : Note<"%0 is an implicit parameter">; def note_member_synthesized_at : Note< - "in implicit %select{default constructor|copy constructor|move constructor|" - "copy assignment operator|move assignment operator|destructor}0 for %1 " + "in implicit %sub{select_special_member_kind}0 for %1 " "first required here">; def err_missing_default_ctor : Error< "%select{constructor for %1 must explicitly initialize the|" @@ -1623,16 +1664,14 @@ def err_missing_default_ctor : Error< "%select{base class|member}2 %3 %select{which|which|of %1}0 " "does not have a default constructor">; def note_due_to_dllexported_class : Note< - "due to '%0' being dllexported%select{|; try compiling in C++11 mode}1">; + "due to %0 being dllexported%select{|; try compiling in C++11 mode}1">; def err_illegal_union_or_anon_struct_member : Error< "%select{anonymous struct|union}0 member %1 has a non-trivial " - "%select{constructor|copy constructor|move constructor|copy assignment " - "operator|move assignment operator|destructor}2">; + "%sub{select_special_member_kind}2">; def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning< "%select{anonymous struct|union}0 member %1 with a non-trivial " - "%select{constructor|copy constructor|move constructor|copy assignment " - "operator|move assignment operator|destructor}2 is incompatible with C++98">, + "%sub{select_special_member_kind}2 is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; def note_nontrivial_virtual_dtor : Note< @@ -1651,8 +1690,7 @@ def note_nontrivial_no_copy : Note< "%select{base class|field|an object}0 of type %3">; def note_nontrivial_user_provided : Note< "because %select{base class of |field of |}0type %1 has a user-provided " - "%select{default constructor|copy constructor|move constructor|" - "copy assignment operator|move assignment operator|destructor}2">; + "%sub{select_special_member_kind}2">; def note_nontrivial_in_class_init : Note< "because field %0 has an initializer">; def note_nontrivial_param_type : Note< @@ -1695,6 +1733,8 @@ def warn_overriding_method_missing_noescape : Warning< "__attribute__((noescape))">, InGroup<MissingNoEscape>; def note_overridden_marked_noescape : Note< "parameter of overridden method is annotated with __attribute__((noescape))">; +def note_cat_conform_to_noescape_prot : Note< + "%select{category|class extension}0 conforms to protocol %1 which defines method %2">; def err_covariant_return_inaccessible_base : Error< "invalid covariant return for virtual function: %1 is a " @@ -1719,9 +1759,7 @@ def err_covariant_return_type_class_type_more_qualified : Error< // C++ implicit special member functions def note_in_declaration_of_implicit_special_member : Note< - "while declaring the implicit " - "%select{default constructor|copy constructor|move constructor|" - "copy assignment operator|move assignment operator|destructor}1" + "while declaring the implicit %sub{select_special_member_kind}1" " for %0">; // C++ constructors @@ -1776,7 +1814,8 @@ def err_destructor_template : Error< // C++ initialization def err_init_conversion_failed : Error< - "cannot initialize %select{a variable|a parameter|return object|an " + "cannot initialize %select{a variable|a parameter|return object|" + "statement expression result|an " "exception object|a member subobject|an array element|a new value|a value|a " "base class|a constructor delegation|a vector element|a block element|a " "block element|a complex element|a lambda capture|a compound literal " @@ -1816,10 +1855,6 @@ def err_reference_bind_failed : Error< "type $|could not bind to %select{rvalue|lvalue}1 of incompatible type}0,2">; def err_reference_bind_init_list : Error< "reference to type %0 cannot bind to an initializer list">; -def warn_temporary_array_to_pointer_decay : Warning< - "pointer is initialized by a temporary array, which will be destroyed at the " - "end of the full-expression">, - InGroup<DiagGroup<"address-of-array-temporary">>; def err_init_list_bad_dest_type : Error< "%select{|non-aggregate }0type %1 cannot be initialized with an initializer " "list">; @@ -1911,34 +1946,29 @@ def warn_unsequenced_mod_mod : Warning< def warn_unsequenced_mod_use : Warning< "unsequenced modification and access to %0">, InGroup<Unsequenced>; +def select_initialized_entity_kind : TextSubstitution< + "%select{copying variable|copying parameter|" + "returning object|initializing statement expression result|" + "throwing object|copying member subobject|copying array element|" + "allocating object|copying temporary|initializing base subobject|" + "initializing vector element|capturing value}0">; + def err_temp_copy_no_viable : Error< - "no viable constructor %select{copying variable|copying parameter|" - "returning object|throwing object|copying member subobject|copying array " - "element|allocating object|copying temporary|initializing base subobject|" - "initializing vector element|capturing value}0 of type %1">; + "no viable constructor %sub{select_initialized_entity_kind}0 of type %1">; def ext_rvalue_to_reference_temp_copy_no_viable : Extension< - "no viable constructor %select{copying variable|copying parameter|" - "returning object|throwing object|copying member subobject|copying array " - "element|allocating object|copying temporary|initializing base subobject|" - "initializing vector element|capturing value}0 of type %1; C++98 requires a copy " - "constructor when binding a reference to a temporary">, + "no viable constructor %sub{select_initialized_entity_kind}0 of type %1; " + "C++98 requires a copy constructor when binding a reference to a temporary">, InGroup<BindToTemporaryCopy>; def err_temp_copy_ambiguous : Error< - "ambiguous constructor call when %select{copying variable|copying " - "parameter|returning object|throwing object|copying member subobject|copying " - "array element|allocating object|copying temporary|initializing base subobject|" - "initializing vector element|capturing value}0 of type %1">; + "ambiguous constructor call when %sub{select_initialized_entity_kind}0 " + "of type %1">; def err_temp_copy_deleted : Error< - "%select{copying variable|copying parameter|returning object|throwing " - "object|copying member subobject|copying array element|allocating object|" - "copying temporary|initializing base subobject|initializing vector element|" - "capturing value}0 of type %1 invokes deleted constructor">; + "%sub{select_initialized_entity_kind}0 of type %1 " + "invokes deleted constructor">; def err_temp_copy_incomplete : Error< "copying a temporary object of incomplete type %0">; def warn_cxx98_compat_temp_copy : Warning< - "%select{copying variable|copying parameter|returning object|throwing " - "object|copying member subobject|copying array element|allocating object|" - "copying temporary|initializing base subobject|initializing vector element}1 " + "%sub{select_initialized_entity_kind}1 " "of type %2 when binding a reference to a temporary would %select{invoke " "an inaccessible constructor|find no viable constructor|find ambiguous " "constructors|invoke a deleted constructor}0 in C++98">, @@ -1951,7 +1981,7 @@ def note_explicit_ctor_deduction_guide_here : Note< // C++11 decltype def err_decltype_in_declarator : Error< "'decltype' cannot be used to name a declaration">; - + // C++11 auto def warn_cxx98_compat_auto_type_specifier : Warning< "'auto' type specifier is incompatible with C++98">, @@ -2035,10 +2065,6 @@ def err_implied_std_initializer_list_not_found : Error< "not found; include <initializer_list>">; def err_malformed_std_initializer_list : Error< "std::initializer_list must be a class template with a single type parameter">; -def warn_dangling_std_initializer_list : Warning< - "array backing the initializer list will be destroyed at the end of " - "%select{the full-expression|the constructor}0">, - InGroup<DiagGroup<"dangling-initializer-list">>; def err_auto_init_list_from_c : Error< "cannot use __auto_type with initializer list in C">; def err_auto_bitfield : Error< @@ -2103,9 +2129,16 @@ def err_deduction_guide_explicit_mismatch : Error< def err_deduction_guide_specialized : Error<"deduction guide cannot be " "%select{explicitly instantiated|explicitly specialized}0">; def err_deduction_guide_template_not_deducible : Error< - "deduction guide template contains " - "%select{a template parameter|template parameters}0 that cannot be " - "deduced">; + "deduction guide template contains " + "%select{a template parameter|template parameters}0 that cannot be " + "deduced">; +def err_deduction_guide_wrong_access : Error< + "deduction guide has different access from the corresponding " + "member template">; +def note_deduction_guide_template_access : Note< + "member template declared %0 here">; +def note_deduction_guide_access : Note< + "deduction guide declared %0 by intervening access specifier">; // C++1y deduced return types def err_auto_fn_deduction_failure : Error< @@ -2367,6 +2400,8 @@ def note_non_literal_user_provided_dtor : Note< "%0 is not literal because it has a user-provided destructor">; def note_non_literal_nontrivial_dtor : Note< "%0 is not literal because it has a non-trivial destructor">; +def note_non_literal_lambda : Note< + "lambda closure types are non-literal types before C++17">; def warn_private_extern : Warning< "use of __private_extern__ on a declaration may not produce external symbol " "private to the linkage unit and is deprecated">, InGroup<PrivateExtern>; @@ -2407,6 +2442,9 @@ def err_template_different_associated_constraints : Error< def warn_cxx98_compat_unicode_type : Warning< "'%0' type specifier is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx17_compat_unicode_type : Warning< + "'char8_t' type specifier is incompatible with C++ standards before C++20">, + InGroup<CXXPre2aCompat>, DefaultIgnore; // __make_integer_seq def err_integer_sequence_negative_length : Error< @@ -2445,8 +2483,8 @@ def err_attribute_requires_positive_integer : Error< def err_attribute_requires_opencl_version : Error< "%0 attribute requires OpenCL version %1%select{| or above}2">; def warn_unsupported_target_attribute - : Warning<"ignoring %select{unsupported|duplicate}0" - "%select{| architecture}1 '%2' in the target attribute string">, + : Warning<"%select{unsupported|duplicate}0%select{| architecture}1 '%2' in" + " the 'target' attribute string; 'target' attribute ignored">, InGroup<IgnoredAttributes>; def err_attribute_unsupported : Error<"%0 attribute is not supported for this target">; @@ -2550,6 +2588,9 @@ def err_attribute_address_space_too_high : Error< "address space is larger than the maximum supported (%0)">; def err_attribute_address_multiple_qualifiers : Error< "multiple address spaces specified for type">; +def warn_attribute_address_multiple_identical_qualifiers : Warning< + "multiple identical address spaces specified for type">, + InGroup<DuplicateDeclSpecifier>; def err_attribute_address_function_type : Error< "function type may not be qualified with an address space">; def err_as_qualified_auto_decl : Error< @@ -2593,7 +2634,7 @@ def warn_objc_literal_comparison : Warning< def err_missing_atsign_prefix : Error< "string literal must be prefixed by '@' ">; def warn_objc_string_literal_comparison : Warning< - "direct comparison of a string literal has undefined behavior">, + "direct comparison of a string literal has undefined behavior">, InGroup<ObjCStringComparison>; def warn_concatenated_nsarray_literal : Warning< "concatenated NSString literal for an NSArray expression - " @@ -2643,11 +2684,19 @@ def err_only_annotate_after_access_spec : Error< "access specifier can only have annotation attributes">; def err_attribute_section_invalid_for_target : Error< - "argument to 'section' attribute is not valid for this target: %0">; + "argument to %select{'code_seg'|'section'}1 attribute is not valid for this target: %0">; def warn_mismatched_section : Warning< - "section does not match previous declaration">, InGroup<Section>; + "%select{codeseg|section}0 does not match previous declaration">, InGroup<Section>; def warn_attribute_section_on_redeclaration : Warning< "section attribute is specified on redeclared variable">, InGroup<Section>; +def err_mismatched_code_seg_base : Error< + "derived class must specify the same code segment as its base classes">; +def err_mismatched_code_seg_override : Error< + "overriding virtual function must specify the same code segment as its overridden function">; +def err_conflicting_codeseg_attribute : Error< + "conflicting code segment specifiers">; +def warn_duplicate_codeseg_attribute : Warning< + "duplicate code segment specifiers">, InGroup<Section>; def err_anonymous_property: Error< "anonymous property is not supported">; @@ -2687,6 +2736,9 @@ def warn_attribute_ignored : Warning<"%0 attribute ignored">, def warn_attribute_ignored_on_inline : Warning<"%0 attribute ignored on inline function">, InGroup<IgnoredAttributes>; +def warn_nocf_check_attribute_ignored : + Warning<"'nocf_check' attribute ignored; use -fcf-protection to enable the attribute">, + InGroup<IgnoredAttributes>; def warn_attribute_after_definition_ignored : Warning< "attribute %0 after definition is ignored">, InGroup<IgnoredAttributes>; @@ -2696,7 +2748,7 @@ def warn_cxx11_gnu_attribute_on_type : Warning< "attribute %0 ignored, because it cannot be applied to a type">, InGroup<IgnoredAttributes>; def warn_unhandled_ms_attribute_ignored : Warning< - "__declspec attribute %0 is not supported">, + "__declspec attribute %0 is not supported">, InGroup<IgnoredAttributes>; def err_decl_attribute_invalid_on_stmt : Error< "%0 attribute cannot be applied to a statement">; @@ -2800,13 +2852,11 @@ def warn_alias_with_section : Warning< "%select{alias|ifunc}1 will not be in section '%0' but in the same section as the %select{aliasee|resolver}2">, InGroup<IgnoredAttributes>; def err_duplicate_mangled_name : Error< - "definition with same mangled name as another definition">; + "definition with same mangled name '%0' as another definition">; def err_cyclic_alias : Error< "%select{alias|ifunc}0 definition is part of a cycle">; def err_ifunc_resolver_return : Error< "ifunc resolver function must return a pointer">; -def err_ifunc_resolver_params : Error< - "ifunc resolver function must have no parameters">; def warn_attribute_wrong_decl_type_str : Warning< "%0 attribute only applies to %1">, InGroup<IgnoredAttributes>; def err_attribute_wrong_decl_type_str : Error< @@ -2825,8 +2875,7 @@ def warn_attribute_wrong_decl_type : Warning< "|types and namespaces" "|variables, functions and classes" "|kernel functions" - "|non-K&R-style functions" - "|variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members}1">, + "|non-K&R-style functions}1">, InGroup<IgnoredAttributes>; def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>; def warn_type_attribute_wrong_type : Warning< @@ -2881,6 +2930,9 @@ def err_base_specifier_attribute : Error< def err_invalid_attribute_on_virtual_function : Error< "%0 attribute cannot be applied to virtual functions">; +def ext_cannot_use_trivial_abi : ExtWarn< + "'trivial_abi' cannot be applied to %0">, InGroup<IgnoredAttributes>; + // Availability attribute def warn_availability_unknown_platform : Warning< "unknown platform %0 in availability macro">, InGroup<Availability>; @@ -2900,6 +2952,10 @@ def warn_mismatched_availability_override_unavail : Warning< "%select{the protocol method it implements|its overridden method}1 is " "available">, InGroup<Availability>; +def warn_availability_on_static_initializer : Warning< + "ignoring availability attribute %select{on '+load' method|" + "with constructor attribute|with destructor attribute}0">, + InGroup<Availability>; def note_overridden_method : Note< "overridden method is here">; def note_protocol_method : Note< @@ -2945,7 +3001,7 @@ def err_attribute_argument_out_of_range : Error< "1:can only be 1, since there is one parameter|" ":must be between 1 and %2}2">; -// Thread Safety Analysis +// Thread Safety Analysis def warn_unlock_but_no_lock : Warning<"releasing %0 '%1' that was not held">, InGroup<ThreadSafetyAnalysis>, DefaultIgnore; def warn_unlock_kind_mismatch : Warning< @@ -2959,7 +3015,7 @@ def warn_no_unlock : Warning< InGroup<ThreadSafetyAnalysis>, DefaultIgnore; def warn_expecting_locked : Warning< "expecting %0 '%1' to be held at the end of function">, - InGroup<ThreadSafetyAnalysis>, DefaultIgnore; + InGroup<ThreadSafetyAnalysis>, DefaultIgnore; // FIXME: improve the error message about locks not in scope def warn_lock_some_predecessors : Warning< "%0 '%1' is not held on every path through here">, @@ -2974,11 +3030,11 @@ def warn_lock_exclusive_and_shared : Warning< def note_lock_exclusive_and_shared : Note< "the other acquisition of %0 '%1' is here">; def warn_variable_requires_any_lock : Warning< - "%select{reading|writing}1 variable '%0' requires holding " + "%select{reading|writing}1 variable %0 requires holding " "%select{any mutex|any mutex exclusively}1">, InGroup<ThreadSafetyAnalysis>, DefaultIgnore; def warn_var_deref_requires_any_lock : Warning< - "%select{reading|writing}1 the value pointed to by '%0' requires holding " + "%select{reading|writing}1 the value pointed to by %0 requires holding " "%select{any mutex|any mutex exclusively}1">, InGroup<ThreadSafetyAnalysis>, DefaultIgnore; def warn_fun_excludes_mutex : Warning< @@ -3002,25 +3058,25 @@ def warn_acquire_requires_negative_cap : Warning< // Thread safety warnings on pass by reference def warn_guarded_pass_by_reference : Warning< - "passing variable '%1' by reference requires holding %0 " + "passing variable %1 by reference requires holding %0 " "%select{'%2'|'%2' exclusively}3">, InGroup<ThreadSafetyReference>, DefaultIgnore; def warn_pt_guarded_pass_by_reference : Warning< - "passing the value that '%1' points to by reference requires holding %0 " + "passing the value that %1 points to by reference requires holding %0 " "%select{'%2'|'%2' exclusively}3">, InGroup<ThreadSafetyReference>, DefaultIgnore; // Imprecise thread safety warnings def warn_variable_requires_lock : Warning< - "%select{reading|writing}3 variable '%1' requires holding %0 " + "%select{reading|writing}3 variable %1 requires holding %0 " "%select{'%2'|'%2' exclusively}3">, InGroup<ThreadSafetyAnalysis>, DefaultIgnore; def warn_var_deref_requires_lock : Warning< - "%select{reading|writing}3 the value pointed to by '%1' requires " + "%select{reading|writing}3 the value pointed to by %1 requires " "holding %0 %select{'%2'|'%2' exclusively}3">, InGroup<ThreadSafetyAnalysis>, DefaultIgnore; def warn_fun_requires_lock : Warning< - "calling function '%1' requires holding %0 %select{'%2'|'%2' exclusively}3">, + "calling function %1 requires holding %0 %select{'%2'|'%2' exclusively}3">, InGroup<ThreadSafetyAnalysis>, DefaultIgnore; // Precise thread safety warnings @@ -3036,13 +3092,13 @@ def warn_fun_requires_lock_precise : def note_found_mutex_near_match : Note<"found near match '%0'">; // Verbose thread safety warnings -def warn_thread_safety_verbose : Warning<"Thread safety verbose warning.">, +def warn_thread_safety_verbose : Warning<"Thread safety verbose warning.">, InGroup<ThreadSafetyVerbose>, DefaultIgnore; -def note_thread_warning_in_fun : Note<"Thread warning in function '%0'">; +def note_thread_warning_in_fun : Note<"Thread warning in function %0">; def note_guarded_by_declared_here : Note<"Guarded_by declared here.">; -// Dummy warning that will trigger "beta" warnings from the analysis if enabled. -def warn_thread_safety_beta : Warning<"Thread safety beta warning.">, +// Dummy warning that will trigger "beta" warnings from the analysis if enabled. +def warn_thread_safety_beta : Warning<"Thread safety beta warning.">, InGroup<ThreadSafetyBeta>, DefaultIgnore; // Consumed warnings @@ -3086,6 +3142,9 @@ def err_impcast_complex_scalar : Error< def warn_impcast_float_precision : Warning< "implicit conversion loses floating-point precision: %0 to %1">, InGroup<Conversion>, DefaultIgnore; +def warn_impcast_float_result_precision : Warning< + "implicit conversion when assigning computation result loses floating-point precision: %0 to %1">, + InGroup<Conversion>, DefaultIgnore; def warn_impcast_double_promotion : Warning< "implicit conversion increases floating-point precision: %0 to %1">, InGroup<DoublePromotion>, DefaultIgnore; @@ -3111,13 +3170,18 @@ def warn_impcast_bitfield_precision_constant : Warning< def warn_impcast_literal_float_to_integer : Warning< "implicit conversion from %0 to %1 changes value from %2 to %3">, InGroup<LiteralConversion>; +def warn_impcast_literal_float_to_integer_out_of_range : Warning< + "implicit conversion of out of range value from %0 to %1 is undefined">, + InGroup<LiteralConversion>; def warn_impcast_float_integer : Warning< "implicit conversion turns floating-point number into integer: %0 to %1">, InGroup<FloatConversion>, DefaultIgnore; def warn_impcast_float_to_integer : Warning< - "implicit conversion of out of range value from %0 to %1 changes value " - "from %2 to %3">, + "implicit conversion from %0 to %1 changes value from %2 to %3">, + InGroup<FloatOverflowConversion>, DefaultIgnore; +def warn_impcast_float_to_integer_out_of_range : Warning< + "implicit conversion of out of range value from %0 to %1 is undefined">, InGroup<FloatOverflowConversion>, DefaultIgnore; def warn_impcast_float_to_integer_zero : Warning< "implicit conversion from %0 to %1 changes non-zero value from %2 to %3">, @@ -3290,7 +3354,7 @@ def err_attribute_sentinel_not_zero_or_one : Error< "'sentinel' parameter 2 not 0 or 1">; def warn_cleanup_ext : Warning< "GCC does not allow the 'cleanup' attribute argument to be anything other " - "than a simple identifier">, + "than a simple identifier">, InGroup<GccCompat>; def err_attribute_cleanup_arg_not_function : Error< "'cleanup' argument %select{|%1 |%1 }0is not a %select{||single }0function">; @@ -3307,6 +3371,9 @@ def err_attribute_not_supported_in_lang : Error< "%0 attribute is not supported in %select{C|C++|Objective-C}1">; def err_attribute_not_supported_on_arch : Error<"%0 attribute is not supported on '%1'">; +def warn_gcc_ignores_type_attr : Warning< + "GCC does not allow the %0 attribute to be written on a type">, + InGroup<GccCompat>; // Clang-Specific Attributes def warn_attribute_iboutlet : Warning< @@ -3322,7 +3389,7 @@ def warn_iboutlet_object_type : Warning< def warn_iboutletcollection_property_assign : Warning< "IBOutletCollection properties should be copy/strong and not assign">, InGroup<ObjCInvalidIBOutletProperty>; - + def err_attribute_overloadable_mismatch : Error< "redeclaration of %0 must %select{not |}1have the 'overloadable' attribute">; def note_attribute_overloadable_prev_overload : Note< @@ -3488,27 +3555,29 @@ def err_ovl_deleted_member_call : Error< def note_ovl_too_many_candidates : Note< "remaining %0 candidate%s0 omitted; " "pass -fshow-overloads=all to show them">; -def note_ovl_candidate : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "is the implicit default constructor|" - "is the implicit copy constructor|" - "is the implicit move constructor|" - "is the implicit copy assignment operator|" - "is the implicit move assignment operator|" - "inherited constructor|" - "inherited constructor }0%2" - "%select{| has different class%diff{ (expected $ but has $)|}4,5" - "| has different number of parameters (expected %4 but has %5)" - "| has type mismatch at %ordinal4 parameter" - "%diff{ (expected $ but has $)|}5,6" - "| has different return type%diff{ ($ expected but has $)|}4,5" + +def select_ovl_candidate_kind : TextSubstitution< + "%select{function|function|constructor|" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "inherited constructor}0%select{| template| %2}1">; + +def note_ovl_candidate : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,3" + "%select{| has different class%diff{ (expected $ but has $)|}5,6" + "| has different number of parameters (expected %5 but has %6)" + "| has type mismatch at %ordinal5 parameter" + "%diff{ (expected $ but has $)|}6,7" + "| has different return type%diff{ ($ expected but has $)|}5,6" "| has different qualifiers (expected " "%select{none|const|restrict|const and restrict|volatile|const and volatile" - "|volatile and restrict|const, volatile, and restrict}4 but found " + "|volatile and restrict|const, volatile, and restrict}5 but found " "%select{none|const|restrict|const and restrict|volatile|const and volatile" - "|volatile and restrict|const, volatile, and restrict}5)" - "| has different exception specification}3">; + "|volatile and restrict|const, volatile, and restrict}6)" + "| has different exception specification}4">; def note_ovl_candidate_inherited_constructor : Note< "constructor from base class %0 inherited here">; @@ -3522,6 +3591,9 @@ def note_ovl_candidate_bad_deduction : Note< "candidate template ignored: failed template argument deduction">; def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " "couldn't infer template argument %0">; +def note_ovl_candidate_incomplete_deduction_pack : Note<"candidate template ignored: " + "deduced too few arguments for expanded pack %0; no argument for %ordinal1 " + "expanded parameter in deduced argument pack %2">; def note_ovl_candidate_inconsistent_deduction : Note< "candidate template ignored: deduced conflicting %select{types|values|" "templates}0 for parameter %1%diff{ ($ vs. $)|}2,3">; @@ -3578,233 +3650,99 @@ def note_ovl_candidate_non_deduced_mismatch_qualified : Note< // Note that we don't treat templates differently for this diagnostic. def note_ovl_candidate_arity : Note<"candidate " - "%select{function|function|constructor|function|function|constructor|" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor}0 %select{|template }1" - "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " - "%plural{1:was|:were}4 provided">; + "%sub{select_ovl_candidate_kind}0,1,2 not viable: " + "requires%select{ at least| at most|}3 %4 argument%s4, but %5 " + "%plural{1:was|:were}5 provided">; def note_ovl_candidate_arity_one : Note<"candidate " - "%select{function|function|constructor|function|function|constructor|" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor}0 %select{|template }1not viable: " - "%select{requires at least|allows at most single|requires single}2 " - "argument %3, but %plural{0:no|:%4}4 arguments were provided">; + "%sub{select_ovl_candidate_kind}0,1,2 not viable: " + "%select{requires at least|allows at most single|requires single}3 " + "argument %4, but %plural{0:no|:%5}5 arguments were provided">; def note_ovl_candidate_deleted : Note< - "candidate %select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 has been " + "candidate %sub{select_ovl_candidate_kind}0,1,2 has been " "%select{explicitly made unavailable|explicitly deleted|" - "implicitly deleted}2">; + "implicitly deleted}3">; // Giving the index of the bad argument really clutters this message, and // it's relatively unimportant because 1) it's generally obvious which // argument(s) are of the given object type and 2) the fix is usually // to complete the type, which doesn't involve changes to the call line // anyway. If people complain, we can change it. -def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 " - "not viable: cannot convert argument of incomplete type " - "%diff{$ to $|to parameter type}2,3 for " - "%select{%ordinal5 argument|object argument}4" +def note_ovl_candidate_bad_conv_incomplete : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "cannot convert argument of incomplete type " + "%diff{$ to $|to parameter type}3,4 for " + "%select{%ordinal6 argument|object argument}5" "%select{|; dereference the argument with *|" "; take the address of the argument with &|" "; remove *|" - "; remove &}6">; -def note_ovl_candidate_bad_list_argument : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 " - "not viable: cannot convert initializer list argument to %3">; -def note_ovl_candidate_bad_overload : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1" - " not viable: no overload of %3 matching %2 for %ordinal4 argument">; -def note_ovl_candidate_bad_conv : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1" - " not viable: no known conversion " - "%diff{from $ to $|from argument type to parameter type}2,3 for " - "%select{%ordinal5 argument|object argument}4" + "; remove &}7">; +def note_ovl_candidate_bad_list_argument : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "cannot convert initializer list argument to %4">; +def note_ovl_candidate_bad_overload : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "no overload of %4 matching %3 for %ordinal5 argument">; +def note_ovl_candidate_bad_conv : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "no known conversion " + "%diff{from $ to $|from argument type to parameter type}3,4 for " + "%select{%ordinal6 argument|object argument}5" "%select{|; dereference the argument with *|" "; take the address of the argument with &|" "; remove *|" - "; remove &}6">; -def note_ovl_candidate_bad_arc_conv : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1" - " not viable: cannot implicitly convert argument " - "%diff{of type $ to $|type to parameter type}2,3 for " - "%select{%ordinal5 argument|object argument}4 under ARC">; -def note_ovl_candidate_bad_lvalue : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1" - " not viable: expects an l-value for " - "%select{%ordinal3 argument|object argument}2">; -def note_ovl_candidate_bad_addrspace : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " - "%select{%ordinal6|'this'}5 argument (%2) is in " - "address space %3, but parameter must be in address space %4">; -def note_ovl_candidate_bad_gc : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " - "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 " - "ownership, but parameter has %select{no|__weak|__strong}4 ownership">; -def note_ovl_candidate_bad_ownership : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " - "%select{%ordinal6|'this'}5 argument (%2) has " - "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 ownership," + "; remove &}7">; +def note_ovl_candidate_bad_arc_conv : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "cannot implicitly convert argument " + "%diff{of type $ to $|type to parameter type}3,4 for " + "%select{%ordinal6 argument|object argument}5 under ARC">; +def note_ovl_candidate_bad_lvalue : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "expects an l-value for " + "%select{%ordinal4 argument|object argument}3">; +def note_ovl_candidate_bad_addrspace : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "address space mismatch in %select{%ordinal6|'this'}5 argument (%3), " + "parameter type must be %4">; +def note_ovl_candidate_bad_gc : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "%select{%ordinal7|'this'}6 argument (%3) has %select{no|__weak|__strong}4 " + "ownership, but parameter has %select{no|__weak|__strong}5 ownership">; +def note_ovl_candidate_bad_ownership : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "%select{%ordinal7|'this'}6 argument (%3) has " + "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}4 ownership," " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" - "__autoreleasing}4 ownership">; -def note_ovl_candidate_bad_cvr_this : Note<"candidate " - "%select{|function|||function|||||" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)||}0 not viable: " - "'this' argument has type %2, but method is not marked " + "__autoreleasing}5 ownership">; +def note_ovl_candidate_bad_cvr_this : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "'this' argument has type %3, but method is not marked " "%select{const|restrict|const or restrict|volatile|const or volatile|" - "volatile or restrict|const, volatile, or restrict}3">; -def note_ovl_candidate_bad_cvr : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " - "%ordinal4 argument (%2) would lose " + "volatile or restrict|const, volatile, or restrict}4">; +def note_ovl_candidate_bad_cvr : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "%ordinal5 argument (%3) would lose " "%select{const|restrict|const and restrict|volatile|const and volatile|" - "volatile and restrict|const, volatile, and restrict}3 qualifier" - "%select{||s||s|s|s}3">; -def note_ovl_candidate_bad_unaligned : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " - "%ordinal4 argument (%2) would lose __unaligned qualifier">; -def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate " - "%select{function|function|constructor|" - "function |function |constructor |" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor }0%1 not viable: " - "cannot %select{convert from|convert from|bind}2 " - "%select{base class pointer|superclass|base class object of type}2 %3 to " - "%select{derived class pointer|subclass|derived class reference}2 %4 for " - "%ordinal5 argument">; + "volatile and restrict|const, volatile, and restrict}4 qualifier" + "%select{||s||s|s|s}4">; +def note_ovl_candidate_bad_unaligned : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "%ordinal5 argument (%3) would lose __unaligned qualifier">; +def note_ovl_candidate_bad_base_to_derived_conv : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "cannot %select{convert from|convert from|bind}3 " + "%select{base class pointer|superclass|base class object of type}3 %4 to " + "%select{derived class pointer|subclass|derived class reference}3 %5 for " + "%ordinal6 argument">; def note_ovl_candidate_bad_target : Note< - "candidate %select{function|function|constructor|" - "function|function|constructor|" - "constructor (the implicit default constructor)|" - "constructor (the implicit copy constructor)|" - "constructor (the implicit move constructor)|" - "function (the implicit copy assignment operator)|" - "function (the implicit move assignment operator)|" - "inherited constructor|" - "inherited constructor}0 not viable: " + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " "call to " - "%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from" - " %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">; + "%select{__device__|__global__|__host__|__host__ __device__|invalid}3 function from" + " %select{__device__|__global__|__host__|__host__ __device__|invalid}4 function">; def note_implicit_member_target_infer_collision : Note< - "implicit %select{" - "default constructor|" - "copy constructor|" - "move constructor|" - "copy assignment operator|" - "move assignment operator|" - "destructor}0 inferred target collision: call to both " + "implicit %sub{select_special_member_kind}0 inferred target collision: call to both " "%select{__device__|__global__|__host__|__host__ __device__}1 and " "%select{__device__|__global__|__host__|__host__ __device__}2 members">; @@ -3846,16 +3784,14 @@ def err_ovl_deleted_oper : Error< "overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">; def err_ovl_deleted_special_oper : Error< "object of type %0 cannot be %select{constructed|copied|moved|assigned|" - "assigned|destroyed}1 because its %select{default constructor|" - "copy constructor|move constructor|copy assignment operator|" - "move assignment operator|destructor}1 is implicitly deleted">; + "assigned|destroyed}1 because its %sub{select_special_member_kind}1 is implicitly deleted">; def err_ovl_no_viable_subscript : Error<"no viable overloaded operator[] for type %0">; def err_ovl_no_oper : Error<"type %0 does not provide a %select{subscript|call}1 operator">; def err_ovl_unresolvable : Error< - "reference to overloaded function could not be resolved; " - "did you mean to call it%select{| with no arguments}0?">; + "reference to %select{overloaded|multiversioned}1 function could not be " + "resolved; did you mean to call it%select{| with no arguments}0?">; def err_bound_member_function : Error< "reference to non-static member function must be called" "%select{|; did you mean to call it with no arguments?}0">; @@ -3918,7 +3854,7 @@ def note_template_param_different_kind : Note< def err_invalid_decl_specifier_in_nontype_parm : Error< "invalid declaration specifier in template non-type parameter">; - + def err_template_nontype_parm_different_type : Error< "template non-type parameter has a different type %0 in template " "%select{|template parameter }1redeclaration">; @@ -3965,8 +3901,6 @@ def err_template_member_noparams : Error< "extraneous 'template<>' in declaration of member %0">; def err_template_tag_noparams : Error< "extraneous 'template<>' in declaration of %0 %1">; -def err_template_decl_ref : Error< - "cannot refer to %select{class|variable}0 template %1 without a template argument list">; // C++ Template Argument Lists def err_template_missing_args : Error< @@ -4134,42 +4068,20 @@ def note_explicit_specialization_declared_here : Note< "explicit specialization declared here">; def err_template_spec_decl_function_scope : Error< "explicit specialization of %0 in function scope">; -def err_template_spec_decl_class_scope : Error< - "explicit specialization of %0 in class scope">; def err_template_spec_decl_friend : Error< "cannot declare an explicit specialization in a friend">; -def err_template_spec_decl_out_of_scope_global : Error< - "%select{class template|class template partial|variable template|" - "variable template partial|function template|member function|" - "static data member|member class|member enumeration}0 " - "specialization of %1 must originally be declared in the global scope">; -def err_template_spec_decl_out_of_scope : Error< - "%select{class template|class template partial|variable template|" - "variable template partial|function template|member " - "function|static data member|member class|member enumeration}0 " - "specialization of %1 must originally be declared in namespace %2">; -def ext_template_spec_decl_out_of_scope : ExtWarn< - "first declaration of %select{class template|class template partial|" - "variable template|variable template partial|" - "function template|member function|static data member|member class|" - "member enumeration}0 specialization of %1 outside namespace %2 is a " - "C++11 extension">, InGroup<CXX11>; -def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning< - "%select{class template|class template partial|variable template|" - "variable template partial|function template|member " - "function|static data member|member class|member enumeration}0 " - "specialization of %1 outside namespace %2 is incompatible with C++98">, - InGroup<CXX98Compat>, DefaultIgnore; def err_template_spec_redecl_out_of_scope : Error< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " - "specialization of %1 not in a namespace enclosing %2">; + "specialization of %1 not in %select{a namespace enclosing %2|" + "class %2 or an enclosing namespace}3">; def ext_ms_template_spec_redecl_out_of_scope: ExtWarn< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " - "specialization of %1 outside namespace enclosing %2 " + "specialization of %1 not in %select{a namespace enclosing %2|" + "class %2 or an enclosing namespace}3 " "is a Microsoft extension">, InGroup<MicrosoftTemplate>; def err_template_spec_redecl_global_scope : Error< "%select{class template|class template partial|variable template|" @@ -4191,16 +4103,18 @@ def err_template_spec_default_arg : Error< def err_not_class_template_specialization : Error< "cannot specialize a %select{dependent template|template template " "parameter}0">; -def err_function_specialization_in_class : Error< - "cannot specialize a function %0 within class scope">; -def ext_function_specialization_in_class : ExtWarn< - "explicit specialization of %0 within class scope is a Microsoft extension">, - InGroup<MicrosoftTemplate>; def ext_explicit_specialization_storage_class : ExtWarn< "explicit specialization cannot have a storage class">; def err_explicit_specialization_inconsistent_storage_class : Error< "explicit specialization has extraneous, inconsistent storage class " "'%select{none|extern|static|__private_extern__|auto|register}0'">; +def err_dependent_function_template_spec_no_match : Error< + "no candidate function template was found for dependent" + " friend function template specialization">; +def note_dependent_function_template_spec_discard_reason : Note< + "candidate ignored: %select{not a function template" + "|not a member of the enclosing namespace;" + " did you mean to explicitly qualify the specialization?}0">; // C++ class template specializations and out-of-line definitions def err_template_spec_needs_header : Error< @@ -4242,7 +4156,7 @@ def err_dependent_typed_non_type_arg_in_partial_spec : Error< def err_partial_spec_args_match_primary_template : Error< "%select{class|variable}0 template partial specialization does not " "specialize any template argument; to %select{declare|define}1 the " - "primary template, remove the template argument list">; + "primary template, remove the template argument list">; def ext_partial_spec_not_more_specialized_than_primary : ExtWarn< "%select{class|variable}0 template partial specialization is not " "more specialized than the primary template">, DefaultError, @@ -4277,7 +4191,7 @@ def err_var_spec_no_template : Error< def err_var_spec_no_template_but_method : Error< "no variable template matches specialization; " "did you mean to use %0 as function template instead?">; - + // C++ Function template specializations def err_function_template_spec_no_match : Error< "no function template matches function template specialization %0">; @@ -4398,12 +4312,12 @@ def err_explicit_instantiation_out_of_scope : Error< def err_explicit_instantiation_must_be_global : Error< "explicit instantiation of %0 must occur at global scope">; def warn_explicit_instantiation_out_of_scope_0x : Warning< - "explicit instantiation of %0 not in a namespace enclosing %1">, + "explicit instantiation of %0 not in a namespace enclosing %1">, InGroup<CXX11Compat>, DefaultIgnore; def warn_explicit_instantiation_must_be_global_0x : Warning< - "explicit instantiation of %0 must occur at global scope">, + "explicit instantiation of %0 must occur at global scope">, InGroup<CXX11Compat>, DefaultIgnore; - + def err_explicit_instantiation_requires_name : Error< "explicit instantiation declaration requires a name">; def err_explicit_instantiation_of_typedef : Error< @@ -4464,7 +4378,7 @@ def err_mismatched_exception_spec_explicit_instantiation : Error< def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn< err_mismatched_exception_spec_explicit_instantiation.Text>, InGroup<MicrosoftExceptionSpec>; - + // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; def err_typename_nested_not_found_enable_if : Error< @@ -4497,6 +4411,8 @@ def note_using_value_decl_missing_typename : Note< def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; +def note_template_kw_refers_to_non_template : Note< + "declared as a non-template here">; def err_template_kw_refers_to_class_template : Error< "'%0%1' instantiated to a class template, not a function template">; def note_referenced_class_template : Note< @@ -4540,7 +4456,7 @@ def note_template_parameter_pack_non_pack : Note< def note_template_parameter_pack_here : Note< "previous %select{template type|non-type template|template template}0 " "parameter%select{| pack}1 declared here">; - + def err_unexpanded_parameter_pack : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" @@ -4558,6 +4474,9 @@ def err_pack_expansion_length_conflict : Error< def err_pack_expansion_length_conflict_multilevel : Error< "pack expansion contains parameter pack %0 that has a different " "length (%1 vs. %2) from outer parameter packs">; +def err_pack_expansion_length_conflict_partial : Error< + "pack expansion contains parameter pack %0 that has a different " + "length (at least %1 vs. %2) from outer parameter packs">; def err_pack_expansion_member_init : Error< "pack expansion for initialization of member %0">; @@ -4641,7 +4560,7 @@ def warn_missing_prototype : Warning< "no previous prototype for function %0">, InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore; def note_declaration_not_a_prototype : Note< - "this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">; + "this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">; def warn_strict_prototypes : Warning< "this %select{function declaration is not|block declaration is not|" "old-style function definition is not preceded by}0 a prototype">, @@ -4849,7 +4768,7 @@ def ext_ms_forward_ref_enum : ExtWarn< def ext_forward_ref_enum_def : Extension< "redeclaration of already-defined enum %0 is a GNU extension">, InGroup<GNURedeclaredEnum>; - + def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">; def err_duplicate_member : Error<"duplicate member %0">; def err_misplaced_ivar : Error< @@ -4868,7 +4787,7 @@ def ext_enumerator_increment_too_large : ExtWarn< def warn_flag_enum_constant_out_of_range : Warning< "enumeration value %0 is out of range of flags in enumeration type %1">, InGroup<FlagEnum>; - + def warn_illegal_constant_array_size : Extension< "size of static array must be an integer constant expression">; def err_vm_decl_in_file_scope : Error< @@ -4973,7 +4892,7 @@ def err_illegal_initializer : Error< "illegal initializer (only variables can be initialized)">; def err_illegal_initializer_type : Error<"illegal initializer type %0">; def ext_init_list_type_narrowing : ExtWarn< - "type %0 cannot be narrowed to %1 in initializer list">, + "type %0 cannot be narrowed to %1 in initializer list">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; def ext_init_list_variable_narrowing : ExtWarn< "non-constant-expression cannot be narrowed from type %0 to %1 in " @@ -5116,12 +5035,17 @@ def note_protected_by_objc_strong_init : Note< "jump bypasses initialization of __strong variable">; def note_protected_by_objc_weak_init : Note< "jump bypasses initialization of __weak variable">; +def note_protected_by_non_trivial_c_struct_init : Note< + "jump bypasses initialization of variable of non-trivial C struct type">; def note_enters_block_captures_cxx_obj : Note< "jump enters lifetime of block which captures a destructible C++ object">; def note_enters_block_captures_strong : Note< "jump enters lifetime of block which strongly captures a variable">; def note_enters_block_captures_weak : Note< "jump enters lifetime of block which weakly captures a variable">; +def note_enters_block_captures_non_trivial_c_struct : Note< + "jump enters lifetime of block which captures a C struct that is non-trivial " + "to destroy">; def note_exits_cleanup : Note< "jump exits scope of variable with __attribute__((cleanup))">; @@ -5162,6 +5086,9 @@ def note_exits_block_captures_strong : Note< "jump exits lifetime of block which strongly captures a variable">; def note_exits_block_captures_weak : Note< "jump exits lifetime of block which weakly captures a variable">; +def note_exits_block_captures_non_trivial_c_struct : Note< + "jump exits lifetime of block which captures a C struct that is non-trivial " + "to destroy">; def err_func_returning_qualified_void : ExtWarn< "function cannot return qualified void type %0">, @@ -5303,9 +5230,9 @@ def err_arc_illegal_method_def : Error< def warn_arc_strong_pointer_objc_pointer : Warning< "method parameter of type %0 with no explicit ownership">, InGroup<DiagGroup<"explicit-ownership-type">>, DefaultIgnore; - + } // end "ARC Restrictions" category - + def err_arc_lost_method_convention : Error< "method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 " "method, but its implementation doesn't match because %select{" @@ -5374,7 +5301,7 @@ def warn_receiver_forward_instance : Warning< InGroup<ForwardClassReceiver>, DefaultIgnore; def err_arc_collection_forward : Error< "collection expression type %0 is a forward declaration">; -def err_arc_multiple_method_decl : Error< +def err_arc_multiple_method_decl : Error< "multiple methods named %0 found with mismatched result, " "parameter type or attributes">; def warn_arc_lifetime_result_type : Warning< @@ -5415,8 +5342,6 @@ def warn_block_capture_autoreleasing : Warning< "block captures an autoreleasing out-parameter, which may result in " "use-after-free bugs">, InGroup<BlockCaptureAutoReleasing>; -def note_declare_parameter_autoreleasing : Note< - "declare the parameter __autoreleasing explicitly to suppress this warning">; def note_declare_parameter_strong : Note< "declare the parameter __strong or capture a __block __strong variable to " "keep values alive across autorelease pools">; @@ -5605,9 +5530,12 @@ def warn_addition_in_bitshift : Warning< "operator '%0' has lower precedence than '%1'; " "'%1' will be evaluated first">, InGroup<ShiftOpParentheses>; -def warn_self_assignment : Warning< +def warn_self_assignment_builtin : Warning< "explicitly assigning value of variable of type %0 to itself">, InGroup<SelfAssignment>, DefaultIgnore; +def warn_self_assignment_overloaded : Warning< + "explicitly assigning value of variable of type %0 to itself">, + InGroup<SelfAssignmentOverloaded>, DefaultIgnore; def warn_self_move : Warning< "explicitly moving variable of type %0 to itself">, InGroup<SelfMove>, DefaultIgnore; @@ -5623,6 +5551,19 @@ def warn_pessimizing_move_on_initialization : Warning< InGroup<PessimizingMove>, DefaultIgnore; def note_remove_move : Note<"remove std::move call here">; +def warn_return_std_move : Warning< + "local variable %0 will be copied despite being %select{returned|thrown}1 by name">, + InGroup<ReturnStdMove>, DefaultIgnore; +def note_add_std_move : Note< + "call 'std::move' explicitly to avoid copying">; +def warn_return_std_move_in_cxx11 : Warning< + "prior to the resolution of a defect report against ISO C++11, " + "local variable %0 would have been copied despite being returned by name, " + "due to its not matching the function return type%diff{ ($ vs $)|}1,2">, + InGroup<ReturnStdMoveInCXX11>, DefaultIgnore; +def note_add_std_move_in_cxx11 : Note< + "call 'std::move' explicitly to avoid copying on older compilers">; + def warn_string_plus_int : Warning< "adding %0 to a string does not append to the string">, InGroup<StringPlusInt>; @@ -5753,7 +5694,7 @@ def warn_namespace_member_extra_qualification : Warning< "extra qualification on member %0">, InGroup<DiagGroup<"extra-qualification">>; def err_member_qualification : Error< - "non-friend class member %0 cannot have a qualified name">; + "non-friend class member %0 cannot have a qualified name">; def note_member_def_close_match : Note<"member declaration nearly matches">; def note_member_def_close_const_match : Note< "member declaration does not match because " @@ -5801,6 +5742,13 @@ def err_array_init_wide_string_into_char : Error< "initializing char array with wide string literal">; def err_array_init_incompat_wide_string_into_wchar : Error< "initializing wide char array with incompatible wide string literal">; +def err_array_init_plain_string_into_char8_t : Error< + "initializing 'char8_t' array with plain string literal">; +def note_array_init_plain_string_into_char8_t : Note< + "add 'u8' prefix to form a 'char8_t' string literal">; +def err_array_init_utf8_string_into_char : Error< + "initialization of char array with UTF-8 string literal is not permitted " + "by '-fchar8_t'">; def err_array_init_different_type : Error< "cannot initialize array %diff{of type $ with array of type $|" "with different type of array}0,1">; @@ -5852,7 +5800,7 @@ def err_typecheck_invalid_lvalue_addrof_addrof_function : Error< def err_typecheck_invalid_lvalue_addrof : Error< "cannot take the address of an rvalue of type %0">; def ext_typecheck_addrof_temporary : ExtWarn< - "taking the address of a temporary object of type %0">, + "taking the address of a temporary object of type %0">, InGroup<AddressOfTemporary>, DefaultError; def err_typecheck_addrof_temporary : Error< "taking the address of a temporary object of type %0">; @@ -5885,6 +5833,8 @@ def err_objc_object_assignment : Error< "cannot assign to class object (%0 invalid)">; def err_typecheck_invalid_operands : Error< "invalid operands to binary expression (%0 and %1)">; +def note_typecheck_invalid_operands_converted : Note< + "%select{first|second}0 operand was implicitly converted to type %1">; def err_typecheck_logical_vector_expr_gnu_cpp_restrict : Error< "logical expression with vector %select{type %1 and non-vector type %2|types" " %1 and %2}0 is only supported in C++">; @@ -5898,7 +5848,8 @@ def ext_typecheck_ordered_comparison_of_pointer_and_zero : Extension< def err_typecheck_ordered_comparison_of_pointer_and_zero : Error< "ordered comparison between pointer and zero (%0 and %1)">; def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn< - "ordered comparison of function pointers (%0 and %1)">; + "ordered comparison of function pointers (%0 and %1)">, + InGroup<DiagGroup<"ordered-compare-function-pointers">>; def ext_typecheck_comparison_of_fptr_to_void : Extension< "equality comparison between function pointer and void pointer (%0 and %1)">; def err_typecheck_comparison_of_fptr_to_void : Error< @@ -5960,7 +5911,7 @@ def warn_mixed_sign_comparison : Warning< "comparison of integers of different signs: %0 and %1">, InGroup<SignCompare>, DefaultIgnore; def warn_out_of_range_compare : Warning< - "result of comparison of %select{constant %0|true|false}1 with " + "result of comparison of %select{constant %0|true|false}1 with " "%select{expression of type %2|boolean expression}3 is always %4">, InGroup<TautologicalOutOfRangeCompare>; def warn_tautological_bool_compare : Warning<warn_out_of_range_compare.Text>, @@ -6118,7 +6069,7 @@ def err_no_subobject_property_setting : Error< "expression is not assignable">; def err_qualified_objc_access : Error< "%select{property|instance variable}0 access cannot be qualified with '%1'">; - + def ext_freestanding_complex : Extension< "complex numbers are an extension in a freestanding C99 implementation">; @@ -6190,9 +6141,9 @@ def err_objc_object_catch : Error< def err_incomplete_type_objc_at_encode : Error< "'@encode' of incomplete type %0">; def warn_objc_circular_container : Warning< - "adding '%0' to '%1' might cause circular dependency in container">, + "adding %0 to %1 might cause circular dependency in container">, InGroup<DiagGroup<"objc-circular-container">>; -def note_objc_circular_container_declared_here : Note<"'%0' declared here">; +def note_objc_circular_container_declared_here : Note<"%0 declared here">; def warn_objc_unsafe_perform_selector : Warning< "%0 is incompatible with selectors that return a " "%select{struct|union|vector}1 type">, @@ -6264,6 +6215,12 @@ def err_bad_cxx_cast_bitfield : Error< def err_bad_cxx_cast_qualifiers_away : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from %1 to %2 casts away qualifiers">; +def ext_bad_cxx_cast_qualifiers_away_incoherent : ExtWarn< + "ISO C++ does not allow " + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 because it casts away qualifiers, " + "even though the source and destination types are unrelated">, + SFINAEFailure, InGroup<DiagGroup<"cast-qual-unrelated">>; def err_bad_const_cast_dest : Error< "%select{const_cast||||C-style cast|functional-style cast}0 to %2, " "which is not a reference, pointer-to-object, or pointer-to-data-member">; @@ -6278,13 +6235,13 @@ def warn_cxx98_compat_cast_fn_obj : Warning< def err_bad_reinterpret_cast_small_int : Error< "cast from pointer to smaller type %2 loses information">; def err_bad_cxx_cast_vector_to_scalar_different_size : Error< - "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " + "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " "to scalar %2 of different size">; def err_bad_cxx_cast_scalar_to_vector_different_size : Error< - "%select{||reinterpret_cast||C-style cast|}0 from scalar %1 " + "%select{||reinterpret_cast||C-style cast|}0 from scalar %1 " "to vector %2 of different size">; def err_bad_cxx_cast_vector_to_vector_different_size : Error< - "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " + "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " "to vector %2 of different size">; def err_bad_lvalue_to_rvalue_cast : Error< "cannot cast from lvalue of type %1 to rvalue reference type %2; types are " @@ -6444,6 +6401,8 @@ def err_bad_memptr_rhs : Error< def err_bad_memptr_lhs : Error< "left hand operand to %0 must be a %select{|pointer to }1class " "compatible with the right hand operand, but is %2">; +def err_memptr_incomplete : Error< + "member pointer has incomplete base type %0">; def warn_exception_caught_by_earlier_handler : Warning< "exception of type %0 will be caught by earlier handler">, InGroup<Exceptions>; @@ -6504,12 +6463,12 @@ def warn_overaligned_type : Warning< "type %0 requires %1 bytes of alignment and the default allocator only " "guarantees %2 bytes">, InGroup<OveralignedType>, DefaultIgnore; -def warn_aligned_allocation_unavailable :Warning< +def err_aligned_allocation_unavailable : Error< "aligned %select{allocation|deallocation}0 function of type '%1' is only " - "available on %2 %3 or newer">, InGroup<AlignedAllocationUnavailable>, DefaultError; + "available on %2 %3 or newer">; def note_silence_unligned_allocation_unavailable : Note< "if you supply your own aligned allocation functions, use " - "-Wno-aligned-allocation-unavailable to silence this diagnostic">; + "-faligned-allocation to silence this diagnostic">; def err_conditional_void_nonvoid : Error< "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " @@ -6565,6 +6524,8 @@ let CategoryName = "Lambda Issue" in { "lambda expression in an unevaluated operand">; def err_lambda_in_constant_expression : Error< "a lambda expression may not appear inside of a constant expression">; + def err_lambda_in_invalid_context : Error< + "a lambda expression cannot appear in this context">; def err_lambda_return_init_list : Error< "cannot deduce lambda return type from initializer list">; def err_lambda_capture_default_arg : Error< @@ -6623,6 +6584,11 @@ let CategoryName = "Lambda Issue" in { def ext_equals_this_lambda_capture_cxx2a : ExtWarn< "explicit capture of 'this' with a capture default of '=' " "is a C++2a extension">, InGroup<CXX2a>; + def warn_deprecated_this_capture : Warning< + "implicit capture of 'this' with a capture default of '=' is deprecated">, + InGroup<DeprecatedThisCapture>, DefaultIgnore; + def note_deprecated_this_capture : Note< + "add an explicit capture of 'this' to capture '*this' by reference">; } def err_return_in_captured_stmt : Error< @@ -6677,7 +6643,7 @@ def err_typecheck_nonviable_condition_incomplete : Error< def err_typecheck_deleted_function : Error< "conversion function %diff{from $ to $|between types}0,1 " "invokes a deleted function">; - + def err_expected_class_or_namespace : Error<"%0 is not a class" "%select{ or namespace|, namespace, or enumeration}1">; def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here " @@ -6692,9 +6658,9 @@ def err_not_tag_in_scope : Error< "no %select{struct|interface|union|class|enum}0 named %1 in %2">; def err_no_typeid_with_fno_rtti : Error< - "cannot use typeid with -fno-rtti">; + "use of typeid requires -frtti">; def err_no_dynamic_cast_with_fno_rtti : Error< - "cannot use dynamic_cast with -fno-rtti">; + "use of dynamic_cast requires -frtti">; def err_cannot_form_pointer_to_member_of_reference_type : Error< "cannot form a pointer-to-member to member %0 of reference type %1">; @@ -7045,11 +7011,11 @@ def err_typecheck_call_too_many_args_at_most_suggest : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at most %1, have %2; did you mean %3?">; - + def err_arc_typecheck_convert_incompatible_pointer : Error< "incompatible pointer types passing retainable parameter of type %0" "to a CF function expecting %1 type">; - + def err_builtin_fn_use : Error<"builtin functions must be directly called">; def warn_call_wrong_number_of_arguments : Warning< @@ -7059,6 +7025,8 @@ def err_atomic_builtin_must_be_pointer : Error< def err_atomic_builtin_must_be_pointer_intptr : Error< "address argument to atomic builtin must be a pointer to integer or pointer" " (%0 invalid)">; +def err_atomic_builtin_cannot_be_const : Error< + "address argument to atomic builtin cannot be const-qualified (%0 invalid)">; def err_atomic_builtin_must_be_pointer_intfltptr : Error< "address argument to atomic builtin must be a pointer to integer," " floating-point or pointer (%0 invalid)">; @@ -7083,6 +7051,8 @@ def err_atomic_op_needs_trivial_copy : Error< def err_atomic_op_needs_atomic_int_or_ptr : Error< "address argument to atomic operation must be a pointer to %select{|atomic }0" "integer or pointer (%1 invalid)">; +def err_atomic_op_needs_int32_or_ptr : Error< + "address argument to atomic operation must be a pointer to signed or unsigned 32-bit integer">; def err_atomic_op_bitwise_needs_atomic_int : Error< "address argument to bitwise atomic operation must be a pointer to " "%select{|atomic }0integer (%1 invalid)">; @@ -7091,6 +7061,9 @@ def warn_atomic_op_has_invalid_memory_order : Warning< InGroup<DiagGroup<"atomic-memory-ordering">>; def err_atomic_op_has_invalid_synch_scope : Error< "synchronization scope argument to atomic operation is invalid">; +def warn_atomic_op_misaligned : Warning< + "misaligned or large atomic operation may incur significant performance penalty">, + InGroup<DiagGroup<"atomic-alignment">>; def err_overflow_builtin_must_be_int : Error< "operand argument to overflow builtin must be an integer (%0 invalid)">; @@ -7141,7 +7114,7 @@ def err_va_arg_in_device : Error< "CUDA device code does not support va_arg">; def err_alias_not_supported_on_nvptx : Error<"CUDA does not support aliases">; def err_cuda_unattributed_constexpr_cannot_overload_device : Error< - "constexpr function '%0' without __host__ or __device__ attributes cannot " + "constexpr function %0 without __host__ or __device__ attributes cannot " "overload __device__ function with same signature. Add a __host__ " "attribute, or build with -fno-cuda-host-device-constexpr.">; def note_cuda_conflicting_device_function_declared_here : Note< @@ -7156,7 +7129,8 @@ def err_shared_var_init : Error< "initialization is not supported for __shared__ variables.">; def err_device_static_local_var : Error< "within a %select{__device__|__global__|__host__|__host__ __device__}0 " - "function, only __shared__ variables may be marked 'static'">; + "function, only __shared__ variables or const variables without device " + "memory qualifier may be marked 'static'">; def err_cuda_vla : Error< "cannot use variable-length arrays in " "%select{__device__|__global__|__host__|__host__ __device__}0 functions">; @@ -7180,6 +7154,10 @@ def err_cannot_pass_objc_interface_to_vararg_format : Error< "cannot pass object with interface type %1 by value to variadic " "%select{function|block|method|constructor}2; expected type from format " "string was %3">; +def err_cannot_pass_non_trivial_c_struct_to_vararg : Error< + "cannot pass non-trivial C object of type %0 by value to variadic " + "%select{function|block|method|constructor}1">; + def err_cannot_pass_objc_interface_to_vararg : Error< "cannot pass object with interface type %0 by value through variadic " @@ -7528,8 +7506,8 @@ def err_reference_to_local_in_enclosing_context : Error< "%select{%3|block literal|lambda expression|context}2">; def err_static_data_member_not_allowed_in_local_class : Error< - "static data member %0 not allowed in local class %1">; - + "static data member %0 not allowed in local class %1">; + // C++ derived classes def err_base_clause_on_union : Error<"unions cannot have base classes">; def err_base_must_be_class : Error<"base specifier must name a class">; @@ -7627,6 +7605,11 @@ def err_destroying_operator_delete_not_usual : Error< "alignment parameter">; def note_implicit_delete_this_in_destructor_here : Note< "while checking implicit 'delete this' for virtual destructor">; +def err_builtin_operator_new_delete_not_usual : Error< + "call to '%select{__builtin_operator_new|__builtin_operator_delete}0' " + "selects non-usual %select{allocation|deallocation}0 function">; +def note_non_usual_function_declared_here : Note< + "non-usual %0 declared here">; // C++ literal operators def err_literal_operator_outside_namespace : Error< @@ -7709,9 +7692,8 @@ def err_defaulted_special_member_quals : Error< "an explicitly-defaulted %select{copy|move}0 assignment operator may not " "have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">; def err_defaulted_special_member_volatile_param : Error< - "the parameter for an explicitly-defaulted %select{<<ERROR>>|" - "copy constructor|move constructor|copy assignment operator|" - "move assignment operator|<<ERROR>>}0 may not be volatile">; + "the parameter for an explicitly-defaulted %sub{select_special_member_kind}0 " + "may not be volatile">; def err_defaulted_special_member_move_const_param : Error< "the parameter for an explicitly-defaulted move " "%select{constructor|assignment operator}0 may not be const">; @@ -7723,17 +7705,13 @@ def err_defaulted_copy_assign_not_ref : Error< "the parameter for an explicitly-defaulted copy assignment operator must be an " "lvalue reference type">; def err_incorrect_defaulted_exception_spec : Error< - "exception specification of explicitly defaulted %select{default constructor|" - "copy constructor|move constructor|copy assignment operator|move assignment " - "operator|destructor}0 does not match the " - "calculated one">; + "exception specification of explicitly defaulted " + "%sub{select_special_member_kind}0 does not match the calculated one">; def err_incorrect_defaulted_constexpr : Error< - "defaulted definition of %select{default constructor|copy constructor|" - "move constructor|copy assignment operator|move assignment operator}0 " + "defaulted definition of %sub{select_special_member_kind}0 " "is not constexpr">; def err_out_of_line_default_deletes : Error< - "defaulting this %select{default constructor|copy constructor|move " - "constructor|copy assignment operator|move assignment operator|destructor}0 " + "defaulting this %sub{select_special_member_kind}0 " "would delete it after its first declaration">; def warn_vbase_moved_multiple_times : Warning< "defaulted move assignment operator of %0 will move assign virtual base " @@ -7788,6 +7766,10 @@ def warn_format_argument_needs_cast : Warning< "%select{values of type|enum values with underlying type}2 '%0' should not " "be used as format arguments; add an explicit cast to %1 instead">, InGroup<Format>; +def warn_format_argument_needs_cast_pedantic : Warning< + "%select{values of type|enum values with underlying type}2 '%0' should not " + "be used as format arguments; add an explicit cast to %1 instead">, + InGroup<FormatPedantic>, DefaultIgnore; def warn_printf_positional_arg_exceeds_data_args : Warning < "data argument position '%0' exceeds the number of data arguments (%1)">, InGroup<Format>; @@ -7870,10 +7852,17 @@ def warn_null_ret : Warning< "null returned from %select{function|method}0 that requires a non-null return value">, InGroup<NonNull>; +def err_lifetimebound_no_object_param : Error< + "'lifetimebound' attribute cannot be applied; %select{static |non-}0member " + "function has no implicit object parameter">; +def err_lifetimebound_ctor_dtor : Error< + "'lifetimebound' attribute cannot be applied to a " + "%select{constructor|destructor}0">; + // CHECK: returning address/reference of stack memory def warn_ret_stack_addr_ref : Warning< - "%select{address of|reference to}0 stack memory associated with local " - "variable %1 returned">, + "%select{address of|reference to}0 stack memory associated with " + "%select{local variable|parameter}2 %1 returned">, InGroup<ReturnStackAddress>; def warn_ret_local_temp_addr_ref : Warning< "returning %select{address of|reference to}0 local temporary object">, @@ -7883,30 +7872,71 @@ def warn_ret_addr_label : Warning< InGroup<ReturnStackAddress>; def err_ret_local_block : Error< "returning block that lives on the local stack">; -def note_ref_var_local_bind : Note< - "binding reference variable %0 here">; +def note_local_var_initializer : Note< + "%select{via initialization of|binding reference}0 variable " + "%select{%2 |}1here">; +def note_init_with_default_member_initalizer : Note< + "initializing field %0 with default member initializer">; // Check for initializing a member variable with the address or a reference to // a constructor parameter. def warn_bind_ref_member_to_parameter : Warning< - "binding reference member %0 to stack allocated parameter %1">, - InGroup<DanglingField>; + "binding reference member %0 to stack allocated " + "%select{variable|parameter}2 %1">, InGroup<DanglingField>; def warn_init_ptr_member_to_parameter_addr : Warning< - "initializing pointer member %0 with the stack address of parameter %1">, - InGroup<DanglingField>; -def warn_bind_ref_member_to_temporary : Warning< - "binding reference %select{|subobject of }1member %0 to a temporary value">, - InGroup<DanglingField>; + "initializing pointer member %0 with the stack address of " + "%select{variable|parameter}2 %1">, InGroup<DanglingField>; def note_ref_or_ptr_member_declared_here : Note< "%select{reference|pointer}0 member declared here">; -def note_ref_subobject_of_member_declared_here : Note< - "member with reference subobject declared here">; + +def err_dangling_member : Error< + "%select{reference|backing array for 'std::initializer_list'}2 " + "%select{|subobject of }1member %0 " + "%select{binds to|is}2 a temporary object " + "whose lifetime would be shorter than the lifetime of " + "the constructed object">; +def warn_dangling_member : Warning< + "%select{reference|backing array for 'std::initializer_list'}2 " + "%select{|subobject of }1member %0 " + "%select{binds to|is}2 a temporary object " + "whose lifetime is shorter than the lifetime of the constructed object">, + InGroup<DanglingField>; +def note_lifetime_extending_member_declared_here : Note< + "%select{%select{reference|'std::initializer_list'}0 member|" + "member with %select{reference|'std::initializer_list'}0 subobject}1 " + "declared here">; +def warn_dangling_variable : Warning< + "%select{temporary %select{whose address is used as value of|" + "%select{|implicitly }2bound to}4 " + "%select{%select{|reference }4member of local variable|" + "local %select{variable|reference}4}1|" + "array backing " + "%select{initializer list subobject of local variable|" + "local initializer list}1}0 " + "%select{%3 |}2will be destroyed at the end of the full-expression">, + InGroup<Dangling>; +def warn_new_dangling_reference : Warning< + "temporary bound to reference member of allocated object " + "will be destroyed at the end of the full-expression">, + InGroup<DanglingField>; +def warn_new_dangling_initializer_list : Warning< + "array backing " + "%select{initializer list subobject of the allocated object|" + "the allocated initializer list}0 " + "will be destroyed at the end of the full-expression">, + InGroup<DanglingInitializerList>; +def warn_unsupported_lifetime_extension : Warning< + "sorry, lifetime extension of " + "%select{temporary|backing array of initializer list}0 created " + "by aggregate initialization using default member initializer " + "is not supported; lifetime of %select{temporary|backing array}0 " + "will end at the end of the full-expression">, InGroup<Dangling>; // For non-floating point, expressions of the form x == x or x != x // should result in a warning, since these always evaluate to a constant. // Array comparisons have similar warnings def warn_comparison_always : Warning< - "%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">, + "%select{self-|array }0comparison always evaluates to %select{a constant|%2}1">, InGroup<TautologicalCompare>; def warn_comparison_bitwise_always : Warning< "bitwise comparison always evaluates to %select{false|true}0">, @@ -7962,7 +7992,7 @@ def err_generic_sel_multi_match : Error< // Blocks def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks" - " or %select{pick a deployment target that supports them|for OpenCL 2.0 or above}0">; + " or %select{pick a deployment target that supports them|for OpenCL 2.0}0">; def err_block_returning_array_function : Error< "block cannot return %select{array|function}0 type %1">; @@ -8199,9 +8229,12 @@ def err_vector_incorrect_num_initializers : Error< def err_altivec_empty_initializer : Error<"expected initializer">; def err_invalid_neon_type_code : Error< - "incompatible constant for this __builtin_neon function">; + "incompatible constant for this __builtin_neon function">; def err_argument_invalid_range : Error< - "argument should be a value from %0 to %1">; + "argument value %0 is outside the valid range [%1, %2]">; +def warn_argument_invalid_range : Warning< + "argument value %0 is outside the valid range [%1, %2]">, DefaultError, + InGroup<DiagGroup<"argument-outside-range">>; def err_argument_not_multiple : Error< "argument should be a multiple of %0">; def warn_neon_vector_initializer_non_portable : Warning< @@ -8218,6 +8251,8 @@ def err_systemz_invalid_tabort_code : Error< "invalid transaction abort code">; def err_64_bit_builtin_32_bit_tgt : Error< "this builtin is only available on 64-bit targets">; +def err_32_bit_builtin_64_bit_tgt : Error< + "this builtin is only available on 32-bit targets">; def err_builtin_x64_aarch64_only : Error< "this builtin is only available on x86-64 and aarch64 targets">; def err_ppc_builtin_only_on_pwr7 : Error< @@ -8226,7 +8261,15 @@ def err_x86_builtin_invalid_rounding : Error< "invalid rounding argument">; def err_x86_builtin_invalid_scale : Error< "scale argument must be 1, 2, 4, or 8">; - +def err_hexagon_builtin_unsupported_cpu : Error< + "builtin is not supported on this CPU">; +def err_hexagon_builtin_requires_hvx : Error< + "builtin requires HVX">; +def err_hexagon_builtin_unsupported_hvx : Error< + "builtin is not supported on this version of HVX">; + +def err_builtin_target_unsupported : Error< + "builtin is not supported on this target">; def err_builtin_longjmp_unsupported : Error< "__builtin_longjmp is not supported for the current target">; def err_builtin_setjmp_unsupported : Error< @@ -8242,7 +8285,7 @@ def err_constant_integer_arg_type : Error< def ext_mixed_decls_code : Extension< "ISO C90 forbids mixing declarations and code">, InGroup<DiagGroup<"declaration-after-statement">>; - + def err_non_local_variable_decl_in_for : Error< "declaration of non-local variable in 'for' loop">; def err_non_variable_decl_in_for : Error< @@ -8300,13 +8343,17 @@ def err_c99_array_usage_cxx : Error< "feature, not permitted in C++">; def err_type_unsupported : Error< "%0 is not supported on this target">; -def warn_nsconsumed_attribute_mismatch : Warning< +def err_nsconsumed_attribute_mismatch : Error< "overriding method has mismatched ns_consumed attribute on its" - " parameter">, InGroup<NSConsumedMismatch>; -def warn_nsreturns_retained_attribute_mismatch : Warning< + " parameter">; +def err_nsreturns_retained_attribute_mismatch : Error< "overriding method has mismatched ns_returns_%select{not_retained|retained}0" - " attributes">, InGroup<NSReturnsMismatch>; - + " attributes">; +def warn_nsconsumed_attribute_mismatch : Warning< + err_nsconsumed_attribute_mismatch.Text>, InGroup<NSConsumedMismatch>; +def warn_nsreturns_retained_attribute_mismatch : Warning< + err_nsreturns_retained_attribute_mismatch.Text>, InGroup<NSReturnsMismatch>; + def note_getter_unavailable : Note< "or because setter is declared here, but no getter method %0 is found">; def err_invalid_protocol_qualifiers : Error< @@ -8501,7 +8548,7 @@ def err_reference_pipe_type : Error < "pipes packet types cannot be of reference type">; def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">; def err_opencl_kernel_attr : - Error<"attribute %0 can only be applied to a kernel function">; + Error<"attribute %0 can only be applied to an OpenCL kernel function">; def err_opencl_return_value_with_address_space : Error< "return value cannot be qualified with address space">; def err_opencl_constant_no_init : Error< @@ -8549,7 +8596,8 @@ def note_opencl_typedef_access_qualifier : Note< // OpenCL Section 6.8.g def err_opencl_unknown_type_specifier : Error< - "OpenCL version %0 does not support the '%1' %select{type qualifier|storage class specifier}2">; + "OpenCL %select{C|C++}0 version %1 does not support the '%2' " + "%select{type qualifier|storage class specifier}3">; // OpenCL v2.0 s6.12.5 Blocks restrictions def err_opencl_block_storage_type : Error< @@ -8561,7 +8609,7 @@ def err_opencl_extern_block_declaration : Error< def err_opencl_block_ref_block : Error< "cannot refer to a block inside block">; -// OpenCL v2.0 s6.13.9 - Address space qualifier functions. +// OpenCL v2.0 s6.13.9 - Address space qualifier functions. def err_opencl_builtin_to_addr_arg_num : Error< "invalid number of arguments to function: %0">; def err_opencl_builtin_to_addr_invalid_arg : Error< @@ -8639,8 +8687,8 @@ def err_omp_pointer_mapped_along_with_derived_section : Error< "pointer cannot be mapped along with a section derived from itself">; def err_omp_original_storage_is_shared_and_does_not_contain : Error< "original storage of expression in data environment is shared but data environment do not fully contain mapped expression storage">; -def err_omp_same_pointer_derreferenced : Error< - "same pointer derreferenced in multiple different ways in map clause expressions">; +def err_omp_same_pointer_dereferenced : Error< + "same pointer dereferenced in multiple different ways in map clause expressions">; def note_omp_task_predetermined_firstprivate_here : Note< "predetermined as a firstprivate in a task construct here">; def err_omp_threadprivate_incomplete_type : Error< @@ -8976,6 +9024,9 @@ def err_omp_reduction_vla_unsupported : Error< "cannot generate code for reduction on %select{|array section, which requires a }0variable length array">; def err_omp_linear_distribute_var_non_loop_iteration : Error< "only loop iteration variables are allowed in 'linear' clause in distribute directives">; +def warn_omp_non_trivial_type_mapped : Warning< + "Non-trivial type %0 is mapped, only trivial types are guaranteed to be mapped correctly">, + InGroup<OpenMPTarget>; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { @@ -9076,9 +9127,9 @@ def note_equivalent_internal_linkage_decl : Note< "declared here%select{ in module '%1'|}0">; def note_redefinition_modules_same_file : Note< - "'%0' included multiple times, additional include site in header from module '%1'">; + "'%0' included multiple times, additional include site in header from module '%1'">; def note_redefinition_include_same_file : Note< - "'%0' included multiple times, additional include site here">; + "'%0' included multiple times, additional include site here">; } let CategoryName = "Coroutines Issue" in { @@ -9119,7 +9170,7 @@ def err_coroutine_promise_type_incomplete : Error< "this function cannot be a coroutine: %0 is an incomplete type">; def err_coroutine_type_missing_specialization : Error< "this function cannot be a coroutine: missing definition of " - "specialization %q0">; + "specialization %0">; def err_coroutine_promise_incompatible_return_functions : Error< "the coroutine promise type %0 declares both 'return_value' and 'return_void'">; def err_coroutine_promise_requires_return_function : Error< @@ -9324,8 +9375,67 @@ def ext_warn_gnu_final : ExtWarn< InGroup<GccCompat>; def warn_shadow_field : - Warning<"non-static data member '%0' of '%1' shadows member inherited from type '%2'">, + Warning<"non-static data member %0 of %1 shadows member inherited from " + "type %2">, InGroup<ShadowField>, DefaultIgnore; def note_shadow_field : Note<"declared here">; +def err_multiversion_required_in_redecl : Error< + "function declaration is missing %select{'target'|'cpu_specific' or " + "'cpu_dispatch'}0 attribute in a multiversioned function">; +def note_multiversioning_caused_here : Note< + "function multiversioning caused by this declaration">; +def err_multiversion_after_used : Error< + "function declaration cannot become a multiversioned function after first " + "usage">; +def err_bad_multiversion_option : Error< + "function multiversioning doesn't support %select{feature|architecture}0 " + "'%1'">; +def err_multiversion_duplicate : Error< + "multiversioned function redeclarations require identical target attributes">; +def err_multiversion_noproto : Error< + "multiversioned function must have a prototype">; +def err_multiversion_no_other_attrs : Error< + "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioning cannot be combined" + " with other attributes">; +def err_multiversion_diff : Error< + "multiversioned function declaration has a different %select{calling convention" + "|return type|constexpr specification|inline specification|storage class|" + "linkage}0">; +def err_multiversion_doesnt_support : Error< + "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioned functions do not " + "yet support %select{function templates|virtual functions|" + "deduced return types|constructors|destructors|deleted functions|" + "defaulted functions|constexpr functions}1">; +def err_multiversion_not_allowed_on_main : Error< + "'main' cannot be a multiversioned function">; +def err_multiversion_not_supported : Error< + "function multiversioning is not supported on the current target">; +def err_multiversion_types_mixed : Error< + "multiversioning attributes cannot be combined">; +def err_cpu_dispatch_mismatch : Error< + "'cpu_dispatch' function redeclared with different CPUs">; +def err_cpu_specific_multiple_defs : Error< + "multiple 'cpu_specific' functions cannot specify the same CPU: %0">; +def warn_multiversion_duplicate_entries : Warning< + "CPU list contains duplicate entries; attribute ignored">, + InGroup<FunctionMultiVersioning>; +def warn_dispatch_body_ignored : Warning< + "body of cpu_dispatch function will be ignored">, + InGroup<FunctionMultiVersioning>; + +// three-way comparison operator diagnostics +def err_implied_comparison_category_type_not_found : Error< + "cannot deduce return type of 'operator<=>' because type '%0' was not found; " + "include <compare>">; +def err_spaceship_argument_narrowing : Error< + "argument to 'operator<=>' " + "%select{cannot be narrowed from type %1 to %2|" + "evaluates to %1, which cannot be narrowed to type %2}0">; +def err_std_compare_type_not_supported : Error< + "standard library implementation of %0 is not supported; " + "%select{member '%2' does not have expected form|" + "member '%2' is missing|" + "the type is not trivially copyable|" + "the type does not have the expected form}1">; } // end of sema component. diff --git a/gnu/llvm/tools/clang/include/clang/Driver/CC1Options.td b/gnu/llvm/tools/clang/include/clang/Driver/CC1Options.td index f19b2c3f277..7565ca45c11 100644 --- a/gnu/llvm/tools/clang/include/clang/Driver/CC1Options.td +++ b/gnu/llvm/tools/clang/include/clang/Driver/CC1Options.td @@ -36,6 +36,10 @@ def triple_EQ : Joined<["-"], "triple=">, Alias<triple>; def mfpmath : Separate<["-"], "mfpmath">, HelpText<"Which unit to use for fp math">; +def fpadding_on_unsigned_fixed_point : Flag<["-"], "fpadding-on-unsigned-fixed-point">, + HelpText<"Force each unsigned fixed point type to have an extra bit of padding to align their scales with those of signed fixed point types">; +def fno_padding_on_unsigned_fixed_point : Flag<["-"], "fno-padding-on-unsigned-fixed-point">; + //===----------------------------------------------------------------------===// // Analyzer Options //===----------------------------------------------------------------------===// @@ -83,16 +87,16 @@ def analyzer_viz_egraph_ubigraph : Flag<["-"], "analyzer-viz-egraph-ubigraph">, def analyzer_inline_max_stack_depth : Separate<["-"], "analyzer-inline-max-stack-depth">, HelpText<"Bound on stack depth while inlining (4 by default)">; -def analyzer_inline_max_stack_depth_EQ : Joined<["-"], "analyzer-inline-max-stack-depth=">, +def analyzer_inline_max_stack_depth_EQ : Joined<["-"], "analyzer-inline-max-stack-depth=">, Alias<analyzer_inline_max_stack_depth>; - + def analyzer_inlining_mode : Separate<["-"], "analyzer-inlining-mode">, HelpText<"Specify the function selection heuristic used during inlining">; def analyzer_inlining_mode_EQ : Joined<["-"], "analyzer-inlining-mode=">, Alias<analyzer_inlining_mode>; def analyzer_disable_retry_exhausted : Flag<["-"], "analyzer-disable-retry-exhausted">, HelpText<"Do not re-analyze paths leading to exhausted nodes with a different strategy (may decrease code coverage)">; - + def analyzer_max_loop : Separate<["-"], "analyzer-max-loop">, HelpText<"The maximum number of times the analyzer will go through a loop">; def analyzer_stats : Flag<["-"], "analyzer-stats">, @@ -275,8 +279,6 @@ def split_stacks : Flag<["-"], "split-stacks">, HelpText<"Try to use a split stack if possible.">; def mno_zero_initialized_in_bss : Flag<["-"], "mno-zero-initialized-in-bss">, HelpText<"Do not put zero initialized data in the BSS">; -def backend_option : Separate<["-"], "backend-option">, - HelpText<"Additional arguments to forward to LLVM backend (during code gen)">; def mregparm : Separate<["-"], "mregparm">, HelpText<"Limit the number of registers available for integer arguments">; def munwind_tables : Flag<["-"], "munwind-tables">, @@ -447,6 +449,8 @@ def no_code_completion_ns_level_decls : Flag<["-"], "no-code-completion-ns-level HelpText<"Do not include declarations inside namespaces (incl. global namespace) in the code-completion results.">; def code_completion_brief_comments : Flag<["-"], "code-completion-brief-comments">, HelpText<"Include brief documentation comments in code-completion results.">; +def code_completion_with_fixits : Flag<["-"], "code-completion-with-fixits">, + HelpText<"Include code completion results which require small fix-its.">; def disable_free : Flag<["-"], "disable-free">, HelpText<"Disable freeing of memory on exit">; def discard_value_names : Flag<["-"], "discard-value-names">, @@ -533,6 +537,8 @@ def ast_dump : Flag<["-"], "ast-dump">, HelpText<"Build ASTs and then debug dump them">; def ast_dump_all : Flag<["-"], "ast-dump-all">, HelpText<"Build ASTs and then debug dump them, forcing deserialization">; +def templight_dump : Flag<["-"], "templight-dump">, + HelpText<"Dump templight information to stdout">; def ast_dump_lookups : Flag<["-"], "ast-dump-lookups">, HelpText<"Build ASTs and then debug dump their name lookup tables">; def ast_view : Flag<["-"], "ast-view">, @@ -561,6 +567,8 @@ def rewrite_macros : Flag<["-"], "rewrite-macros">, HelpText<"Expand macros without full preprocessing">; def migrate : Flag<["-"], "migrate">, HelpText<"Migrate source code">; +def compiler_options_dump : Flag<["-"], "compiler-options-dump">, + HelpText<"Dump the compiler configuration options">; } def emit_llvm_uselists : Flag<["-"], "emit-llvm-uselists">, @@ -599,13 +607,14 @@ def fixit_to_temp : Flag<["-"], "fixit-to-temporary">, def foverride_record_layout_EQ : Joined<["-"], "foverride-record-layout=">, HelpText<"Override record layouts with those in the given file">; -def find_pch_source_EQ : Joined<["-"], "find-pch-source=">, - HelpText<"When building a pch, try to find the input file in include " - "directories, as if it had been included by the argument passed " - "to this flag.">; +def pch_through_header_EQ : Joined<["-"], "pch-through-header=">, + HelpText<"Stop PCH generation after including this file. When using a PCH, " + "skip tokens until after this file is included.">; def fno_pch_timestamp : Flag<["-"], "fno-pch-timestamp">, HelpText<"Disable inclusion of timestamp in precompiled headers">; - +def building_pch_with_obj : Flag<["-"], "building-pch-with-obj">, + HelpText<"This compilation is part of building a PCH with corresponding object file.">; + def aligned_alloc_unavailable : Flag<["-"], "faligned-alloc-unavailable">, HelpText<"Aligned allocation/deallocation functions are unavailable">; @@ -619,6 +628,8 @@ def version : Flag<["-"], "version">, HelpText<"Print the compiler version">; def main_file_name : Separate<["-"], "main-file-name">, HelpText<"Main file name to use for debug info">; +def split_dwarf_file : Separate<["-"], "split-dwarf-file">, + HelpText<"File name to use for split dwarf debug info output">; } @@ -628,8 +639,6 @@ def fexternc_nounwind : Flag<["-"], "fexternc-nounwind">, HelpText<"Assume all functions with C linkage do not unwind">; def enable_split_dwarf : Flag<["-"], "enable-split-dwarf">, HelpText<"Use split dwarf/Fission">; -def split_dwarf_file : Separate<["-"], "split-dwarf-file">, - HelpText<"File name to use for split dwarf debug info output">; def fno_wchar : Flag<["-"], "fno-wchar">, HelpText<"Disable C++ builtin type wchar_t">; def fconstant_string_class : Separate<["-"], "fconstant-string-class">, @@ -645,6 +654,8 @@ def disable_objc_default_synthesize_properties : Flag<["-"], "disable-objc-defau HelpText<"disable the default synthesis of Objective-C properties">; def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signature">, HelpText<"enable extended encoding of block type signature">; +def function_alignment : Separate<["-"], "function-alignment">, + HelpText<"default alignment for functions">; def pic_level : Separate<["-"], "pic-level">, HelpText<"Value for __PIC__">; def pic_is_pie : Flag<["-"], "pic-is-pie">, @@ -707,8 +718,6 @@ def fobjc_subscripting_legacy_runtime : Flag<["-"], "fobjc-subscripting-legacy-r HelpText<"Allow Objective-C array and dictionary subscripting in legacy runtime">; def vtordisp_mode_EQ : Joined<["-"], "vtordisp-mode=">, HelpText<"Control vtordisp placement on win32 targets">; -def fno_rtti_data : Flag<["-"], "fno-rtti-data">, - HelpText<"Control emission of RTTI data">; def fnative_half_type: Flag<["-"], "fnative-half-type">, HelpText<"Use the native half type for __fp16 instead of promoting to float">; def fnative_half_arguments_and_returns : Flag<["-"], "fnative-half-arguments-and-returns">, @@ -808,7 +817,7 @@ def fopenmp_is_device : Flag<["-"], "fopenmp-is-device">, HelpText<"Generate code only for an OpenMP target device.">; def fopenmp_host_ir_file_path : Separate<["-"], "fopenmp-host-ir-file-path">, HelpText<"Path to the IR file produced by the frontend for the host.">; - + } // let Flags = [CC1Option] diff --git a/gnu/llvm/tools/clang/include/clang/Driver/Options.td b/gnu/llvm/tools/clang/include/clang/Driver/Options.td index 2b5be735f49..e8afeb469c5 100644 --- a/gnu/llvm/tools/clang/include/clang/Driver/Options.td +++ b/gnu/llvm/tools/clang/include/clang/Driver/Options.td @@ -143,14 +143,18 @@ def m_hexagon_Features_Group : OptionGroup<"<hexagon features group>">, // These are explicitly handled. def m_hexagon_Features_HVX_Group : OptionGroup<"<hexagon features group>">, Group<m_Group>, DocName<"Hexagon">; +def m_mips_Features_Group : OptionGroup<"<mips features group>">, + Group<m_Group>, DocName<"MIPS">; def m_ppc_Features_Group : OptionGroup<"<ppc features group>">, Group<m_Group>, DocName<"PowerPC">; def m_wasm_Features_Group : OptionGroup<"<wasm features group>">, Group<m_Group>, DocName<"WebAssembly">; def m_x86_Features_Group : OptionGroup<"<x86 features group>">, Group<m_Group>, Flags<[CoreOption]>, DocName<"X86">; +def m_riscv_Features_Group : OptionGroup<"<riscv features group>">, + Group<m_Group>, DocName<"RISCV">; -def m_libc_Group : OptionGroup<"<m libc group>">, Group<m_Group>, +def m_libc_Group : OptionGroup<"<m libc group>">, Group<m_mips_Features_Group>, Flags<[HelpHidden]>; def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>, @@ -396,7 +400,12 @@ def O_flag : Flag<["-"], "O">, Flags<[CC1Option]>, Alias<O>, AliasArgs<["2"]>; def Ofast : Joined<["-"], "Ofast">, Group<O_Group>, Flags<[CC1Option]>; def P : Flag<["-"], "P">, Flags<[CC1Option]>, Group<Preprocessor_Group>, HelpText<"Disable linemarker output in -E mode">; -def Qn : Flag<["-"], "Qn">, IgnoredGCCCompat; +def Qy : Flag<["-"], "Qy">, Flags<[CC1Option]>, + HelpText<"Emit metadata containing compiler name and version">; +def Qn : Flag<["-"], "Qn">, Flags<[CC1Option]>, + HelpText<"Do not emit metadata containing compiler name and version">; +def : Flag<["-"], "fident">, Group<f_Group>, Alias<Qy>, Flags<[CC1Option]>; +def : Flag<["-"], "fno-ident">, Group<f_Group>, Alias<Qn>, Flags<[CC1Option]>; def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[DriverOption, CoreOption]>, HelpText<"Don't emit warning for unused driver arguments">; def Q : Flag<["-"], "Q">, IgnoredGCCCompat; @@ -418,9 +427,9 @@ def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>, def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>, MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">; def Tdata : JoinedOrSeparate<["-"], "Tdata">, Group<T_Group>, - MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">; + MetaVarName<"<addr>">, HelpText<"Set starting address of DATA to <addr>">; def Ttext : JoinedOrSeparate<["-"], "Ttext">, Group<T_Group>, - MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">; + MetaVarName<"<addr>">, HelpText<"Set starting address of TEXT to <addr>">; def T : JoinedOrSeparate<["-"], "T">, Group<T_Group>, MetaVarName<"<script>">, HelpText<"Specify <script> as linker script">; def U : JoinedOrSeparate<["-"], "U">, Group<Preprocessor_Group>, @@ -466,7 +475,8 @@ def Xcuda_ptxas : Separate<["-"], "Xcuda-ptxas">, def Xopenmp_target : Separate<["-"], "Xopenmp-target">, HelpText<"Pass <arg> to the target offloading toolchain.">, MetaVarName<"<arg>">; def Xopenmp_target_EQ : JoinedAndSeparate<["-"], "Xopenmp-target=">, - HelpText<"Pass <arg> to the specified target offloading toolchain. The triple that identifies the toolchain must be provided after the equals sign.">, MetaVarName<"<arg>">; + HelpText<"Pass <arg> to the target offloading toolchain identified by <triple>.">, + MetaVarName<"<triple> <arg>">; def z : Separate<["-"], "z">, Flags<[LinkerInput, RenderAsInput]>, HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">, Group<Link_Group>; @@ -492,6 +502,8 @@ def bind__at__load : Flag<["-"], "bind_at_load">; def bundle__loader : Separate<["-"], "bundle_loader">; def bundle : Flag<["-"], "bundle">; def b : JoinedOrSeparate<["-"], "b">, Flags<[Unsupported]>; +def cfguard : Flag<["-"], "cfguard">, Flags<[CC1Option]>, + HelpText<"Emit tables required for Windows Control Flow Guard.">; def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>, Flags<[CC1Option]>, HelpText<"OpenCL only. This option disables all optimizations. By default optimizations are enabled.">; def cl_strict_aliasing : Flag<["-"], "cl-strict-aliasing">, Group<opencl_Group>, Flags<[CC1Option]>, @@ -511,11 +523,13 @@ def cl_mad_enable : Flag<["-"], "cl-mad-enable">, Group<opencl_Group>, Flags<[CC def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group<opencl_Group>, Flags<[CC1Option]>, HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">; def cl_std_EQ : Joined<["-"], "cl-std=">, Group<opencl_Group>, Flags<[CC1Option]>, - HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0">; + HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0,c++">; def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group<opencl_Group>, Flags<[CC1Option]>, HelpText<"OpenCL only. Allow denormals to be flushed to zero.">; def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group<opencl_Group>, Flags<[CC1Option]>, HelpText<"OpenCL only. Specify that single precision floating-point divide and sqrt used in the program source are correctly rounded.">; +def cl_uniform_work_group_size : Flag<["-"], "cl-uniform-work-group-size">, Group<opencl_Group>, Flags<[CC1Option]>, + HelpText<"OpenCL only. Defines that the global work-size be a multiple of the work-group size specified to clEnqueueNDRangeKernel">; def client__name : JoinedOrSeparate<["-"], "client_name">; def combine : Flag<["-", "--"], "combine">, Flags<[DriverOption, Unsupported]>; def compatibility__version : JoinedOrSeparate<["-"], "compatibility_version">; @@ -541,8 +555,14 @@ def cuda_host_only : Flag<["--"], "cuda-host-only">, def cuda_compile_host_device : Flag<["--"], "cuda-compile-host-device">, HelpText<"Compile CUDA code for both host and device (default). Has no " "effect on non-CUDA compilations.">; +def cuda_include_ptx_EQ : Joined<["--"], "cuda-include-ptx=">, Flags<[DriverOption]>, + HelpText<"Include PTX for the follwing GPU architecture (e.g. sm_35) or 'all'. May be specified more than once.">; +def no_cuda_include_ptx_EQ : Joined<["--"], "no-cuda-include-ptx=">, Flags<[DriverOption]>, + HelpText<"Do not include PTX for the follwing GPU architecture (e.g. sm_35) or 'all'. May be specified more than once.">; def cuda_gpu_arch_EQ : Joined<["--"], "cuda-gpu-arch=">, Flags<[DriverOption]>, HelpText<"CUDA GPU architecture (e.g. sm_35). May be specified more than once.">; +def hip_link : Flag<["--"], "hip-link">, + HelpText<"Link clang-offload-bundler bundles for HIP">; def no_cuda_gpu_arch_EQ : Joined<["--"], "no-cuda-gpu-arch=">, Flags<[DriverOption]>, HelpText<"Remove GPU architecture (e.g. sm_35) from the list of GPUs to compile for. " "'all' resets the list to its default value.">; @@ -554,6 +574,8 @@ def no_cuda_version_check : Flag<["--"], "no-cuda-version-check">, def no_cuda_noopt_device_debug : Flag<["--"], "no-cuda-noopt-device-debug">; def cuda_path_EQ : Joined<["--"], "cuda-path=">, Group<i_Group>, HelpText<"CUDA installation path">; +def cuda_path_ignore_env : Flag<["--"], "cuda-path-ignore-env">, Group<i_Group>, + HelpText<"Ignore environment variables to detect CUDA installation">; def ptxas_path_EQ : Joined<["--"], "ptxas-path=">, Group<i_Group>, HelpText<"Path to ptxas (used for compiling CUDA code)">; def fcuda_flush_denormals_to_zero : Flag<["-"], "fcuda-flush-denormals-to-zero">, @@ -562,6 +584,18 @@ def fno_cuda_flush_denormals_to_zero : Flag<["-"], "fno-cuda-flush-denormals-to- def fcuda_approx_transcendentals : Flag<["-"], "fcuda-approx-transcendentals">, Flags<[CC1Option]>, HelpText<"Use approximate transcendental functions">; def fno_cuda_approx_transcendentals : Flag<["-"], "fno-cuda-approx-transcendentals">; +def fcuda_rdc : Flag<["-"], "fcuda-rdc">, Flags<[CC1Option]>, + HelpText<"Generate relocatable device code, also known as separate compilation mode.">; +def fno_cuda_rdc : Flag<["-"], "fno-cuda-rdc">; +def fcuda_short_ptr : Flag<["-"], "fcuda-short-ptr">, Flags<[CC1Option]>, + HelpText<"Use 32-bit pointers for accessing const/local/shared address spaces.">; +def fno_cuda_short_ptr : Flag<["-"], "fno-cuda-short-ptr">; +def hip_device_lib_path_EQ : Joined<["--"], "hip-device-lib-path=">, Group<Link_Group>, + HelpText<"HIP device library path">; +def hip_device_lib_EQ : Joined<["--"], "hip-device-lib=">, Group<Link_Group>, + HelpText<"HIP device library">; +def fhip_dump_offload_linker_script : Flag<["-"], "fhip-dump-offload-linker-script">, + Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>; def dA : Flag<["-"], "dA">, Group<d_Group>; def dD : Flag<["-"], "dD">, Group<d_Group>, Flags<[CC1Option]>, HelpText<"Print macro definitions in -E mode in addition to normal output">; @@ -597,6 +631,9 @@ def fno_PIC : Flag<["-"], "fno-PIC">, Group<f_Group>; def fPIE : Flag<["-"], "fPIE">, Group<f_Group>; def fno_PIE : Flag<["-"], "fno-PIE">, Group<f_Group>; def faccess_control : Flag<["-"], "faccess-control">, Group<f_Group>; +def falign_functions : Flag<["-"], "falign-functions">, Group<f_Group>; +def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group<f_Group>; +def fno_align_functions: Flag<["-"], "fno-align-functions">, Group<f_Group>; def fallow_unsupported : Flag<["-"], "fallow-unsupported">, Group<f_Group>; def fapple_kext : Flag<["-"], "fapple-kext">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Use Apple's kernel extensions ABI">; @@ -693,10 +730,10 @@ def fprofile_instr_use_EQ : Joined<["-"], "fprofile-instr-use=">, Group<f_Group>, Flags<[CoreOption]>, HelpText<"Use instrumentation data for profile-guided optimization">; def fcoverage_mapping : Flag<["-"], "fcoverage-mapping">, - Group<f_Group>, Flags<[CC1Option]>, + Group<f_Group>, Flags<[CC1Option, CoreOption]>, HelpText<"Generate coverage mapping to enable code coverage analysis">; def fno_coverage_mapping : Flag<["-"], "fno-coverage-mapping">, - Group<f_Group>, Flags<[DriverOption]>, + Group<f_Group>, Flags<[DriverOption, CoreOption]>, HelpText<"Disable code coverage analysis">; def fprofile_generate : Flag<["-"], "fprofile-generate">, Group<f_Group>, Flags<[DriverOption]>, @@ -721,12 +758,16 @@ def fno_profile_instr_use : Flag<["-"], "fno-profile-instr-use">, def fno_profile_use : Flag<["-"], "fno-profile-use">, Alias<fno_profile_instr_use>; -def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CC1Option]>, +def faddrsig : Flag<["-"], "faddrsig">, Group<f_Group>, Flags<[CoreOption, CC1Option]>, + HelpText<"Emit an address-significance table">; +def fno_addrsig : Flag<["-"], "fno-addrsig">, Group<f_Group>, Flags<[CoreOption]>, + HelpText<"Don't emit an address-significance table">; +def fblocks : Flag<["-"], "fblocks">, Group<f_Group>, Flags<[CoreOption, CC1Option]>, HelpText<"Enable the 'blocks' language feature">; def fbootclasspath_EQ : Joined<["-"], "fbootclasspath=">, Group<f_Group>; def fborland_extensions : Flag<["-"], "fborland-extensions">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Accept non-standard constructs supported by the Borland compiler">; -def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>; +def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>, Flags<[CoreOption]>; def fbuiltin_module_map : Flag <["-"], "fbuiltin-module-map">, Group<f_Group>, Flags<[DriverOption]>, HelpText<"Load the clang builtins module map file.">; def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group<f_Group>; @@ -747,6 +788,12 @@ def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, Gr def fparse_all_comments : Flag<["-"], "fparse-all-comments">, Group<f_clang_Group>, Flags<[CC1Option]>; def fcommon : Flag<["-"], "fcommon">, Group<f_Group>; def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group<f_Group>; +def fcomplete_member_pointers : Flag<["-"], "fcomplete-member-pointers">, Group<f_clang_Group>, + Flags<[CoreOption, CC1Option]>, + HelpText<"Require member pointer base types to be complete if they would be significant under the Microsoft ABI">; +def fno_complete_member_pointers : Flag<["-"], "fno-complete-member-pointers">, Group<f_clang_Group>, + Flags<[CoreOption]>, + HelpText<"Do not require member pointer base types to be complete if they would be significant under the Microsoft ABI">; def fconstant_cfstrings : Flag<["-"], "fconstant-cfstrings">, Group<f_Group>; def fconstant_string_class_EQ : Joined<["-"], "fconstant-string-class=">, Group<f_Group>; def fconstexpr_depth_EQ : Joined<["-"], "fconstexpr-depth=">, Group<f_Group>; @@ -755,6 +802,7 @@ def fconstexpr_backtrace_limit_EQ : Joined<["-"], "fconstexpr-backtrace-limit="> Group<f_Group>; def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>, HelpText<"Disable auto-generation of preprocessed source files and a script for reproduction during a clang crash">; +def fcrash_diagnostics_dir : Joined<["-"], "fcrash-diagnostics-dir=">, Group<f_clang_Group>, Flags<[NoArgumentUnused, CoreOption]>; def fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>; def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group<f_Group>, HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>; @@ -786,6 +834,10 @@ def fdiagnostics_show_template_tree : Flag<["-"], "fdiagnostics-show-template-tr HelpText<"Print a template comparison tree for differing templates">; def fdeclspec : Flag<["-"], "fdeclspec">, Group<f_clang_Group>, HelpText<"Allow __declspec as a keyword">, Flags<[CC1Option]>; +def fdiscard_value_names : Flag<["-"], "fdiscard-value-names">, Group<f_clang_Group>, + HelpText<"Discard value names in LLVM IR">, Flags<[DriverOption]>; +def fno_discard_value_names : Flag<["-"], "fno-discard-value-names">, Group<f_clang_Group>, + HelpText<"Do not discard value names in LLVM IR">, Flags<[DriverOption]>; def fdollars_in_identifiers : Flag<["-"], "fdollars-in-identifiers">, Group<f_Group>, HelpText<"Allow '$' in identifiers">, Flags<[CC1Option]>; def fdwarf2_cfi_asm : Flag<["-"], "fdwarf2-cfi-asm">, Group<clang_ignored_f_Group>; @@ -801,7 +853,7 @@ def femit_all_decls : Flag<["-"], "femit-all-decls">, Group<f_Group>, Flags<[CC1 HelpText<"Emit all declarations, even if unused">; def femulated_tls : Flag<["-"], "femulated-tls">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Use emutls functions to access thread_local variables">; -def fno_emulated_tls : Flag<["-"], "fno-emulated-tls">, Group<f_Group>; +def fno_emulated_tls : Flag<["-"], "fno-emulated-tls">, Group<f_Group>, Flags<[CC1Option]>; def fencoding_EQ : Joined<["-"], "fencoding=">, Group<f_Group>; def ferror_limit_EQ : Joined<["-"], "ferror-limit=">, Group<f_Group>, Flags<[CoreOption]>; def fexceptions : Flag<["-"], "fexceptions">, Group<f_Group>, Flags<[CC1Option]>, @@ -835,6 +887,17 @@ def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>; def fjump_tables : Flag<["-"], "fjump-tables">, Group<f_Group>; def fno_jump_tables : Flag<["-"], "fno-jump-tables">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Do not use jump tables for lowering switches">; +def fforce_enable_int128 : Flag<["-"], "fforce-enable-int128">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable support for int128_t type">; +def fno_force_enable_int128 : Flag<["-"], "fno-force-enable-int128">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Disable support for int128_t type">; + +def ffixed_point : Flag<["-"], "ffixed-point">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Enable fixed point types">; +def fno_fixed_point : Flag<["-"], "fno-fixed-point">, Group<f_Group>, + HelpText<"Disable fixed point types">; // Begin sanitizer flags. These should all be core options exposed in all driver // modes. @@ -887,6 +950,14 @@ def fno_sanitize_address_use_after_scope : Flag<["-"], "fno-sanitize-address-use Group<f_clang_Group>, Flags<[CoreOption, DriverOption]>, HelpText<"Disable use-after-scope detection in AddressSanitizer">; +def fsanitize_address_poison_class_member_array_new_cookie + : Flag<[ "-" ], "fsanitize-address-poison-class-member-array-new-cookie">, + Group<f_clang_Group>, + HelpText<"Enable poisoning array cookies when using class member operator new[] in AddressSanitizer">; +def fno_sanitize_address_poison_class_member_array_new_cookie + : Flag<[ "-" ], "fno-sanitize-address-poison-class-member-array-new-cookie">, + Group<f_clang_Group>, + HelpText<"Disable poisoning array cookies when using class member operator new[] in AddressSanitizer">; def fsanitize_address_globals_dead_stripping : Flag<["-"], "fsanitize-address-globals-dead-stripping">, Group<f_clang_Group>, HelpText<"Enable linker dead stripping of globals in AddressSanitizer">; @@ -991,6 +1062,13 @@ def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)" " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">, Values<"fast,on,off">; +def fstrict_float_cast_overflow : Flag<["-"], + "fstrict-float-cast-overflow">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Assume that overflowing float-to-int casts are undefined (default)">; +def fno_strict_float_cast_overflow : Flag<["-"], + "fno-strict-float-cast-overflow">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Relax language rules and try to match the behavior of the target's native float-to-int conversion instructions">; + def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>; def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>; @@ -1002,6 +1080,13 @@ def frewrite_imports : Flag<["-"], "frewrite-imports">, Group<f_Group>, Flags<[CC1Option]>; def fno_rewrite_imports : Flag<["-"], "fno-rewrite-imports">, Group<f_Group>; +def fdelete_null_pointer_checks : Flag<["-"], + "fdelete-null-pointer-checks">, Group<f_Group>, + HelpText<"Treat usage of null pointers as undefined behavior.">; +def fno_delete_null_pointer_checks : Flag<["-"], + "fno-delete-null-pointer-checks">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Do not treat usage of null pointers as undefined behavior.">; + def frewrite_map_file : Separate<["-"], "frewrite-map-file">, Group<f_Group>, Flags<[ DriverOption, CC1Option ]>; @@ -1044,6 +1129,11 @@ def finstrument_functions_after_inlining : Flag<["-"], "finstrument-functions-af HelpText<"Like -finstrument-functions, but insert the calls after inlining">; def finstrument_function_entry_bare : Flag<["-"], "finstrument-function-entry-bare">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Instrument function entry only, after inlining, without arguments to the instrumentation call">; +def fcf_protection_EQ : Joined<["-"], "fcf-protection=">, Flags<[CoreOption, CC1Option]>, Group<f_Group>, + HelpText<"Instrument control-flow architecture protection. Options: return, branch, full, none.">, Values<"return,branch,full,none">; +def fcf_protection : Flag<["-"], "fcf-protection">, Group<f_Group>, Flags<[CoreOption, CC1Option]>, + Alias<fcf_protection_EQ>, AliasArgs<["full"]>, + HelpText<"Enable cf-protection in 'full' mode">; def fxray_instrument : Flag<["-"], "fxray-instrument">, Group<f_Group>, Flags<[CC1Option]>, @@ -1062,11 +1152,19 @@ def fxray_instruction_threshold_ : def fxray_always_instrument : JoinedOrSeparate<["-"], "fxray-always-instrument=">, Group<f_Group>, Flags<[CC1Option]>, - HelpText<"Filename defining the whitelist for imbuing the 'always instrument' XRay attribute.">; + HelpText<"DEPRECATED: Filename defining the whitelist for imbuing the 'always instrument' XRay attribute.">; def fxray_never_instrument : JoinedOrSeparate<["-"], "fxray-never-instrument=">, Group<f_Group>, Flags<[CC1Option]>, - HelpText<"Filename defining the whitelist for imbuing the 'never instrument' XRay attribute.">; + HelpText<"DEPRECATED: Filename defining the whitelist for imbuing the 'never instrument' XRay attribute.">; +def fxray_attr_list : + JoinedOrSeparate<["-"], "fxray-attr-list=">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Filename defining the list of functions/types for imbuing XRay attributes.">; +def fxray_modes : + JoinedOrSeparate<["-"], "fxray-modes=">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"List of modes to link in by default into XRay instrumented binaries.">; def fxray_always_emit_customevents : Flag<["-"], "fxray-always-emit-customevents">, Group<f_Group>, Flags<[CC1Option]>, @@ -1074,9 +1172,26 @@ def fxray_always_emit_customevents : Flag<["-"], "fxray-always-emit-customevents def fnoxray_always_emit_customevents : Flag<["-"], "fno-xray-always-emit-customevents">, Group<f_Group>, Flags<[CC1Option]>; +def fxray_always_emit_typedevents : Flag<["-"], "fxray-always-emit-typedevents">, Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Determine whether to always emit __xray_typedevent(...) calls even if the function it appears in is not always instrumented.">; +def fnoxray_always_emit_typedevents : Flag<["-"], "fno-xray-always-emit-typedevents">, Group<f_Group>, + Flags<[CC1Option]>; + +def fxray_link_deps : Flag<["-"], "fxray-link-deps">, Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Tells clang to add the link dependencies for XRay.">; +def fnoxray_link_deps : Flag<["-"], "fnoxray-link-deps">, Group<f_Group>, + Flags<[CC1Option]>; + +def fxray_instrumentation_bundle : + JoinedOrSeparate<["-"], "fxray-instrumentation-bundle=">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Select which XRay instrumentation points to emit. Options: all, none, function, custom. Default is 'all'.">; + def ffine_grained_bitfield_accesses : Flag<["-"], "ffine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>, - HelpText<"Use separate accesses for bitfields with legal widths and alignments.">; + HelpText<"Use separate accesses for consecutive bitfield runs with legal widths and alignments.">; def fno_fine_grained_bitfield_accesses : Flag<["-"], "fno-fine-grained-bitfield-accesses">, Group<f_clang_Group>, Flags<[CC1Option]>, HelpText<"Use large-integer access for consecutive bitfield runs.">; @@ -1100,7 +1215,8 @@ def fthinlto_index_EQ : Joined<["-"], "fthinlto-index=">, HelpText<"Perform ThinLTO importing using provided function summary index">; def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">, Group<f_Group>, Flags<[DriverOption, CoreOption]>; -def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group<f_Group>; +def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group<f_Group>, + Flags<[CC1Option, CoreOption]>, HelpText<"Allow merging of constants">; def fmessage_length_EQ : Joined<["-"], "fmessage-length=">, Group<f_Group>; def fms_extensions : Flag<["-"], "fms-extensions">, Group<f_Group>, Flags<[CC1Option, CoreOption]>, HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">; @@ -1154,6 +1270,8 @@ def fmodules_disable_diagnostic_validation : Flag<["-"], "fmodules-disable-diagn def fmodules_validate_system_headers : Flag<["-"], "fmodules-validate-system-headers">, Group<i_Group>, Flags<[CC1Option]>, HelpText<"Validate the system headers that a module depends on when loading the module">; +def fno_modules_validate_system_headers : Flag<["-"], "fno-modules-validate-system-headers">, + Group<i_Group>, Flags<[DriverOption]>; def fmodules : Flag <["-"], "fmodules">, Group<f_Group>, Flags<[DriverOption, CC1Option]>, HelpText<"Enable the 'modules' language feature">; @@ -1202,11 +1320,11 @@ def fno_asynchronous_unwind_tables : Flag<["-"], "fno-asynchronous-unwind-tables def fno_assume_sane_operator_new : Flag<["-"], "fno-assume-sane-operator-new">, Group<f_Group>, HelpText<"Don't assume that C++'s global operator new can't alias any pointer">, Flags<[CC1Option]>; -def fno_blocks : Flag<["-"], "fno-blocks">, Group<f_Group>; +def fno_blocks : Flag<["-"], "fno-blocks">, Group<f_Group>, Flags<[CoreOption]>; def fno_borland_extensions : Flag<["-"], "fno-borland-extensions">, Group<f_Group>; -def fno_builtin : Flag<["-"], "fno-builtin">, Group<f_Group>, Flags<[CC1Option]>, +def fno_builtin : Flag<["-"], "fno-builtin">, Group<f_Group>, Flags<[CC1Option, CoreOption]>, HelpText<"Disable implicit builtin knowledge of functions">; -def fno_builtin_ : Joined<["-"], "fno-builtin-">, Group<f_Group>, Flags<[CC1Option]>, +def fno_builtin_ : Joined<["-"], "fno-builtin-">, Group<f_Group>, Flags<[CC1Option, CoreOption]>, HelpText<"Disable implicit builtin knowledge of a specific function">; def fno_caret_diagnostics : Flag<["-"], "fno-caret-diagnostics">, Group<f_Group>, Flags<[CC1Option]>; @@ -1228,6 +1346,10 @@ def fno_diagnostics_show_hotness : Flag<["-"], "fno-diagnostics-show-hotness">, def fno_diagnostics_show_option : Flag<["-"], "fno-diagnostics-show-option">, Group<f_Group>; def fno_diagnostics_show_note_include_stack : Flag<["-"], "fno-diagnostics-show-note-include-stack">, Flags<[CC1Option]>, Group<f_Group>; +def fdigraphs : Flag<["-"], "fdigraphs">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable alternative token representations '<:', ':>', '<%', '%>', '%:', '%:%:' (default)">; +def fno_digraphs : Flag<["-"], "fno-digraphs">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Disallow alternative token representations '<:', ':>', '<%', '%>', '%:', '%:%:'">; def fno_declspec : Flag<["-"], "fno-declspec">, Group<f_clang_Group>, HelpText<"Disallow __declspec as a keyword">, Flags<[CC1Option]>; def fno_dollars_in_identifiers : Flag<["-"], "fno-dollars-in-identifiers">, Group<f_Group>, @@ -1249,7 +1371,7 @@ def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>, Flags<[CC1Option]>, def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>, HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>; def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>, - Flags<[CC1Option]>, HelpText<"Disallow merging of constants">; + HelpText<"Disallow merging of constants">; def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>, Flags<[DriverOption]>; def fno_implicit_module_maps : Flag <["-"], "fno-implicit-module-maps">, Group<f_Group>, @@ -1282,6 +1404,8 @@ def fno_operator_names : Flag<["-"], "fno-operator-names">, Group<f_Group>, def fno_pascal_strings : Flag<["-"], "fno-pascal-strings">, Group<f_Group>; def fno_rtti : Flag<["-"], "fno-rtti">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Disable generation of rtti information">; +def fno_rtti_data : Flag<["-"], "fno-rtti-data">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Control emission of RTTI data">; def fno_short_enums : Flag<["-"], "fno-short-enums">, Group<f_Group>; def fno_show_column : Flag<["-"], "fno-show-column">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Do not include column number on diagnostics">; @@ -1305,6 +1429,8 @@ def fno_threadsafe_statics : Flag<["-"], "fno-threadsafe-statics">, Group<f_Grou Flags<[CC1Option]>, HelpText<"Do not emit code to make initialization of local statics thread safe">; def fno_use_cxa_atexit : Flag<["-"], "fno-use-cxa-atexit">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Don't use __cxa_atexit for calling destructors">; +def fno_register_global_dtors_with_atexit : Flag<["-"], "fno-register-global-dtors-with-atexit">, Group<f_Group>, + HelpText<"Don't use atexit or __cxa_atexit to register global destructors">; def fno_use_init_array : Flag<["-"], "fno-use-init-array">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Don't use .init_array instead of .ctors">; def fno_unit_at_a_time : Flag<["-"], "fno-unit-at-a-time">, Group<f_Group>; @@ -1362,7 +1488,7 @@ def fobjc_weak : Flag<["-"], "fobjc-weak">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Enable ARC-style weak references in Objective-C">; // Objective-C ABI options. -def fobjc_runtime_EQ : Joined<["-"], "fobjc-runtime=">, Group<f_Group>, Flags<[CC1Option]>, +def fobjc_runtime_EQ : Joined<["-"], "fobjc-runtime=">, Group<f_Group>, Flags<[CC1Option, CoreOption]>, HelpText<"Specify the target Objective-C runtime kind and version">; def fobjc_abi_version_EQ : Joined<["-"], "fobjc-abi-version=">, Group<f_Group>; def fobjc_nonfragile_abi_version_EQ : Joined<["-"], "fobjc-nonfragile-abi-version=">, Group<f_Group>; @@ -1371,26 +1497,34 @@ def fno_objc_nonfragile_abi : Flag<["-"], "fno-objc-nonfragile-abi">, Group<f_Gr def fobjc_sender_dependent_dispatch : Flag<["-"], "fobjc-sender-dependent-dispatch">, Group<f_Group>; def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>; -def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>; +def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>, + HelpText<"Parse OpenMP pragmas and generate parallel code.">; def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>, Flags<[NoArgumentUnused]>; def fopenmp_version_EQ : Joined<["-"], "fopenmp-version=">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>; def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>; -def fopenmp_use_tls : Flag<["-"], "fopenmp-use-tls">, Group<f_Group>, Flags<[NoArgumentUnused]>; -def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>; +def fopenmp_use_tls : Flag<["-"], "fopenmp-use-tls">, Group<f_Group>, + Flags<[NoArgumentUnused, HelpHidden]>; +def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group<f_Group>, + Flags<[CC1Option, NoArgumentUnused, HelpHidden]>; def fopenmp_targets_EQ : CommaJoined<["-"], "fopenmp-targets=">, Flags<[DriverOption, CC1Option]>, HelpText<"Specify comma-separated list of triples OpenMP offloading targets to be supported">; -def fopenmp_dump_offload_linker_script : Flag<["-"], "fopenmp-dump-offload-linker-script">, Group<f_Group>, - Flags<[NoArgumentUnused]>; -def fopenmp_relocatable_target : Flag<["-"], "fopenmp-relocatable-target">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>, - HelpText<"OpenMP target code is compiled as relocatable using the -c flag. For OpenMP targets the code is relocatable by default.">; -def fnoopenmp_relocatable_target : Flag<["-"], "fnoopenmp-relocatable-target">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>, - HelpText<"Do not compile OpenMP target code as relocatable.">; +def fopenmp_dump_offload_linker_script : Flag<["-"], "fopenmp-dump-offload-linker-script">, + Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>; +def fopenmp_relocatable_target : Flag<["-"], "fopenmp-relocatable-target">, + Group<f_Group>, Flags<[CC1Option, NoArgumentUnused, HelpHidden]>; +def fnoopenmp_relocatable_target : Flag<["-"], "fnoopenmp-relocatable-target">, + Group<f_Group>, Flags<[CC1Option, NoArgumentUnused, HelpHidden]>; def fopenmp_simd : Flag<["-"], "fopenmp-simd">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>, HelpText<"Emit OpenMP code only for SIMD-based constructs.">; -def fno_openmp_simd : Flag<["-"], "fno-openmp-simd">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>, - HelpText<"Disable OpenMP code for SIMD-based constructs.">; +def fno_openmp_simd : Flag<["-"], "fno-openmp-simd">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>; +def fopenmp_cuda_mode : Flag<["-"], "fopenmp-cuda-mode">, Group<f_Group>, + Flags<[CC1Option, NoArgumentUnused, HelpHidden]>; +def fno_openmp_cuda_mode : Flag<["-"], "fno-openmp-cuda-mode">, Group<f_Group>, + Flags<[NoArgumentUnused, HelpHidden]>; def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>; def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>; +def fno_escaping_block_tail_calls : Flag<["-"], "fno-escaping-block-tail-calls">, Group<f_Group>, Flags<[CC1Option]>; +def fescaping_block_tail_calls : Flag<["-"], "fescaping-block-tail-calls">, Group<f_Group>; def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">; def force__flat__namespace : Flag<["-"], "force_flat_namespace">; def force__load : Separate<["-"], "force_load">; @@ -1435,6 +1569,10 @@ def frtti : Flag<["-"], "frtti">, Group<f_Group>; def : Flag<["-"], "fsched-interblock">, Group<clang_ignored_f_Group>; def fshort_enums : Flag<["-"], "fshort-enums">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">; +def fchar8__t : Flag<["-"], "fchar8_t">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable C++ builtin type char8_t">; +def fno_char8__t : Flag<["-"], "fno-char8_t">, Group<f_Group>, + HelpText<"Disable C++ builtin type char8_t">; def fshort_wchar : Flag<["-"], "fshort-wchar">, Group<f_Group>, HelpText<"Force wchar_t to be a short unsigned int">; def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, @@ -1551,6 +1689,8 @@ def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>; def fno_unsigned_char : Flag<["-"], "fno-unsigned-char">; def funwind_tables : Flag<["-"], "funwind-tables">, Group<f_Group>; def fuse_cxa_atexit : Flag<["-"], "fuse-cxa-atexit">, Group<f_Group>; +def fregister_global_dtors_with_atexit : Flag<["-"], "fregister-global-dtors-with-atexit">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Use atexit or __cxa_atexit to register global destructors">; def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Use .init_array instead of .ctors">; def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group<clang_ignored_f_Group>; @@ -1558,7 +1698,7 @@ def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>; def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>, HelpText<"Set the default symbol visibility for all global declarations">, Values<"hidden,default">; def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>, - HelpText<"Give inline C++ member functions default visibility by default">, + HelpText<"Give inline C++ member functions hidden visibility by default">, Flags<[CC1Option]>; def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group<f_Group>, HelpText<"Give global types 'default' visibility and global functions and " @@ -1568,6 +1708,11 @@ def fwhole_program_vtables : Flag<["-"], "fwhole-program-vtables">, Group<f_Grou HelpText<"Enables whole-program vtable optimization. Requires -flto">; def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>, Flags<[CoreOption]>; +def fforce_emit_vtables : Flag<["-"], "fforce-emit-vtables">, Group<f_Group>, + Flags<[CC1Option]>, + HelpText<"Emits more virtual tables to improve devirtualization">; +def fno_force_emit_vtables : Flag<["-"], "fno-force-emit-vtables">, Group<f_Group>, + Flags<[CoreOption]>; def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Treat signed integer overflow as two's complement">; def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>, @@ -1582,6 +1727,10 @@ def fdata_sections : Flag <["-"], "fdata-sections">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Place each data in its own section (ELF Only)">; def fno_data_sections : Flag <["-"], "fno-data-sections">, Group<f_Group>, Flags<[CC1Option]>; +def fstack_size_section : Flag<["-"], "fstack-size-section">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Emit section containing metadata on function stack sizes">; +def fno_stack_size_section : Flag<["-"], "fno-stack-size-section">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Don't emit section containing metadata on function stack sizes">; def funique_section_names : Flag <["-"], "funique-section-names">, Group<f_Group>, Flags<[CC1Option]>, @@ -1607,11 +1756,12 @@ def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>, def fno_debug_types_section: Flag<["-"], "fno-debug-types-section">, Group<f_Group>, Flags<[CC1Option]>; def fsplit_dwarf_inlining: Flag <["-"], "fsplit-dwarf-inlining">, Group<f_Group>, - Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">; + Flags<[CC1Option]>, HelpText<"Provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF">; def fno_split_dwarf_inlining: Flag<["-"], "fno-split-dwarf-inlining">, Group<f_Group>, Flags<[CC1Option]>; def fdebug_prefix_map_EQ - : Joined<["-"], "fdebug-prefix-map=">, Group<f_Group>, Flags<[CC1Option]>, + : Joined<["-"], "fdebug-prefix-map=">, Group<f_Group>, + Flags<[CC1Option,CC1AsOption]>, HelpText<"remap file source paths in debug info">; def g_Flag : Flag<["-"], "g">, Group<g_Group>, HelpText<"Generate source-level debug information">; @@ -1660,6 +1810,7 @@ def gcolumn_info : Flag<["-"], "gcolumn-info">, Group<g_flags_Group>, Flags<[Cor def gno_column_info : Flag<["-"], "gno-column-info">, Group<g_flags_Group>, Flags<[CoreOption]>; def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>; def ggnu_pubnames : Flag<["-"], "ggnu-pubnames">, Group<g_flags_Group>, Flags<[CC1Option]>; +def gno_gnu_pubnames : Flag<["-"], "gno-gnu-pubnames">, Group<g_flags_Group>, Flags<[CC1Option]>; def gdwarf_aranges : Flag<["-"], "gdwarf-aranges">, Group<g_flags_Group>; def gmodules : Flag <["-"], "gmodules">, Group<gN_Group>, HelpText<"Generate debug info with external references to clang modules" @@ -1668,6 +1819,11 @@ def gz : Flag<["-"], "gz">, Group<g_flags_Group>, HelpText<"DWARF debug sections compression type">; def gz_EQ : Joined<["-"], "gz=">, Group<g_flags_Group>, HelpText<"DWARF debug sections compression type">; +def gembed_source : Flag<["-"], "gembed-source">, Group<g_flags_Group>, Flags<[CC1Option]>, + HelpText<"Embed source text in DWARF debug sections">; +def gno_embed_source : Flag<["-"], "gno-embed-source">, Group<g_flags_Group>, + Flags<[DriverOption]>, + HelpText<"Restore the default behavior of not embedding source text in DWARF debug sections">; def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">; def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption]>, HelpText<"Display available options">; @@ -1718,7 +1874,7 @@ def iwithsysroot : JoinedOrSeparate<["-"], "iwithsysroot">, Group<clang_i_Group> Flags<[CC1Option]>; def ivfsoverlay : JoinedOrSeparate<["-"], "ivfsoverlay">, Group<clang_i_Group>, Flags<[CC1Option]>, HelpText<"Overlay the virtual filesystem described by file over the real file system">; -def i : Joined<["-"], "i">, Group<i_Group>; +def imultilib : Separate<["-"], "imultilib">, Group<gfortran_Group>; def keep__private__externs : Flag<["-"], "keep_private_externs">; def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>, Group<Link_Group>; @@ -1805,6 +1961,10 @@ def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">, Group<m_Group>, Alias<mmacosx_version_min_EQ>; def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">; +def moutline : Flag<["-"], "moutline">, Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Enable function outlining (AArch64 only)">; +def mno_outline : Flag<["-"], "mno-outline">, Group<f_clang_Group>, Flags<[CC1Option]>, + HelpText<"Disable function outlining (AArch64 only)">; def mno_ms_bitfields : Flag<["-"], "mno-ms-bitfields">, Group<m_Group>, HelpText<"Do not set the default structure layout to be compatible with the Microsoft compiler standard">; def mstackrealign : Flag<["-"], "mstackrealign">, Group<m_Group>, Flags<[CC1Option]>, @@ -1813,6 +1973,10 @@ def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group<m_Group>, Flags HelpText<"Set the stack alignment">; def mstack_probe_size : Joined<["-"], "mstack-probe-size=">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"Set the stack probe size">; +def mstack_arg_probe : Flag<["-"], "mstack-arg-probe">, Group<m_Group>, + HelpText<"Enable stack probes">; +def mno_stack_arg_probe : Flag<["-"], "mno-stack-arg-probe">, Group<m_Group>, Flags<[CC1Option]>, + HelpText<"Disable stack probes which are enabled by default">; def mthread_model : Separate<["-"], "mthread-model">, Group<m_Group>, Flags<[CC1Option]>, HelpText<"The thread model to use, e.g. posix, single (posix by default)">, Values<"posix,single">; def meabi : Separate<["-"], "meabi">, Group<m_Group>, Flags<[CC1Option]>, @@ -1829,6 +1993,11 @@ def mno_rtd: Flag<["-"], "mno-rtd">, Group<m_Group>; def mno_soft_float : Flag<["-"], "mno-soft-float">, Group<m_Group>; def mno_stackrealign : Flag<["-"], "mno-stackrealign">, Group<m_Group>; +def mrelax : Flag<["-"], "mrelax">, Group<m_riscv_Features_Group>, + HelpText<"Enable linker relaxation">; +def mno_relax : Flag<["-"], "mno-relax">, Group<m_riscv_Features_Group>, + HelpText<"Disable linker relaxation">; + def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>, HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">; def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group<m_arm_Features_Group>, @@ -1845,8 +2014,8 @@ def ffixed_r9 : Flag<["-"], "ffixed-r9">, Group<m_arm_Features_Group>, HelpText<"Reserve the r9 register (ARM only)">; def mno_movt : Flag<["-"], "mno-movt">, Group<m_arm_Features_Group>, HelpText<"Disallow use of movt/movw pairs (ARM only)">; -def mcrc : Flag<["-"], "mcrc">, Group<m_arm_Features_Group>, - HelpText<"Allow use of CRC instructions (ARM only)">; +def mcrc : Flag<["-"], "mcrc">, Group<m_Group>, + HelpText<"Allow use of CRC instructions (ARM/Mips only)">; def mnocrc : Flag<["-"], "mnocrc">, Group<m_arm_Features_Group>, HelpText<"Disallow use of CRC instructions (ARM only)">; def mno_neg_immediates: Flag<["-"], "mno-neg-immediates">, Group<m_arm_Features_Group>, @@ -1862,11 +2031,17 @@ def mno_fix_cortex_a53_835769 : Flag<["-"], "mno-fix-cortex-a53-835769">, HelpText<"Don't workaround Cortex-A53 erratum 835769 (AArch64 only)">; def ffixed_x18 : Flag<["-"], "ffixed-x18">, Group<m_aarch64_Features_Group>, HelpText<"Reserve the x18 register (AArch64 only)">; +def ffixed_x20 : Flag<["-"], "ffixed-x20">, Group<m_aarch64_Features_Group>, + HelpText<"Reserve the x20 register (AArch64 only)">; def msimd128 : Flag<["-"], "msimd128">, Group<m_wasm_Features_Group>; def mno_simd128 : Flag<["-"], "mno-simd128">, Group<m_wasm_Features_Group>; def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group<m_wasm_Features_Group>; def mno_nontrapping_fptoint : Flag<["-"], "mno-nontrapping-fptoint">, Group<m_wasm_Features_Group>; +def msign_ext : Flag<["-"], "msign-ext">, Group<m_wasm_Features_Group>; +def mno_sign_ext : Flag<["-"], "mno-sign-ext">, Group<m_wasm_Features_Group>; +def mexception_handing : Flag<["-"], "mexception-handling">, Group<m_wasm_Features_Group>; +def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group<m_wasm_Features_Group>; def mamdgpu_debugger_abi : Joined<["-"], "mamdgpu-debugger-abi=">, Flags<[HelpHidden]>, @@ -1884,6 +2059,7 @@ def maltivec : Flag<["-"], "maltivec">, Group<m_ppc_Features_Group>; def mno_altivec : Flag<["-"], "mno-altivec">, Group<m_ppc_Features_Group>; def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>; def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>; +def msecure_plt : Flag<["-"], "msecure-plt">, Group<m_ppc_Features_Group>; def mpower8_vector : Flag<["-"], "mpower8-vector">, Group<m_ppc_Features_Group>; def mno_power8_vector : Flag<["-"], "mno-power8-vector">, @@ -1980,124 +2156,141 @@ def mpie_copy_relocations : Flag<["-"], "mpie-copy-relocations">, Group<m_Group> def mno_pie_copy_relocations : Flag<["-"], "mno-pie-copy-relocations">, Group<m_Group>; def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86 only)">, Flags<[CC1Option]>, Group<m_Group>; -def mips16 : Flag<["-"], "mips16">, Group<m_Group>; -def mno_mips16 : Flag<["-"], "mno-mips16">, Group<m_Group>; -def mmicromips : Flag<["-"], "mmicromips">, Group<m_Group>; -def mno_micromips : Flag<["-"], "mno-micromips">, Group<m_Group>; -def mxgot : Flag<["-"], "mxgot">, Group<m_Group>; -def mno_xgot : Flag<["-"], "mno-xgot">, Group<m_Group>; -def mldc1_sdc1 : Flag<["-"], "mldc1-sdc1">, Group<m_Group>; -def mno_ldc1_sdc1 : Flag<["-"], "mno-ldc1-sdc1">, Group<m_Group>; -def mcheck_zero_division : Flag<["-"], "mcheck-zero-division">, Group<m_Group>; +def mips16 : Flag<["-"], "mips16">, Group<m_mips_Features_Group>; +def mno_mips16 : Flag<["-"], "mno-mips16">, Group<m_mips_Features_Group>; +def mmicromips : Flag<["-"], "mmicromips">, Group<m_mips_Features_Group>; +def mno_micromips : Flag<["-"], "mno-micromips">, Group<m_mips_Features_Group>; +def mxgot : Flag<["-"], "mxgot">, Group<m_mips_Features_Group>; +def mno_xgot : Flag<["-"], "mno-xgot">, Group<m_mips_Features_Group>; +def mldc1_sdc1 : Flag<["-"], "mldc1-sdc1">, Group<m_mips_Features_Group>; +def mno_ldc1_sdc1 : Flag<["-"], "mno-ldc1-sdc1">, Group<m_mips_Features_Group>; +def mcheck_zero_division : Flag<["-"], "mcheck-zero-division">, + Group<m_mips_Features_Group>; def mno_check_zero_division : Flag<["-"], "mno-check-zero-division">, - Group<m_Group>; -def mcompact_branches_EQ : Joined<["-"], "mcompact-branches=">, Group<m_Group>; + Group<m_mips_Features_Group>; +def mcompact_branches_EQ : Joined<["-"], "mcompact-branches=">, + Group<m_mips_Features_Group>; def mbranch_likely : Flag<["-"], "mbranch-likely">, Group<m_Group>, IgnoredGCCCompat; def mno_branch_likely : Flag<["-"], "mno-branch-likely">, Group<m_Group>, IgnoredGCCCompat; -def mdsp : Flag<["-"], "mdsp">, Group<m_Group>; -def mno_dsp : Flag<["-"], "mno-dsp">, Group<m_Group>; -def mdspr2 : Flag<["-"], "mdspr2">, Group<m_Group>; -def mno_dspr2 : Flag<["-"], "mno-dspr2">, Group<m_Group>; -def msingle_float : Flag<["-"], "msingle-float">, Group<m_Group>; -def mdouble_float : Flag<["-"], "mdouble-float">, Group<m_Group>; -def mmadd4 : Flag<["-"], "mmadd4">, Group<m_Group>, +def mindirect_jump_EQ : Joined<["-"], "mindirect-jump=">, + Group<m_mips_Features_Group>, + HelpText<"Change indirect jump instructions to inhibit speculation">; +def mdsp : Flag<["-"], "mdsp">, Group<m_mips_Features_Group>; +def mno_dsp : Flag<["-"], "mno-dsp">, Group<m_mips_Features_Group>; +def mdspr2 : Flag<["-"], "mdspr2">, Group<m_mips_Features_Group>; +def mno_dspr2 : Flag<["-"], "mno-dspr2">, Group<m_mips_Features_Group>; +def msingle_float : Flag<["-"], "msingle-float">, Group<m_mips_Features_Group>; +def mdouble_float : Flag<["-"], "mdouble-float">, Group<m_mips_Features_Group>; +def mmadd4 : Flag<["-"], "mmadd4">, Group<m_mips_Features_Group>, HelpText<"Enable the generation of 4-operand madd.s, madd.d and related instructions.">; -def mno_madd4 : Flag<["-"], "mno-madd4">, Group<m_Group>, +def mno_madd4 : Flag<["-"], "mno-madd4">, Group<m_mips_Features_Group>, HelpText<"Disable the generation of 4-operand madd.s, madd.d and related instructions.">; -def mmsa : Flag<["-"], "mmsa">, Group<m_Group>, +def mmsa : Flag<["-"], "mmsa">, Group<m_mips_Features_Group>, HelpText<"Enable MSA ASE (MIPS only)">; -def mno_msa : Flag<["-"], "mno-msa">, Group<m_Group>, +def mno_msa : Flag<["-"], "mno-msa">, Group<m_mips_Features_Group>, HelpText<"Disable MSA ASE (MIPS only)">; -def mmt : Flag<["-"], "mmt">, Group<m_Group>, +def mmt : Flag<["-"], "mmt">, Group<m_mips_Features_Group>, HelpText<"Enable MT ASE (MIPS only)">; -def mno_mt : Flag<["-"], "mno-mt">, Group<m_Group>, +def mno_mt : Flag<["-"], "mno-mt">, Group<m_mips_Features_Group>, HelpText<"Disable MT ASE (MIPS only)">; -def mfp64 : Flag<["-"], "mfp64">, Group<m_Group>, +def mfp64 : Flag<["-"], "mfp64">, Group<m_mips_Features_Group>, HelpText<"Use 64-bit floating point registers (MIPS only)">; -def mfp32 : Flag<["-"], "mfp32">, Group<m_Group>, +def mfp32 : Flag<["-"], "mfp32">, Group<m_mips_Features_Group>, HelpText<"Use 32-bit floating point registers (MIPS only)">; -def mgpopt : Flag<["-"], "mgpopt">, Group<m_Group>, +def mgpopt : Flag<["-"], "mgpopt">, Group<m_mips_Features_Group>, HelpText<"Use GP relative accesses for symbols known to be in a small" " data section (MIPS)">; -def mno_gpopt : Flag<["-"], "mno-gpopt">, Group<m_Group>, +def mno_gpopt : Flag<["-"], "mno-gpopt">, Group<m_mips_Features_Group>, HelpText<"Do not use GP relative accesses for symbols known to be in a small" " data section (MIPS)">; -def mlocal_sdata : Flag<["-"], "mlocal-sdata">, Group<m_Group>, +def mlocal_sdata : Flag<["-"], "mlocal-sdata">, + Group<m_mips_Features_Group>, HelpText<"Extend the -G behaviour to object local data (MIPS)">; -def mno_local_sdata : Flag<["-"], "mno-local-sdata">, Group<m_Group>, +def mno_local_sdata : Flag<["-"], "mno-local-sdata">, + Group<m_mips_Features_Group>, HelpText<"Do not extend the -G behaviour to object local data (MIPS)">; -def mextern_sdata : Flag<["-"], "mextern-sdata">, Group<m_Group>, +def mextern_sdata : Flag<["-"], "mextern-sdata">, + Group<m_mips_Features_Group>, HelpText<"Assume that externally defined data is in the small data if it" " meets the -G <size> threshold (MIPS)">; -def mno_extern_sdata : Flag<["-"], "mno-extern-sdata">, Group<m_Group>, +def mno_extern_sdata : Flag<["-"], "mno-extern-sdata">, + Group<m_mips_Features_Group>, HelpText<"Do not assume that externally defined data is in the small data if" " it meets the -G <size> threshold (MIPS)">; -def membedded_data : Flag<["-"], "membedded-data">, Group<m_Group>, +def membedded_data : Flag<["-"], "membedded-data">, + Group<m_mips_Features_Group>, HelpText<"Place constants in the .rodata section instead of the .sdata " "section even if they meet the -G <size> threshold (MIPS)">; -def mno_embedded_data : Flag<["-"], "mno-embedded-data">, Group<m_Group>, +def mno_embedded_data : Flag<["-"], "mno-embedded-data">, + Group<m_mips_Features_Group>, HelpText<"Do not place constants in the .rodata section instead of the " ".sdata if they meet the -G <size> threshold (MIPS)">; -def mnan_EQ : Joined<["-"], "mnan=">, Group<m_Group>; -def mabs_EQ : Joined<["-"], "mabs=">, Group<m_Group>; -def mabicalls : Flag<["-"], "mabicalls">, Group<m_Group>, +def mnan_EQ : Joined<["-"], "mnan=">, Group<m_mips_Features_Group>; +def mabs_EQ : Joined<["-"], "mabs=">, Group<m_mips_Features_Group>; +def mabicalls : Flag<["-"], "mabicalls">, Group<m_mips_Features_Group>, HelpText<"Enable SVR4-style position-independent code (Mips only)">; -def mno_abicalls : Flag<["-"], "mno-abicalls">, Group<m_Group>, +def mno_abicalls : Flag<["-"], "mno-abicalls">, Group<m_mips_Features_Group>, HelpText<"Disable SVR4-style position-independent code (Mips only)">; +def mno_crc : Flag<["-"], "mno-crc">, Group<m_mips_Features_Group>, + HelpText<"Disallow use of CRC instructions (Mips only)">; +def mvirt : Flag<["-"], "mvirt">, Group<m_mips_Features_Group>; +def mno_virt : Flag<["-"], "mno-virt">, Group<m_mips_Features_Group>; +def mginv : Flag<["-"], "mginv">, Group<m_mips_Features_Group>; +def mno_ginv : Flag<["-"], "mno-ginv">, Group<m_mips_Features_Group>; def mips1 : Flag<["-"], "mips1">, - Alias<march_EQ>, AliasArgs<["mips1"]>, + Alias<march_EQ>, AliasArgs<["mips1"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips1">, Flags<[HelpHidden]>; def mips2 : Flag<["-"], "mips2">, - Alias<march_EQ>, AliasArgs<["mips2"]>, + Alias<march_EQ>, AliasArgs<["mips2"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips2">, Flags<[HelpHidden]>; def mips3 : Flag<["-"], "mips3">, - Alias<march_EQ>, AliasArgs<["mips3"]>, + Alias<march_EQ>, AliasArgs<["mips3"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips3">, Flags<[HelpHidden]>; def mips4 : Flag<["-"], "mips4">, - Alias<march_EQ>, AliasArgs<["mips4"]>, + Alias<march_EQ>, AliasArgs<["mips4"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips4">, Flags<[HelpHidden]>; def mips5 : Flag<["-"], "mips5">, - Alias<march_EQ>, AliasArgs<["mips5"]>, + Alias<march_EQ>, AliasArgs<["mips5"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips5">, Flags<[HelpHidden]>; def mips32 : Flag<["-"], "mips32">, - Alias<march_EQ>, AliasArgs<["mips32"]>, + Alias<march_EQ>, AliasArgs<["mips32"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips32">, Flags<[HelpHidden]>; def mips32r2 : Flag<["-"], "mips32r2">, - Alias<march_EQ>, AliasArgs<["mips32r2"]>, + Alias<march_EQ>, AliasArgs<["mips32r2"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips32r2">, Flags<[HelpHidden]>; def mips32r3 : Flag<["-"], "mips32r3">, - Alias<march_EQ>, AliasArgs<["mips32r3"]>, + Alias<march_EQ>, AliasArgs<["mips32r3"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips32r3">, Flags<[HelpHidden]>; def mips32r5 : Flag<["-"], "mips32r5">, - Alias<march_EQ>, AliasArgs<["mips32r5"]>, + Alias<march_EQ>, AliasArgs<["mips32r5"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips32r5">, Flags<[HelpHidden]>; def mips32r6 : Flag<["-"], "mips32r6">, - Alias<march_EQ>, AliasArgs<["mips32r6"]>, + Alias<march_EQ>, AliasArgs<["mips32r6"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips32r6">, Flags<[HelpHidden]>; def mips64 : Flag<["-"], "mips64">, - Alias<march_EQ>, AliasArgs<["mips64"]>, + Alias<march_EQ>, AliasArgs<["mips64"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips64">, Flags<[HelpHidden]>; def mips64r2 : Flag<["-"], "mips64r2">, - Alias<march_EQ>, AliasArgs<["mips64r2"]>, + Alias<march_EQ>, AliasArgs<["mips64r2"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips64r2">, Flags<[HelpHidden]>; def mips64r3 : Flag<["-"], "mips64r3">, - Alias<march_EQ>, AliasArgs<["mips64r3"]>, + Alias<march_EQ>, AliasArgs<["mips64r3"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips64r3">, Flags<[HelpHidden]>; def mips64r5 : Flag<["-"], "mips64r5">, - Alias<march_EQ>, AliasArgs<["mips64r5"]>, + Alias<march_EQ>, AliasArgs<["mips64r5"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips64r5">, Flags<[HelpHidden]>; def mips64r6 : Flag<["-"], "mips64r6">, - Alias<march_EQ>, AliasArgs<["mips64r6"]>, + Alias<march_EQ>, AliasArgs<["mips64r6"]>, Group<m_mips_Features_Group>, HelpText<"Equivalent to -march=mips64r6">, Flags<[HelpHidden]>; -def mfpxx : Flag<["-"], "mfpxx">, Group<m_Group>, +def mfpxx : Flag<["-"], "mfpxx">, Group<m_mips_Features_Group>, HelpText<"Avoid FPU mode dependent operations when used with the O32 ABI">, Flags<[HelpHidden]>; -def modd_spreg : Flag<["-"], "modd-spreg">, Group<m_Group>, +def modd_spreg : Flag<["-"], "modd-spreg">, Group<m_mips_Features_Group>, HelpText<"Enable odd single-precision floating point registers">, Flags<[HelpHidden]>; -def mno_odd_spreg : Flag<["-"], "mno-odd-spreg">, Group<m_Group>, +def mno_odd_spreg : Flag<["-"], "mno-odd-spreg">, Group<m_mips_Features_Group>, HelpText<"Disable odd single-precision floating point registers">, Flags<[HelpHidden]>; def mglibc : Flag<["-"], "mglibc">, Group<m_libc_Group>, Flags<[HelpHidden]>; @@ -2110,7 +2303,7 @@ def multi__module : Flag<["-"], "multi_module">; def multiply__defined__unused : Separate<["-"], "multiply_defined_unused">; def multiply__defined : Separate<["-"], "multiply_defined">; def mwarn_nonportable_cfstrings : Flag<["-"], "mwarn-nonportable-cfstrings">, Group<m_Group>; -def no_canonical_prefixes : Flag<["-"], "no-canonical-prefixes">, Flags<[HelpHidden]>, +def no_canonical_prefixes : Flag<["-"], "no-canonical-prefixes">, Flags<[HelpHidden, CoreOption]>, HelpText<"Use relative instead of canonical paths">; def no_cpp_precomp : Flag<["-"], "no-cpp-precomp">, Group<clang_ignored_f_Group>; def no_integrated_cpp : Flag<["-", "--"], "no-integrated-cpp">, Flags<[DriverOption]>; @@ -2193,7 +2386,7 @@ def fno_rtlib_add_rpath: Flag<["-"], "fno-rtlib-add-rpath">, Flags<[NoArgumentUn HelpText<"Do not add -rpath with architecture-specific resource directory to the linker flags">; def r : Flag<["-"], "r">, Flags<[LinkerInput,NoArgumentUnused]>, Group<Link_Group>; -def save_temps_EQ : Joined<["-", "--"], "save-temps=">, Flags<[DriverOption]>, +def save_temps_EQ : Joined<["-", "--"], "save-temps=">, Flags<[CC1Option, DriverOption]>, HelpText<"Save intermediate compilation results.">; def save_temps : Flag<["-", "--"], "save-temps">, Flags<[DriverOption]>, Alias<save_temps_EQ>, AliasArgs<["cwd"]>, @@ -2344,7 +2537,8 @@ def _for_linker_EQ : Joined<["--"], "for-linker=">, Alias<Xlinker>; def _for_linker : Separate<["--"], "for-linker">, Alias<Xlinker>; def _force_link_EQ : Joined<["--"], "force-link=">, Alias<u>; def _force_link : Separate<["--"], "force-link">, Alias<u>; -def _help_hidden : Flag<["--"], "help-hidden">; +def _help_hidden : Flag<["--"], "help-hidden">, + HelpText<"Display help for hidden options">; def _imacros_EQ : Joined<["--"], "imacros=">, Alias<imacros>; def _include_barrier : Flag<["--"], "include-barrier">, Alias<I_>; def _include_directory_after_EQ : Joined<["--"], "include-directory-after=">, Alias<idirafter>; @@ -2414,39 +2608,50 @@ def _write_dependencies : Flag<["--"], "write-dependencies">, Alias<MD>; def _write_user_dependencies : Flag<["--"], "write-user-dependencies">, Alias<MMD>; def _ : Joined<["--"], "">, Flags<[Unsupported]>; -def mieee_rnd_near : Flag<["-"], "mieee-rnd-near">, Group<m_hexagon_Features_Group>; +// Hexagon feature flags. +def mieee_rnd_near : Flag<["-"], "mieee-rnd-near">, + Group<m_hexagon_Features_Group>; def mv4 : Flag<["-"], "mv4">, Group<m_hexagon_Features_Group>, - Alias<mcpu_EQ>, AliasArgs<["hexagonv4"]>; + Alias<mcpu_EQ>, AliasArgs<["hexagonv4"]>; def mv5 : Flag<["-"], "mv5">, Group<m_hexagon_Features_Group>, Alias<mcpu_EQ>, - AliasArgs<["hexagonv5"]>; + AliasArgs<["hexagonv5"]>; def mv55 : Flag<["-"], "mv55">, Group<m_hexagon_Features_Group>, - Alias<mcpu_EQ>, AliasArgs<["hexagonv55"]>; + Alias<mcpu_EQ>, AliasArgs<["hexagonv55"]>; def mv60 : Flag<["-"], "mv60">, Group<m_hexagon_Features_Group>, - Alias<mcpu_EQ>, AliasArgs<["hexagonv60"]>; + Alias<mcpu_EQ>, AliasArgs<["hexagonv60"]>; def mv62 : Flag<["-"], "mv62">, Group<m_hexagon_Features_Group>, - Alias<mcpu_EQ>, AliasArgs<["hexagonv62"]>; + Alias<mcpu_EQ>, AliasArgs<["hexagonv62"]>; def mv65 : Flag<["-"], "mv65">, Group<m_hexagon_Features_Group>, - Alias<mcpu_EQ>, AliasArgs<["hexagonv65"]>; -def mhexagon_hvx : Flag<[ "-" ], "mhvx">, - Group<m_hexagon_Features_HVX_Group>, - HelpText<"Enable Hexagon Vector eXtensions">; -def mhexagon_hvx_EQ : Joined<[ "-" ], "mhvx=">, - Group<m_hexagon_Features_HVX_Group>, - HelpText<"Enable Hexagon Vector eXtensions">; -def mno_hexagon_hvx : Flag<[ "-" ], "mno-hvx">, - Group<m_hexagon_Features_HVX_Group>, - HelpText<"Disable Hexagon Vector eXtensions">; -def mhexagon_hvx_length_EQ : Joined<[ "-" ], "mhvx-length=">, - Group<m_hexagon_Features_HVX_Group>, - HelpText<"Set Hexagon Vector Length">, Values<"64B,128B">; -// hvx-double deprecrated flag. -def mhexagon_hvx_double : Flag<[ "-" ], "mhvx-double">, - Group<m_hexagon_Features_HVX_Group>, - HelpText<"Enable Hexagon Double Vector eXtensions">; -def mno_hexagon_hvx_double - : Flag<[ "-" ], "mno-hvx-double">, - Group<m_hexagon_Features_HVX_Group>, - HelpText<"Disable Hexagon Double Vector eXtensions">; + Alias<mcpu_EQ>, AliasArgs<["hexagonv65"]>; +def mhexagon_hvx : Flag<["-"], "mhvx">, Group<m_hexagon_Features_HVX_Group>, + HelpText<"Enable Hexagon Vector eXtensions">; +def mhexagon_hvx_EQ : Joined<["-"], "mhvx=">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Enable Hexagon Vector eXtensions">; +def mno_hexagon_hvx : Flag<["-"], "mno-hvx">, + Group<m_hexagon_Features_HVX_Group>, + HelpText<"Disable Hexagon Vector eXtensions">; +def mhexagon_hvx_length_EQ : Joined<["-"], "mhvx-length=">, + Group<m_hexagon_Features_HVX_Group>, HelpText<"Set Hexagon Vector Length">, + Values<"64B,128B">; +def ffixed_r19: Flag<["-"], "ffixed-r19">, + HelpText<"Reserve register r19 (Hexagon only)">; +def mmemops : Flag<["-"], "mmemops">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Enable generation of memop instructions">; +def mno_memops : Flag<["-"], "mno-memops">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Disable generation of memop instructions">; +def mpackets : Flag<["-"], "mpackets">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Enable generation of instruction packets">; +def mno_packets : Flag<["-"], "mno-packets">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Disable generation of instruction packets">; +def mnvj : Flag<["-"], "mnvj">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Enable generation of new-value jumps">; +def mno_nvj : Flag<["-"], "mno-nvj">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Disable generation of new-value jumps">; +def mnvs : Flag<["-"], "mnvs">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Enable generation of new-value stores">; +def mno_nvs : Flag<["-"], "mno-nvs">, Group<m_hexagon_Features_Group>, + Flags<[CC1Option]>, HelpText<"Disable generation of new-value stores">; // X86 feature flags @@ -2517,10 +2722,14 @@ def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>; def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>; def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>; def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>; +def mcldemote : Flag<["-"], "mcldemote">, Group<m_x86_Features_Group>; +def mno_cldemote : Flag<["-"], "mno-cldemote">, Group<m_x86_Features_Group>; def mclflushopt : Flag<["-"], "mclflushopt">, Group<m_x86_Features_Group>; def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group<m_x86_Features_Group>; def mclwb : Flag<["-"], "mclwb">, Group<m_x86_Features_Group>; def mno_clwb : Flag<["-"], "mno-clwb">, Group<m_x86_Features_Group>; +def mwbnoinvd : Flag<["-"], "mwbnoinvd">, Group<m_x86_Features_Group>; +def mno_wbnoinvd : Flag<["-"], "mno-wbnoinvd">, Group<m_x86_Features_Group>; def mclzero : Flag<["-"], "mclzero">, Group<m_x86_Features_Group>; def mno_clzero : Flag<["-"], "mno-clzero">, Group<m_x86_Features_Group>; def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>; @@ -2535,6 +2744,8 @@ def mfsgsbase : Flag<["-"], "mfsgsbase">, Group<m_x86_Features_Group>; def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group<m_x86_Features_Group>; def mfxsr : Flag<["-"], "mfxsr">, Group<m_x86_Features_Group>; def mno_fxsr : Flag<["-"], "mno-fxsr">, Group<m_x86_Features_Group>; +def minvpcid : Flag<["-"], "minvpcid">, Group<m_x86_Features_Group>; +def mno_invpcid : Flag<["-"], "mno-invpcid">, Group<m_x86_Features_Group>; def mgfni : Flag<["-"], "mgfni">, Group<m_x86_Features_Group>; def mno_gfni : Flag<["-"], "mno-gfni">, Group<m_x86_Features_Group>; def mlwp : Flag<["-"], "mlwp">, Group<m_x86_Features_Group>; @@ -2543,6 +2754,10 @@ def mlzcnt : Flag<["-"], "mlzcnt">, Group<m_x86_Features_Group>; def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group<m_x86_Features_Group>; def mmovbe : Flag<["-"], "mmovbe">, Group<m_x86_Features_Group>; def mno_movbe : Flag<["-"], "mno-movbe">, Group<m_x86_Features_Group>; +def mmovdiri : Flag<["-"], "mmovdiri">, Group<m_x86_Features_Group>; +def mno_movdiri : Flag<["-"], "mno-movdiri">, Group<m_x86_Features_Group>; +def mmovdir64b : Flag<["-"], "mmovdir64b">, Group<m_x86_Features_Group>; +def mno_movdir64b : Flag<["-"], "mno-movdir64b">, Group<m_x86_Features_Group>; def mmpx : Flag<["-"], "mmpx">, Group<m_x86_Features_Group>; def mno_mpx : Flag<["-"], "mno-mpx">, Group<m_x86_Features_Group>; def mmwaitx : Flag<["-"], "mmwaitx">, Group<m_x86_Features_Group>; @@ -2551,18 +2766,26 @@ def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>; def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>; def mpclmul : Flag<["-"], "mpclmul">, Group<m_x86_Features_Group>; def mno_pclmul : Flag<["-"], "mno-pclmul">, Group<m_x86_Features_Group>; +def mpconfig : Flag<["-"], "mpconfig">, Group<m_x86_Features_Group>; +def mno_pconfig : Flag<["-"], "mno-pconfig">, Group<m_x86_Features_Group>; def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>; def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>; def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group<m_x86_Features_Group>; def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group<m_x86_Features_Group>; def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>; def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>; +def mptwrite : Flag<["-"], "mptwrite">, Group<m_x86_Features_Group>; +def mno_ptwrite : Flag<["-"], "mno-ptwrite">, Group<m_x86_Features_Group>; +def mrdpid : Flag<["-"], "mrdpid">, Group<m_x86_Features_Group>; +def mno_rdpid : Flag<["-"], "mno-rdpid">, Group<m_x86_Features_Group>; def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>; def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>; def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>; def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>; def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>; def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>; +def msahf : Flag<["-"], "msahf">, Group<m_x86_Features_Group>; +def mno_sahf : Flag<["-"], "mno-sahf">, Group<m_x86_Features_Group>; def msgx : Flag<["-"], "msgx">, Group<m_x86_Features_Group>; def mno_sgx : Flag<["-"], "mno-sgx">, Group<m_x86_Features_Group>; def msha : Flag<["-"], "msha">, Group<m_x86_Features_Group>; @@ -2573,6 +2796,8 @@ def mvaes : Flag<["-"], "mvaes">, Group<m_x86_Features_Group>; def mno_vaes : Flag<["-"], "mno-vaes">, Group<m_x86_Features_Group>; def mvpclmulqdq : Flag<["-"], "mvpclmulqdq">, Group<m_x86_Features_Group>; def mno_vpclmulqdq : Flag<["-"], "mno-vpclmulqdq">, Group<m_x86_Features_Group>; +def mwaitpkg : Flag<["-"], "mwaitpkg">, Group<m_x86_Features_Group>; +def mno_waitpkg : Flag<["-"], "mno-waitpkg">, Group<m_x86_Features_Group>; def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>; def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>; def mxsave : Flag<["-"], "mxsave">, Group<m_x86_Features_Group>; @@ -2585,8 +2810,6 @@ def mxsaves : Flag<["-"], "mxsaves">, Group<m_x86_Features_Group>; def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>; def mshstk : Flag<["-"], "mshstk">, Group<m_x86_Features_Group>; def mno_shstk : Flag<["-"], "mno-shstk">, Group<m_x86_Features_Group>; -def mibt : Flag<["-"], "mibt">, Group<m_x86_Features_Group>; -def mno_ibt : Flag<["-"], "mno-ibt">, Group<m_x86_Features_Group>; def mretpoline : Flag<["-"], "mretpoline">, Group<m_x86_Features_Group>; def mno_retpoline : Flag<["-"], "mno-retpoline">, Group<m_x86_Features_Group>; def mretpoline_external_thunk : Flag<["-"], "mretpoline-external-thunk">, Group<m_x86_Features_Group>; @@ -2626,8 +2849,6 @@ def fprofile_dir : Joined<["-"], "fprofile-dir=">, Group<f_Group>; def fuse_ld_EQ : Joined<["-"], "fuse-ld=">, Group<f_Group>, Flags<[CoreOption]>; -defm align_functions : BooleanFFlag<"align-functions">, Group<clang_ignored_gcc_optimization_f_Group>; -def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group<clang_ignored_gcc_optimization_f_Group>; defm align_labels : BooleanFFlag<"align-labels">, Group<clang_ignored_gcc_optimization_f_Group>; def falign_labels_EQ : Joined<["-"], "falign-labels=">, Group<clang_ignored_gcc_optimization_f_Group>; defm align_loops : BooleanFFlag<"align-loops">, Group<clang_ignored_gcc_optimization_f_Group>; @@ -2645,8 +2866,6 @@ defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group<clang_ignored_gcc_op defm eliminate_unused_debug_types : BooleanFFlag<"eliminate-unused-debug-types">, Group<clang_ignored_f_Group>; defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group<clang_ignored_gcc_optimization_f_Group>; defm default_inline : BooleanFFlag<"default-inline">, Group<clang_ignored_gcc_optimization_f_Group>; -defm delete_null_pointer_checks : BooleanFFlag<"delete-null-pointer-checks">, - Group<clang_ignored_gcc_optimization_f_Group>; defm fat_lto_objects : BooleanFFlag<"fat-lto-objects">, Group<clang_ignored_gcc_optimization_f_Group>; defm float_store : BooleanFFlag<"float-store">, Group<clang_ignored_gcc_optimization_f_Group>; defm friend_injection : BooleanFFlag<"friend-injection">, Group<clang_ignored_f_Group>; @@ -2656,7 +2875,6 @@ defm gcse_after_reload: BooleanFFlag<"gcse-after-reload">, Group<clang_ignored_g defm gcse_las: BooleanFFlag<"gcse-las">, Group<clang_ignored_gcc_optimization_f_Group>; defm gcse_sm: BooleanFFlag<"gcse-sm">, Group<clang_ignored_gcc_optimization_f_Group>; defm gnu : BooleanFFlag<"gnu">, Group<clang_ignored_f_Group>; -defm ident : BooleanFFlag<"ident">, Group<clang_ignored_f_Group>; defm implicit_templates : BooleanFFlag<"implicit-templates">, Group<clang_ignored_f_Group>; defm implement_inlines : BooleanFFlag<"implement-inlines">, Group<clang_ignored_f_Group>; defm merge_constants : BooleanFFlag<"merge-constants">, Group<clang_ignored_gcc_optimization_f_Group>; diff --git a/gnu/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def b/gnu/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def index 5c4b4c3aa84..9afc0a8c913 100644 --- a/gnu/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def +++ b/gnu/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def @@ -38,10 +38,12 @@ CODEGENOPT(AssumeSaneOperatorNew , 1, 1) ///< implicit __attribute__((malloc)) o CODEGENOPT(Autolink , 1, 1) ///< -fno-autolink CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe. CODEGENOPT(Backchain , 1, 0) ///< -mbackchain +CODEGENOPT(ControlFlowGuard , 1, 0) ///< -cfguard CODEGENOPT(CoverageExtraChecksum, 1, 0) ///< Whether we need a second checksum for functions in GCNO files. CODEGENOPT(CoverageNoFunctionNamesInData, 1, 0) ///< Do not include function names in GCDA files. CODEGENOPT(CoverageExitBlockBeforeBody, 1, 0) ///< Whether to emit the exit block before the body blocks in GCNO files. CODEGENOPT(CXAAtExit , 1, 1) ///< Use __cxa_atexit for calling destructors. +CODEGENOPT(RegisterGlobalDtorsWithAtExit, 1, 1) ///< Use atexit or __cxa_atexit to register global destructors. CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker ///< aliases to base ctors when possible. CODEGENOPT(DataSections , 1, 0) ///< Set when -fdata-sections is enabled. @@ -61,15 +63,19 @@ CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new ///< pass manager. CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled. CODEGENOPT(DisableTailCalls , 1, 0) ///< Do not emit tail calls. +CODEGENOPT(NoEscapingBlockTailCalls, 1, 0) ///< Do not emit tail calls from + ///< escaping blocks. CODEGENOPT(EmitDeclMetadata , 1, 0) ///< Emit special metadata indicating what ///< Decl* various IR entities came from. ///< Only useful when running CodeGen as a ///< subroutine. +CODEGENOPT(EmitVersionIdentMetadata , 1, 1) ///< Emit compiler version metadata. CODEGENOPT(EmitGcovArcs , 1, 0) ///< Emit coverage data files, aka. GCDA. CODEGENOPT(EmitGcovNotes , 1, 0) ///< Emit coverage "notes" files, aka GCNO. CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata. -CODEGENOPT(EmulatedTLS , 1, 0) ///< Set when -femulated-tls is enabled. -/// \brief Embed Bitcode mode (off/all/bitcode/marker). +CODEGENOPT(EmulatedTLS , 1, 0) ///< Set by default or -f[no-]emulated-tls. +CODEGENOPT(ExplicitEmulatedTLS , 1, 0) ///< Set if -f[no-]emulated-tls is used. +/// Embed Bitcode mode (off/all/bitcode/marker). ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off) CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables ///< are required. @@ -80,13 +86,20 @@ CODEGENOPT(InstrumentFunctionsAfterInlining , 1, 0) ///< Set when ///< -finstrument-functions-after-inlining is enabled. CODEGENOPT(InstrumentFunctionEntryBare , 1, 0) ///< Set when ///< -finstrument-function-entry-bare is enabled. - +CODEGENOPT(CFProtectionReturn , 1, 0) ///< if -fcf-protection is + ///< set to full or return. +CODEGENOPT(CFProtectionBranch , 1, 0) ///< if -fcf-protection is + ///< set to full or branch. CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is ///< enabled. +CODEGENOPT(StackSizeSection , 1, 0) ///< Set when -fstack-size-section is enabled. ///< Set when -fxray-always-emit-customevents is enabled. CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0) +///< Set when -fxray-always-emit-typedevents is enabled. +CODEGENOPT(XRayAlwaysEmitTypedEvents , 1, 0) + ///< Set the minimum number of instructions in a function to determine selective ///< XRay instrumentation. VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200) @@ -97,7 +110,7 @@ CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions t ///< be generated. CODEGENOPT(PrepareForLTO , 1, 0) ///< Set when -flto is enabled on the ///< compile step. -CODEGENOPT(EmitSummaryIndex, 1, 0) ///< Set when -flto=thin is enabled on the +CODEGENOPT(PrepareForThinLTO , 1, 0) ///< Set when -flto=thin is enabled on the ///< compile step. CODEGENOPT(LTOUnit, 1, 0) ///< Emit IR to support LTO unit features (CFI, whole ///< program vtable opt). @@ -117,27 +130,32 @@ CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled. CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled. CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf. CODEGENOPT(NoSignedZeros , 1, 0) ///< Allow ignoring the signedness of FP zero +CODEGENOPT(NullPointerIsValid , 1, 0) ///< Assume Null pointer deference is defined. CODEGENOPT(Reassociate , 1, 0) ///< Allow reassociation of FP math ops CODEGENOPT(ReciprocalMath , 1, 0) ///< Allow FP divisions to be reassociated. CODEGENOPT(NoTrappingMath , 1, 0) ///< Set when -fno-trapping-math is enabled. CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN. CODEGENOPT(FlushDenorm , 1, 0) ///< Allow FP denorm numbers to be flushed to zero CODEGENOPT(CorrectlyRoundedDivSqrt, 1, 0) ///< -cl-fp32-correctly-rounded-divide-sqrt + +/// When false, this attempts to generate code as if the result of an +/// overflowing conversion matches the overflowing behavior of a target's native +/// float-to-int conversion instructions. +CODEGENOPT(StrictFloatCastOverflow, 1, 1) + +CODEGENOPT(UniformWGSize , 1, 0) ///< -cl-uniform-work-group-size CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss. -/// \brief Method of Objective-C dispatch to use. +/// Method of Objective-C dispatch to use. ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy) CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is ///< enabled. -/// A version of Clang that we should attempt to be ABI-compatible with. -ENUM_CODEGENOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest) - VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified. VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. -/// \brief Choose profile instrumenation kind or no instrumentation. +/// Choose profile instrumenation kind or no instrumentation. ENUM_CODEGENOPT(ProfileInstr, ProfileInstrKind, 2, ProfileNone) -/// \brief Choose profile kind for PGO use compilation. +/// Choose profile kind for PGO use compilation. ENUM_CODEGENOPT(ProfileUse, ProfileInstrKind, 2, ProfileNone) CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to ///< enable code coverage analysis. @@ -154,6 +172,9 @@ CODEGENOPT(NewStructPathTBAA , 1, 0) ///< Whether or not to use enhanced struct- CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels. CODEGENOPT(SanitizeAddressUseAfterScope , 1, 0) ///< Enable use-after-scope detection ///< in AddressSanitizer +CODEGENOPT(SanitizeAddressPoisonClassMemberArrayNewCookie, 1, + 0) ///< Enable poisoning operator new[] which is not a replaceable + ///< global allocation function in AddressSanitizer CODEGENOPT(SanitizeAddressGlobalsDeadStripping, 1, 0) ///< Enable linker dead stripping ///< of globals in AddressSanitizer CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in @@ -218,6 +239,7 @@ VALUE_CODEGENOPT(StackAlignment , 32, 0) ///< Overrides default stack ///< alignment, if not 0. VALUE_CODEGENOPT(StackProbeSize , 32, 4096) ///< Overrides default stack ///< probe size, even if 0. +CODEGENOPT(NoStackArgProbe, 1, 0) ///< Set when -mno-stack-arg-probe is used CODEGENOPT(DebugColumnInfo, 1, 0) ///< Whether or not to use column information ///< in debug info. @@ -230,7 +252,7 @@ CODEGENOPT(DebugExplicitImport, 1, 0) ///< Whether or not debug info should CODEGENOPT(EnableSplitDwarf, 1, 0) ///< Whether to enable split DWARF CODEGENOPT(SplitDwarfInlining, 1, 1) ///< Whether to include inlining info in the ///< skeleton CU to allow for symbolication - ///< of inline stack frames without .dwo files. + ///< of inline stack frames without .dwo files. CODEGENOPT(DebugFwdTemplateParams, 1, 0) ///< Whether to emit complete ///< template parameter descriptions in ///< forward declarations (versus just @@ -311,6 +333,16 @@ CODEGENOPT(GnuPubnames, 1, 0) CODEGENOPT(NoPLT, 1, 0) +/// Whether to embed source in DWARF debug line section. +CODEGENOPT(EmbedSource, 1, 0) + +/// Whether to emit all vtables +CODEGENOPT(ForceEmitVTables, 1, 0) + +/// Whether to emit an address-significance table into the object file. +CODEGENOPT(Addrsig, 1, 0) + + #undef CODEGENOPT #undef ENUM_CODEGENOPT #undef VALUE_CODEGENOPT diff --git a/gnu/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h b/gnu/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h index 069ca4b8f84..1d421f09fdc 100644 --- a/gnu/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h +++ b/gnu/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h @@ -1,4 +1,4 @@ -//===-- CompilerInvocation.h - Compiler Invocation Helper Data --*- C++ -*-===// +//===- CompilerInvocation.h - Compiler Invocation Helper Data ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H_ -#define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H_ +#ifndef LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H +#define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/Frontend/DependencyOutputOptions.h" @@ -21,25 +22,29 @@ #include "clang/Frontend/PreprocessorOutputOptions.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" +#include <memory> #include <string> namespace llvm { + class Triple; namespace opt { + class ArgList; -} -} + +} // namespace opt + +} // namespace llvm namespace clang { -class PreprocessorOptions; + +class DiagnosticsEngine; class HeaderSearchOptions; +class PreprocessorOptions; class TargetOptions; -class LangOptions; -class CompilerInvocation; -class DiagnosticsEngine; -/// \brief Fill out Opts based on the options given in Args. +/// Fill out Opts based on the options given in Args. /// /// Args must have been created from the OptTable returned by /// createCC1OptTable(). @@ -48,12 +53,10 @@ class DiagnosticsEngine; /// report the error(s). bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args, DiagnosticsEngine *Diags = nullptr, - bool DefaultDiagColor = false, + bool DefaultDiagColor = true, bool DefaultShowOpt = true); class CompilerInvocationBase { - void operator=(const CompilerInvocationBase &) = delete; - public: /// Options controlling the language variant. std::shared_ptr<LangOptions> LangOpts; @@ -71,24 +74,24 @@ public: std::shared_ptr<PreprocessorOptions> PreprocessorOpts; CompilerInvocationBase(); - ~CompilerInvocationBase(); - CompilerInvocationBase(const CompilerInvocationBase &X); + CompilerInvocationBase &operator=(const CompilerInvocationBase &) = delete; + ~CompilerInvocationBase(); LangOptions *getLangOpts() { return LangOpts.get(); } const LangOptions *getLangOpts() const { return LangOpts.get(); } TargetOptions &getTargetOpts() { return *TargetOpts.get(); } - const TargetOptions &getTargetOpts() const { - return *TargetOpts.get(); - } + const TargetOptions &getTargetOpts() const { return *TargetOpts.get(); } DiagnosticOptions &getDiagnosticOpts() const { return *DiagnosticOpts; } HeaderSearchOptions &getHeaderSearchOpts() { return *HeaderSearchOpts; } + const HeaderSearchOptions &getHeaderSearchOpts() const { return *HeaderSearchOpts; } + std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() const { return HeaderSearchOpts; } @@ -96,13 +99,15 @@ public: std::shared_ptr<PreprocessorOptions> getPreprocessorOptsPtr() { return PreprocessorOpts; } + PreprocessorOptions &getPreprocessorOpts() { return *PreprocessorOpts; } + const PreprocessorOptions &getPreprocessorOpts() const { return *PreprocessorOpts; } }; - -/// \brief Helper class for holding the data necessary to invoke the compiler. + +/// Helper class for holding the data necessary to invoke the compiler. /// /// This class is designed to represent an abstract "invocation" of the /// compiler, including data such as the include paths, the code generation @@ -112,7 +117,7 @@ class CompilerInvocation : public CompilerInvocationBase { AnalyzerOptionsRef AnalyzerOpts; MigratorOptions MigratorOpts; - + /// Options controlling IRgen and the backend. CodeGenOptions CodeGenOpts; @@ -134,7 +139,7 @@ public: /// @name Utility Methods /// @{ - /// \brief Create a compiler invocation from a list of input options. + /// Create a compiler invocation from a list of input options. /// \returns true on success. /// /// \param [out] Res - The resulting invocation. @@ -146,7 +151,7 @@ public: const char* const *ArgEnd, DiagnosticsEngine &Diags); - /// \brief Get the directory where the compiler headers + /// Get the directory where the compiler headers /// reside, relative to the compiler binary (found by the passed in /// arguments). /// @@ -156,7 +161,7 @@ public: /// executable), for finding the builtin compiler path. static std::string GetResourcesPath(const char *Argv0, void *MainAddr); - /// \brief Set language defaults for the given input language and + /// Set language defaults for the given input language and /// language standard in the given LangOptions object. /// /// \param Opts - The LangOptions object to set up. @@ -167,49 +172,44 @@ public: static void setLangDefaults(LangOptions &Opts, InputKind IK, const llvm::Triple &T, PreprocessorOptions &PPOpts, LangStandard::Kind LangStd = LangStandard::lang_unspecified); - - /// \brief Retrieve a module hash string that is suitable for uniquely + + /// Retrieve a module hash string that is suitable for uniquely /// identifying the conditions under which the module was built. std::string getModuleHash() const; - + /// @} /// @name Option Subgroups /// @{ - AnalyzerOptionsRef getAnalyzerOpts() const { - return AnalyzerOpts; - } + AnalyzerOptionsRef getAnalyzerOpts() const { return AnalyzerOpts; } MigratorOptions &getMigratorOpts() { return MigratorOpts; } - const MigratorOptions &getMigratorOpts() const { - return MigratorOpts; - } - + const MigratorOptions &getMigratorOpts() const { return MigratorOpts; } + CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; } - const CodeGenOptions &getCodeGenOpts() const { - return CodeGenOpts; - } + const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } DependencyOutputOptions &getDependencyOutputOpts() { return DependencyOutputOpts; } + const DependencyOutputOptions &getDependencyOutputOpts() const { return DependencyOutputOpts; } FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; } + const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; } FrontendOptions &getFrontendOpts() { return FrontendOpts; } - const FrontendOptions &getFrontendOpts() const { - return FrontendOpts; - } + const FrontendOptions &getFrontendOpts() const { return FrontendOpts; } PreprocessorOutputOptions &getPreprocessorOutputOpts() { return PreprocessorOutputOpts; } + const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { return PreprocessorOutputOpts; } @@ -218,8 +218,10 @@ public: }; namespace vfs { - class FileSystem; -} + +class FileSystem; + +} // namespace vfs IntrusiveRefCntPtr<vfs::FileSystem> createVFSFromCompilerInvocation(const CompilerInvocation &CI, @@ -230,6 +232,6 @@ createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags, IntrusiveRefCntPtr<vfs::FileSystem> BaseFS); -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H diff --git a/gnu/llvm/tools/clang/include/clang/Sema/Sema.h b/gnu/llvm/tools/clang/include/clang/Sema/Sema.h index 0e8b276aadb..d0b922f022c 100644 --- a/gnu/llvm/tools/clang/include/clang/Sema/Sema.h +++ b/gnu/llvm/tools/clang/include/clang/Sema/Sema.h @@ -17,9 +17,11 @@ #include "clang/AST/Attr.h" #include "clang/AST/Availability.h" -#include "clang/AST/DeclarationName.h" +#include "clang/AST/ComparisonCategories.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/LocInfoType.h" @@ -30,7 +32,6 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/ExpressionTraits.h" -#include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PragmaKinds.h" @@ -45,12 +46,12 @@ #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" -#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" @@ -75,7 +76,7 @@ namespace clang { class ASTReader; class ASTWriter; class ArrayType; - class AttributeList; + class ParsedAttr; class BindingDecl; class BlockDecl; class CapturedDecl; @@ -172,6 +173,7 @@ namespace clang { class TemplateArgumentList; class TemplateArgumentLoc; class TemplateDecl; + class TemplateInstantiationCallback; class TemplateParameterList; class TemplatePartialOrderingContext; class TemplateTemplateParmDecl; @@ -200,6 +202,7 @@ namespace clang { namespace sema { class AccessedEntity; class BlockScopeInfo; + class Capture; class CapturedRegionScopeInfo; class CapturingScopeInfo; class CompoundScopeInfo; @@ -275,10 +278,10 @@ class Sema { Sema(const Sema &) = delete; void operator=(const Sema &) = delete; - ///\brief Source of additional semantic information. + ///Source of additional semantic information. ExternalSemaSource *ExternalSource; - ///\brief Whether Sema has generated a multiplexer and has to delete it. + ///Whether Sema has generated a multiplexer and has to delete it. bool isMultiplexExternalSource; static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); @@ -318,16 +321,16 @@ public: DiagnosticsEngine &Diags; SourceManager &SourceMgr; - /// \brief Flag indicating whether or not to collect detailed statistics. + /// Flag indicating whether or not to collect detailed statistics. bool CollectStats; - /// \brief Code-completion consumer. + /// Code-completion consumer. CodeCompleteConsumer *CodeCompleter; /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; - /// \brief Generally null except when we temporarily switch decl contexts, + /// Generally null except when we temporarily switch decl contexts, /// like in \see ActOnObjCTemporaryExitContainerContext. DeclContext *OriginalLexicalContext; @@ -337,17 +340,17 @@ public: bool MSStructPragmaOn; // True when \#pragma ms_struct on - /// \brief Controls member pointer representation format under the MS ABI. + /// Controls member pointer representation format under the MS ABI. LangOptions::PragmaMSPointersToMembersKind MSPointerToMemberRepresentationMethod; /// Stack of active SEH __finally scopes. Can be empty. SmallVector<Scope*, 2> CurrentSEHFinally; - /// \brief Source location for newly created implicit MSInheritanceAttrs + /// Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; - /// \brief pragma clang section kind + /// pragma clang section kind enum PragmaClangSectionKind { PCSK_Invalid = 0, PCSK_BSS = 1, @@ -438,7 +441,7 @@ public: // FIXME: We should serialize / deserialize these if they occur in a PCH (but // we shouldn't do so if they're in a module). - /// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft + /// Whether to insert vtordisps prior to virtual bases in the Microsoft /// C++ ABI. Possible values are 0, 1, and 2, which mean: /// /// 0: Suppress all vtordisps @@ -487,26 +490,26 @@ public: /// VisContext - Manages the stack for \#pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" - /// \brief This represents the stack of attributes that were pushed by + /// This represents the stack of attributes that were pushed by /// \#pragma clang attribute. struct PragmaAttributeEntry { SourceLocation Loc; - AttributeList *Attribute; + ParsedAttr *Attribute; SmallVector<attr::SubjectMatchRule, 4> MatchRules; bool IsUsed; }; SmallVector<PragmaAttributeEntry, 2> PragmaAttributeStack; - /// \brief The declaration that is currently receiving an attribute from the + /// The declaration that is currently receiving an attribute from the /// #pragma attribute stack. const Decl *PragmaAttributeCurrentTargetDecl; - /// \brief This represents the last location of a "#pragma clang optimize off" + /// This represents the last location of a "#pragma clang optimize off" /// directive if such a directive has not been closed by an "on" yet. If /// optimizations are currently "on", this is set to an invalid location. SourceLocation OptimizeOffPragmaLocation; - /// \brief Flag indicating if Sema is building a recovery call expression. + /// Flag indicating if Sema is building a recovery call expression. /// /// This flag is used to avoid building recovery call expressions /// if Sema is already doing so, which would cause infinite recursions. @@ -520,7 +523,7 @@ public: /// element type here is ExprWithCleanups::Object. SmallVector<BlockDecl*, 8> ExprCleanupObjects; - /// \brief Store a list of either DeclRefExprs or MemberExprs + /// Store a list of either DeclRefExprs or MemberExprs /// that contain a reference to a variable (constant) that may or may not /// be odr-used in this Expr, and we won't know until all lvalue-to-rvalue /// and discarded value conversions have been applied to all subexpressions @@ -528,12 +531,10 @@ public: /// full expression. llvm::SmallPtrSet<Expr*, 2> MaybeODRUseExprs; - /// \brief Stack containing information about each of the nested + std::unique_ptr<sema::FunctionScopeInfo> PreallocatedFunctionScope; + + /// Stack containing information about each of the nested /// function, block, and method scopes that are currently active. - /// - /// This array is never empty. Clients should ignore the first - /// element, which is used to cache a single FunctionScopeInfo - /// that's used to parse every top-level function. SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes; typedef LazyVector<TypedefNameDecl *, ExternalSemaSource, @@ -548,16 +549,16 @@ public: /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. std::unique_ptr<CXXFieldCollector> FieldCollector; - typedef llvm::SmallSetVector<const NamedDecl*, 16> NamedDeclSetType; + typedef llvm::SmallSetVector<NamedDecl *, 16> NamedDeclSetType; - /// \brief Set containing all declared private fields that are not used. + /// Set containing all declared private fields that are not used. NamedDeclSetType UnusedPrivateFields; - /// \brief Set containing all typedefs that are likely unused. + /// Set containing all typedefs that are likely unused. llvm::SmallSetVector<const TypedefNameDecl *, 4> UnusedLocalTypedefNameCandidates; - /// \brief Delete-expressions to be analyzed at the end of translation unit + /// Delete-expressions to be analyzed at the end of translation unit /// /// This list contains class members, and locations of delete-expressions /// that could not be proven as to whether they mismatch with new-expression @@ -577,21 +578,21 @@ public: /// we are currently parsing the initializer. llvm::SmallPtrSet<const Decl*, 4> ParsingInitForAutoVars; - /// \brief Look for a locally scoped extern "C" declaration by the given name. + /// Look for a locally scoped extern "C" declaration by the given name. NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name); typedef LazyVector<VarDecl *, ExternalSemaSource, &ExternalSemaSource::ReadTentativeDefinitions, 2, 2> TentativeDefinitionsType; - /// \brief All the tentative definitions encountered in the TU. + /// All the tentative definitions encountered in the TU. TentativeDefinitionsType TentativeDefinitions; typedef LazyVector<const DeclaratorDecl *, ExternalSemaSource, &ExternalSemaSource::ReadUnusedFileScopedDecls, 2, 2> UnusedFileScopedDeclsType; - /// \brief The set of file scoped decls seen so far that have not been used + /// The set of file scoped decls seen so far that have not been used /// and must warn if not used. Only contains the first declaration. UnusedFileScopedDeclsType UnusedFileScopedDecls; @@ -599,17 +600,17 @@ public: &ExternalSemaSource::ReadDelegatingConstructors, 2, 2> DelegatingCtorDeclsType; - /// \brief All the delegating constructors seen so far in the file, used for + /// All the delegating constructors seen so far in the file, used for /// cycle detection at the end of the TU. DelegatingCtorDeclsType DelegatingCtorDecls; - /// \brief All the overriding functions seen during a class definition + /// All the overriding functions seen during a class definition /// that had their exception spec checks delayed, plus the overridden /// function. SmallVector<std::pair<const CXXMethodDecl*, const CXXMethodDecl*>, 2> DelayedExceptionSpecChecks; - /// \brief All the members seen during a class definition which were both + /// All the members seen during a class definition which were both /// explicitly defaulted and had explicitly-specified exception /// specifications, along with the function type containing their /// user-specified exception specification. Those exception specifications @@ -624,7 +625,7 @@ public: LateParsedTemplateMapT; LateParsedTemplateMapT LateParsedTemplateMap; - /// \brief Callback to the parser to parse templated functions when needed. + /// Callback to the parser to parse templated functions when needed. typedef void LateTemplateParserCB(void *P, LateParsedTemplate &LPT); typedef void LateTemplateParserCleanupCB(void *P); LateTemplateParserCB *LateTemplateParser; @@ -651,7 +652,7 @@ public: /// A class which encapsulates the logic for delaying diagnostics /// during parsing and other processing. class DelayedDiagnostics { - /// \brief The current pool of diagnostics into which delayed + /// The current pool of diagnostics into which delayed /// diagnostics should go. sema::DelayedDiagnosticPool *CurPool; @@ -734,7 +735,7 @@ public: } }; - /// \brief RAII object to handle the state changes required to synthesize + /// RAII object to handle the state changes required to synthesize /// a function body. class SynthesizedFunctionScope { Sema &S; @@ -787,7 +788,7 @@ public: llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*> ExtnameUndeclaredIdentifiers; - /// \brief Load weak undeclared identifiers from the external source. + /// Load weak undeclared identifiers from the external source. void LoadExternalWeakUndeclaredIdentifiers(); /// WeakTopLevelDecl - Translation-unit scoped declarations generated by @@ -804,77 +805,81 @@ public: /// For example, user-defined classes, built-in "id" type, etc. Scope *TUScope; - /// \brief The C++ "std" namespace, where the standard library resides. + /// The C++ "std" namespace, where the standard library resides. LazyDeclPtr StdNamespace; - /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ + /// The C++ "std::bad_alloc" class, which is defined by the C++ /// standard library. LazyDeclPtr StdBadAlloc; - /// \brief The C++ "std::align_val_t" enum class, which is defined by the C++ + /// The C++ "std::align_val_t" enum class, which is defined by the C++ /// standard library. LazyDeclPtr StdAlignValT; - /// \brief The C++ "std::experimental" namespace, where the experimental parts + /// The C++ "std::experimental" namespace, where the experimental parts /// of the standard library resides. NamespaceDecl *StdExperimentalNamespaceCache; - /// \brief The C++ "std::initializer_list" template, which is defined in + /// The C++ "std::initializer_list" template, which is defined in /// \<initializer_list>. ClassTemplateDecl *StdInitializerList; - /// \brief The C++ "type_info" declaration, which is defined in \<typeinfo>. + /// The C++ "std::coroutine_traits" template, which is defined in + /// \<coroutine_traits> + ClassTemplateDecl *StdCoroutineTraitsCache; + + /// The C++ "type_info" declaration, which is defined in \<typeinfo>. RecordDecl *CXXTypeInfoDecl; - /// \brief The MSVC "_GUID" struct, which is defined in MSVC header files. + /// The MSVC "_GUID" struct, which is defined in MSVC header files. RecordDecl *MSVCGuidDecl; - /// \brief Caches identifiers/selectors for NSFoundation APIs. + /// Caches identifiers/selectors for NSFoundation APIs. std::unique_ptr<NSAPI> NSAPIObj; - /// \brief The declaration of the Objective-C NSNumber class. + /// The declaration of the Objective-C NSNumber class. ObjCInterfaceDecl *NSNumberDecl; - /// \brief The declaration of the Objective-C NSValue class. + /// The declaration of the Objective-C NSValue class. ObjCInterfaceDecl *NSValueDecl; - /// \brief Pointer to NSNumber type (NSNumber *). + /// Pointer to NSNumber type (NSNumber *). QualType NSNumberPointer; - /// \brief Pointer to NSValue type (NSValue *). + /// Pointer to NSValue type (NSValue *). QualType NSValuePointer; - /// \brief The Objective-C NSNumber methods used to create NSNumber literals. + /// The Objective-C NSNumber methods used to create NSNumber literals. ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; - /// \brief The declaration of the Objective-C NSString class. + /// The declaration of the Objective-C NSString class. ObjCInterfaceDecl *NSStringDecl; - /// \brief Pointer to NSString type (NSString *). + /// Pointer to NSString type (NSString *). QualType NSStringPointer; - /// \brief The declaration of the stringWithUTF8String: method. + /// The declaration of the stringWithUTF8String: method. ObjCMethodDecl *StringWithUTF8StringMethod; - /// \brief The declaration of the valueWithBytes:objCType: method. + /// The declaration of the valueWithBytes:objCType: method. ObjCMethodDecl *ValueWithBytesObjCTypeMethod; - /// \brief The declaration of the Objective-C NSArray class. + /// The declaration of the Objective-C NSArray class. ObjCInterfaceDecl *NSArrayDecl; - /// \brief The declaration of the arrayWithObjects:count: method. + /// The declaration of the arrayWithObjects:count: method. ObjCMethodDecl *ArrayWithObjectsMethod; - /// \brief The declaration of the Objective-C NSDictionary class. + /// The declaration of the Objective-C NSDictionary class. ObjCInterfaceDecl *NSDictionaryDecl; - /// \brief The declaration of the dictionaryWithObjects:forKeys:count: method. + /// The declaration of the dictionaryWithObjects:forKeys:count: method. ObjCMethodDecl *DictionaryWithObjectsMethod; - /// \brief id<NSCopying> type. + /// id<NSCopying> type. QualType QIDNSCopying; - /// \brief will hold 'respondsToSelector:' + /// will hold 'respondsToSelector:' Selector RespondsToSelectorSel; /// A flag to remember whether the implicit forms of operator new and delete @@ -885,43 +890,43 @@ public: /// references to fields. This is really a bool AllowAbstractFieldReference; - /// \brief Describes how the expressions currently being parsed are + /// Describes how the expressions currently being parsed are /// evaluated at run-time, if at all. enum class ExpressionEvaluationContext { - /// \brief The current expression and its subexpressions occur within an + /// The current expression and its subexpressions occur within an /// unevaluated operand (C++11 [expr]p7), such as the subexpression of /// \c sizeof, where the type of the expression may be significant but /// no code will be generated to evaluate the value of the expression at /// run time. Unevaluated, - /// \brief The current expression occurs within a braced-init-list within + /// The current expression occurs within a braced-init-list within /// an unevaluated operand. This is mostly like a regular unevaluated /// context, except that we still instantiate constexpr functions that are /// referenced here so that we can perform narrowing checks correctly. UnevaluatedList, - /// \brief The current expression occurs within a discarded statement. + /// The current expression occurs within a discarded statement. /// This behaves largely similarly to an unevaluated operand in preventing /// definitions from being required, but not in other ways. DiscardedStatement, - /// \brief The current expression occurs within an unevaluated + /// The current expression occurs within an unevaluated /// operand that unconditionally permits abstract references to /// fields, such as a SIZE operator in MS-style inline assembly. UnevaluatedAbstract, - /// \brief The current context is "potentially evaluated" in C++11 terms, + /// The current context is "potentially evaluated" in C++11 terms, /// but the expression is evaluated at compile-time (like the values of /// cases in a switch statement). ConstantEvaluated, - /// \brief The current expression is potentially evaluated at run time, + /// The current expression is potentially evaluated at run time, /// which means that code may be generated to evaluate the value of the /// expression at run time. PotentiallyEvaluated, - /// \brief The current expression is potentially evaluated, but any + /// The current expression is potentially evaluated, but any /// declarations referenced inside that expression are only used if /// in fact the current expression is used. /// @@ -932,63 +937,69 @@ public: PotentiallyEvaluatedIfUsed }; - /// \brief Data structure used to record current or nested + /// Data structure used to record current or nested /// expression evaluation contexts. struct ExpressionEvaluationContextRecord { - /// \brief The expression evaluation context. + /// The expression evaluation context. ExpressionEvaluationContext Context; - /// \brief Whether the enclosing context needed a cleanup. + /// Whether the enclosing context needed a cleanup. CleanupInfo ParentCleanup; - /// \brief Whether we are in a decltype expression. + /// Whether we are in a decltype expression. bool IsDecltype; - /// \brief The number of active cleanup objects when we entered + /// The number of active cleanup objects when we entered /// this expression evaluation context. unsigned NumCleanupObjects; - /// \brief The number of typos encountered during this expression evaluation + /// The number of typos encountered during this expression evaluation /// context (i.e. the number of TypoExprs created). unsigned NumTypos; llvm::SmallPtrSet<Expr*, 2> SavedMaybeODRUseExprs; - /// \brief The lambdas that are present within this context, if it + /// The lambdas that are present within this context, if it /// is indeed an unevaluated context. SmallVector<LambdaExpr *, 2> Lambdas; - /// \brief The declaration that provides context for lambda expressions + /// The declaration that provides context for lambda expressions /// and block literals if the normal declaration context does not /// suffice, e.g., in a default function argument. Decl *ManglingContextDecl; - /// \brief The context information used to mangle lambda expressions + /// The context information used to mangle lambda expressions /// and block literals within this context. /// /// This mangling information is allocated lazily, since most contexts /// do not have lambda expressions or block literals. std::unique_ptr<MangleNumberingContext> MangleNumbering; - /// \brief If we are processing a decltype type, a set of call expressions + /// If we are processing a decltype type, a set of call expressions /// for which we have deferred checking the completeness of the return type. SmallVector<CallExpr *, 8> DelayedDecltypeCalls; - /// \brief If we are processing a decltype type, a set of temporary binding + /// If we are processing a decltype type, a set of temporary binding /// expressions for which we have deferred checking the destructor. SmallVector<CXXBindTemporaryExpr *, 8> DelayedDecltypeBinds; + /// \brief Describes whether we are in an expression constext which we have + /// to handle differently. + enum ExpressionKind { + EK_Decltype, EK_TemplateArgument, EK_Other + } ExprContext; + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, CleanupInfo ParentCleanup, Decl *ManglingContextDecl, - bool IsDecltype) - : Context(Context), ParentCleanup(ParentCleanup), - IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), - NumTypos(0), - ManglingContextDecl(ManglingContextDecl), MangleNumbering() { } + ExpressionKind ExprContext) + : Context(Context), ParentCleanup(ParentCleanup), + NumCleanupObjects(NumCleanupObjects), NumTypos(0), + ManglingContextDecl(ManglingContextDecl), MangleNumbering(), + ExprContext(ExprContext) {} - /// \brief Retrieve the mangling numbering context, used to consistently + /// Retrieve the mangling numbering context, used to consistently /// number constructs like lambdas for mangling. MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx); @@ -1005,7 +1016,7 @@ public: /// A stack of expression evaluation contexts. SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts; - /// \brief Compute the mangling number context for a lambda expression or + /// Compute the mangling number context for a lambda expression or /// block literal. /// /// \param DC - The DeclContext containing the lambda expression or @@ -1054,15 +1065,15 @@ public: {} }; - /// \brief A cache of special member function overload resolution results + /// A cache of special member function overload resolution results /// for C++ records. llvm::FoldingSet<SpecialMemberOverloadResultEntry> SpecialMemberCache; - /// \brief A cache of the flags available in enumerations with the flag_bits + /// A cache of the flags available in enumerations with the flag_bits /// attribute. mutable llvm::DenseMap<const EnumDecl*, llvm::APInt> FlagBitsCache; - /// \brief The kind of translation unit we are processing. + /// The kind of translation unit we are processing. /// /// When we're processing a complete translation unit, Sema will perform /// end-of-translation-unit semantic tasks (such as creating @@ -1073,13 +1084,13 @@ public: llvm::BumpPtrAllocator BumpAlloc; - /// \brief The number of SFINAE diagnostics that have been trapped. + /// The number of SFINAE diagnostics that have been trapped. unsigned NumSFINAEErrors; typedef llvm::DenseMap<ParmVarDecl *, llvm::TinyPtrVector<ParmVarDecl *>> UnparsedDefaultArgInstantiationsMap; - /// \brief A mapping from parameters with unparsed default arguments to the + /// A mapping from parameters with unparsed default arguments to the /// set of instantiations of each parameter. /// /// This mapping is a temporary data structure used when parsing @@ -1161,7 +1172,7 @@ public: bool isSelfExpr(Expr *RExpr); bool isSelfExpr(Expr *RExpr, const ObjCMethodDecl *Method); - /// \brief Cause the active diagnostic on the DiagosticsEngine to be + /// Cause the active diagnostic on the DiagosticsEngine to be /// emitted. This is closely coupled to the SemaDiagnosticBuilder class and /// should not be used elsewhere. void EmitCurrentDiagnostic(unsigned DiagID); @@ -1186,7 +1197,7 @@ public: CodeCompleteConsumer *CompletionConsumer = nullptr); ~Sema(); - /// \brief Perform initialization that occurs after the parser has been + /// Perform initialization that occurs after the parser has been /// initialized but before it parses anything. void Initialize(); @@ -1202,7 +1213,7 @@ public: ASTMutationListener *getASTMutationListener() const; ExternalSemaSource* getExternalSource() const { return ExternalSource; } - ///\brief Registers an external source. If an external source already exists, + ///Registers an external source. If an external source already exists, /// creates a multiplex external source and appends to it. /// ///\param[in] E - A non-null external sema source. @@ -1211,7 +1222,7 @@ public: void PrintStats() const; - /// \brief Helper class that creates diagnostics with optional + /// Helper class that creates diagnostics with optional /// template instantiation stacks. /// /// This class provides a wrapper around the basic DiagnosticBuilder @@ -1266,29 +1277,29 @@ public: } }; - /// \brief Emit a diagnostic. + /// Emit a diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { DiagnosticBuilder DB = Diags.Report(Loc, DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID); } - /// \brief Emit a partial diagnostic. + /// Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); - /// \brief Build a partial diagnostic. + /// Build a partial diagnostic. PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h bool findMacroSpelling(SourceLocation &loc, StringRef name); - /// \brief Get a string to suggest for zero-initialization of a type. + /// Get a string to suggest for zero-initialization of a type. std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const; std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const; - /// \brief Calls \c Lexer::getLocForEndOfToken() + /// Calls \c Lexer::getLocForEndOfToken() SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0); - /// \brief Retrieve the module loader associated with the preprocessor. + /// Retrieve the module loader associated with the preprocessor. ModuleLoader &getModuleLoader() const; void emitAndClearUnusedLocalTypedefWarnings(); @@ -1304,7 +1315,7 @@ public: void PushBlockScope(Scope *BlockScope, BlockDecl *Block); sema::LambdaScopeInfo *PushLambdaScope(); - /// \brief This is used to inform Sema what the current TemplateParameterDepth + /// This is used to inform Sema what the current TemplateParameterDepth /// is during Parsing. Currently it is used to pass on the depth /// when parsing generic lambda 'auto' parameters. void RecordParsingTemplateParameterDepth(unsigned Depth); @@ -1318,35 +1329,23 @@ public: const BlockExpr *blkExpr = nullptr); sema::FunctionScopeInfo *getCurFunction() const { - return FunctionScopes.back(); + return FunctionScopes.empty() ? nullptr : FunctionScopes.back(); } - sema::FunctionScopeInfo *getEnclosingFunction() const { - if (FunctionScopes.empty()) - return nullptr; + sema::FunctionScopeInfo *getEnclosingFunction() const; - for (int e = FunctionScopes.size()-1; e >= 0; --e) { - if (isa<sema::BlockScopeInfo>(FunctionScopes[e])) - continue; - return FunctionScopes[e]; - } - return nullptr; - } + void setFunctionHasBranchIntoScope(); + void setFunctionHasBranchProtectedScope(); + void setFunctionHasIndirectGoto(); - template <typename ExprT> - void recordUseOfEvaluatedWeak(const ExprT *E, bool IsRead=true) { - if (!isUnevaluatedContext()) - getCurFunction()->recordUseOfWeak(E, IsRead); - } - - void PushCompoundScope(); + void PushCompoundScope(bool IsStmtExpr); void PopCompoundScope(); sema::CompoundScopeInfo &getCurCompoundScope() const; bool hasAnyUnrecoverableErrorsInThisFunction() const; - /// \brief Retrieve the current block, if any. + /// Retrieve the current block, if any. sema::BlockScopeInfo *getCurBlock(); /// Retrieve the current lambda scope info, if any. @@ -1356,10 +1355,10 @@ public: sema::LambdaScopeInfo * getCurLambda(bool IgnoreNonLambdaCapturingScope = false); - /// \brief Retrieve the current generic lambda info, if any. + /// Retrieve the current generic lambda info, if any. sema::LambdaScopeInfo *getCurGenericLambda(); - /// \brief Retrieve the current captured region, if any. + /// Retrieve the current captured region, if any. sema::CapturedRegionScopeInfo *getCurCapturedRegion(); /// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls @@ -1382,6 +1381,7 @@ public: QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, SourceRange Brackets, DeclarationName Entity); + QualType BuildVectorType(QualType T, Expr *VecSize, SourceLocation AttrLoc); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, @@ -1389,7 +1389,7 @@ public: bool CheckFunctionReturnType(QualType T, SourceLocation Loc); - /// \brief Build a function type. + /// Build a function type. /// /// This routine checks the function type according to C++ rules and /// under the assumption that the result type and parameter types have @@ -1438,7 +1438,7 @@ public: TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *ReturnTypeInfo); - /// \brief Package the given type and TSI into a ParsedType. + /// Package the given type and TSI into a ParsedType. ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); DeclarationNameInfo GetNameForDeclarator(Declarator &D); DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name); @@ -1459,6 +1459,7 @@ public: const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); + bool handlerCanCatch(QualType HandlerType, QualType ExceptionType); bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID, @@ -1475,11 +1476,11 @@ public: TypeResult ActOnTypeName(Scope *S, Declarator &D); - /// \brief The parser has parsed the context-sensitive type 'instancetype' + /// The parser has parsed the context-sensitive type 'instancetype' /// in an Objective-C message declaration. Return the appropriate type. ParsedType ActOnObjCInstanceType(SourceLocation Loc); - /// \brief Abstract class used to diagnose incomplete types. + /// Abstract class used to diagnose incomplete types. struct TypeDiagnoser { TypeDiagnoser() {} @@ -1548,10 +1549,10 @@ private: VisibleModuleSet VisibleModules; public: - /// \brief Get the module owning an entity. + /// Get the module owning an entity. Module *getOwningModule(Decl *Entity) { return Entity->getOwningModule(); } - /// \brief Make a merged definition of an existing hidden definition \p ND + /// Make a merged definition of an existing hidden definition \p ND /// visible at the specified location. void makeMergedDefinitionVisible(NamedDecl *ND); @@ -1649,7 +1650,8 @@ public: } QualType getElaboratedType(ElaboratedTypeKeyword Keyword, - const CXXScopeSpec &SS, QualType T); + const CXXScopeSpec &SS, QualType T, + TagDecl *OwnedTagDecl = nullptr); QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); /// If AsUnevaluated is false, E is treated as though it were an evaluated @@ -1705,7 +1707,7 @@ public: SourceLocation NameLoc, bool IsTemplateTypeArg); - /// \brief Describes the result of the name lookup and resolution performed + /// Describes the result of the name lookup and resolution performed /// by \c ClassifyName(). enum NameClassificationKind { NC_Unknown, @@ -1796,7 +1798,7 @@ public: } }; - /// \brief Perform name lookup on the given name, classifying it based on + /// Perform name lookup on the given name, classifying it based on /// the results of name lookup and the following token. /// /// This routine is used by the parser to resolve identifiers and help direct @@ -1840,13 +1842,19 @@ public: /// Determine whether it's plausible that E was intended to be a /// template-name. - bool mightBeIntendedToBeTemplateName(ExprResult E) { + bool mightBeIntendedToBeTemplateName(ExprResult E, bool &Dependent) { if (!getLangOpts().CPlusPlus || E.isInvalid()) return false; + Dependent = false; if (auto *DRE = dyn_cast<DeclRefExpr>(E.get())) return !DRE->hasExplicitTemplateArgs(); if (auto *ME = dyn_cast<MemberExpr>(E.get())) return !ME->hasExplicitTemplateArgs(); + Dependent = true; + if (auto *DSDRE = dyn_cast<DependentScopeDeclRefExpr>(E.get())) + return !DSDRE->hasExplicitTemplateArgs(); + if (auto *DSME = dyn_cast<CXXDependentScopeMemberExpr>(E.get())) + return !DSME->hasExplicitTemplateArgs(); // Any additional cases recognized here should also be handled by // diagnoseExprIntendedAsTemplateName. return false; @@ -1862,8 +1870,8 @@ public: void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S); bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, - DeclarationName Name, - SourceLocation Loc); + DeclarationName Name, SourceLocation Loc, + bool IsTemplateId); void diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, SourceLocation FallbackLoc, @@ -1942,8 +1950,11 @@ public: FunctionDecl *NewFD, LookupResult &Previous, bool IsMemberSpecialization); bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl); + bool canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD, + QualType NewT, QualType OldT); void CheckMain(FunctionDecl *FD, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); + Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition); Decl *ActOnParamDeclarator(Scope *S, Declarator &D); ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, @@ -1999,7 +2010,7 @@ public: return D && isa<ObjCMethodDecl>(D); } - /// \brief Determine whether we can delay parsing the body of a function or + /// Determine whether we can delay parsing the body of a function or /// function template until it is used, assuming we don't care about emitting /// code for that function. /// @@ -2009,7 +2020,7 @@ public: /// or has an 'auto' return type in C++14. These cases are essentially bugs. bool canDelayFunctionBody(const Declarator &D); - /// \brief Determine whether we can skip parsing the body of a function + /// Determine whether we can skip parsing the body of a function /// definition, assuming we don't care about analyzing its body or emitting /// code for that function. /// @@ -2028,11 +2039,11 @@ public: /// attribute for which parsing is delayed. void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs); - /// \brief Diagnose any unused parameters in the given sequence of + /// Diagnose any unused parameters in the given sequence of /// ParmVarDecl pointers. void DiagnoseUnusedParameters(ArrayRef<ParmVarDecl *> Parameters); - /// \brief Diagnose whether the size of parameters or return value of a + /// Diagnose whether the size of parameters or return value of a /// function or obj-c method definition is pass-by-value and larger than a /// specified threshold. void @@ -2044,9 +2055,8 @@ public: SourceLocation AsmLoc, SourceLocation RParenLoc); - /// \brief Handle a C++11 empty-declaration and attribute-declaration. - Decl *ActOnEmptyDeclaration(Scope *S, - AttributeList *AttrList, + /// Handle a C++11 empty-declaration and attribute-declaration. + Decl *ActOnEmptyDeclaration(Scope *S, const ParsedAttributesView &AttrList, SourceLocation SemiLoc); enum class ModuleDeclKind { @@ -2061,7 +2071,7 @@ public: SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path); - /// \brief The parser has processed a module import declaration. + /// The parser has processed a module import declaration. /// /// \param AtLoc The location of the '@' symbol, if any. /// @@ -2071,17 +2081,17 @@ public: DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc, ModuleIdPath Path); - /// \brief The parser has processed a module import translated from a + /// The parser has processed a module import translated from a /// #include or similar preprocessing directive. void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod); void BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod); - /// \brief The parsed has entered a submodule. + /// The parsed has entered a submodule. void ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod); - /// \brief The parser has left a submodule. + /// The parser has left a submodule. void ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod); - /// \brief Create an implicit import of the given module at the given + /// Create an implicit import of the given module at the given /// source location, for error recovery, if possible. /// /// This routine is typically used when an entity found by name lookup @@ -2100,7 +2110,7 @@ public: PartialSpecialization }; - /// \brief Diagnose that the specified declaration needs to be visible but + /// Diagnose that the specified declaration needs to be visible but /// isn't, and suggest a module import that would resolve the problem. void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, MissingImportKind MIK, bool Recover = true); @@ -2113,23 +2123,23 @@ public: Decl *ActOnFinishExportDecl(Scope *S, Decl *ExportDecl, SourceLocation RBraceLoc); - /// \brief We've found a use of a templated declaration that would trigger an + /// We've found a use of a templated declaration that would trigger an /// implicit instantiation. Check that any relevant explicit specializations /// and partial specializations are visible, and diagnose if not. void checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); - /// \brief We've found a use of a template specialization that would select a + /// We've found a use of a template specialization that would select a /// partial specialization. Check that the partial specialization is visible, /// and diagnose if not. void checkPartialSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); - /// \brief Retrieve a suitable printing policy. + /// Retrieve a suitable printing policy for diagnostics. PrintingPolicy getPrintingPolicy() const { return getPrintingPolicy(Context, PP); } - /// \brief Retrieve a suitable printing policy. + /// Retrieve a suitable printing policy for diagnostics. static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx, const Preprocessor &PP); @@ -2184,7 +2194,7 @@ public: Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, - SourceLocation NameLoc, AttributeList *Attr, + SourceLocation NameLoc, const ParsedAttributesView &Attr, AccessSpecifier AS, SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, @@ -2194,9 +2204,9 @@ public: Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, - CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, + CXXScopeSpec &SS, IdentifierInfo *Name, + SourceLocation NameLoc, + const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists); TypeResult ActOnDependentTag(Scope *S, @@ -2218,11 +2228,11 @@ public: InClassInitStyle InitStyle, AccessSpecifier AS); MSPropertyDecl *HandleMSProperty(Scope *S, RecordDecl *TagD, - SourceLocation DeclStart, - Declarator &D, Expr *BitfieldWidth, + SourceLocation DeclStart, Declarator &D, + Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS, - AttributeList *MSPropertyAttr); + const ParsedAttr &MSPropertyAttr); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, @@ -2235,7 +2245,17 @@ public: bool CheckNontrivialField(FieldDecl *FD); void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM); + + enum TrivialABIHandling { + /// The triviality of a method unaffected by "trivial_abi". + TAH_IgnoreTrivialABI, + + /// The triviality of a method affected by "trivial_abi". + TAH_ConsiderTrivialABI + }; + bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, + TrivialABIHandling TAH = TAH_IgnoreTrivialABI, bool Diagnose = false); CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD); void ActOnLastBitfield(SourceLocation DeclStart, @@ -2245,10 +2265,9 @@ public: tok::ObjCKeywordKind visibility); // This is used for both record definitions and ObjC interface declarations. - void ActOnFields(Scope* S, SourceLocation RecLoc, Decl *TagDecl, - ArrayRef<Decl *> Fields, - SourceLocation LBrac, SourceLocation RBrac, - AttributeList *AttrList); + void ActOnFields(Scope *S, SourceLocation RecLoc, Decl *TagDecl, + ArrayRef<Decl *> Fields, SourceLocation LBrac, + SourceLocation RBrac, const ParsedAttributesView &AttrList); /// ActOnTagStartDefinition - Invoked when we have entered the /// scope of a tag's definition (e.g., for an enumeration, class, @@ -2263,7 +2282,7 @@ public: typedef void *SkippedDefinitionContext; - /// \brief Invoked when we enter a tag definition that we're skipping. + /// Invoked when we enter a tag definition that we're skipping. SkippedDefinitionContext ActOnTagStartSkippedDefinition(Scope *S, Decl *TD); Decl *ActOnObjCContainerStartDefinition(Decl *IDecl); @@ -2285,7 +2304,7 @@ public: void ActOnObjCContainerFinishDefinition(); - /// \brief Invoked when we must temporarily exit the objective-c container + /// Invoked when we must temporarily exit the objective-c container /// scope for parsing/looking-up C constructs. /// /// Must be followed by a call to \see ActOnObjCReenterContainerContext @@ -2303,8 +2322,7 @@ public: Expr *val); bool CheckEnumUnderlyingType(TypeSourceInfo *TI); bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, - QualType EnumUnderlyingTy, - bool EnumUnderlyingIsImplicit, + QualType EnumUnderlyingTy, bool IsFixed, const EnumDecl *Prev); /// Determine whether the body of an anonymous enumeration should be skipped. @@ -2314,12 +2332,11 @@ public: Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, - AttributeList *Attrs, SourceLocation EqualLoc, - Expr *Val); + const ParsedAttributesView &Attrs, + SourceLocation EqualLoc, Expr *Val); void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, - Decl *EnumDecl, - ArrayRef<Decl *> Elements, - Scope *S, AttributeList *Attr); + Decl *EnumDecl, ArrayRef<Decl *> Elements, Scope *S, + const ParsedAttributesView &Attr); DeclContext *getContainingDC(DeclContext *DC); @@ -2356,7 +2373,7 @@ public: /// Add this decl to the scope shadowed decl chains. void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); - /// \brief Make the given externally-produced declaration visible at the + /// Make the given externally-produced declaration visible at the /// top level scope. /// /// \param D The externally-produced declaration to push. @@ -2383,18 +2400,18 @@ public: TypeSourceInfo *TInfo); bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New); - /// \brief Describes the kind of merge to perform for availability + /// Describes the kind of merge to perform for availability /// attributes (including "deprecated", "unavailable", and "availability"). enum AvailabilityMergeKind { - /// \brief Don't merge availability attributes at all. + /// Don't merge availability attributes at all. AMK_None, - /// \brief Merge availability attributes for a redeclaration, which requires + /// Merge availability attributes for a redeclaration, which requires /// an exact match. AMK_Redeclaration, - /// \brief Merge availability attributes for an override, which requires + /// Merge availability attributes for an override, which requires /// an exact match or a weakening of constraints. AMK_Override, - /// \brief Merge availability attributes for an implementation of + /// Merge availability attributes for an implementation of /// a protocol requirement. AMK_ProtocolImplementation, }; @@ -2432,6 +2449,8 @@ public: int FirstArg, unsigned AttrSpellingListIndex); SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, unsigned AttrSpellingListIndex); + CodeSegAttr *mergeCodeSegAttr(Decl *D, SourceRange Range, StringRef Name, + unsigned AttrSpellingListIndex); AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex); @@ -2496,7 +2515,7 @@ public: bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl, bool ConsiderCudaAttrs = true); - /// \brief Checks availability of the function depending on the current + /// Checks availability of the function depending on the current /// function context.Inside an unavailable function,unavailability is ignored. /// /// \returns true if \p FD is unavailable and current context is inside @@ -2568,6 +2587,11 @@ public: NamedDecl *FoundDecl, CXXMethodDecl *Method); + /// Check that the lifetime of the initializer (and its subobjects) is + /// sufficient for initializing the entity, and perform lifetime extension + /// (when permitted) if not. + void checkInitializerLifetime(const InitializedEntity &Entity, Expr *Init); + ExprResult PerformContextuallyConvertToBool(Expr *From); ExprResult PerformContextuallyConvertToObjCPointer(Expr *From); @@ -2584,7 +2608,7 @@ public: ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, APValue &Value, CCEKind CCE); - /// \brief Abstract base class used to perform a contextual implicit + /// Abstract base class used to perform a contextual implicit /// conversion from an expression to any type passing a filter. class ContextualImplicitConverter { public: @@ -2595,38 +2619,38 @@ public: bool SuppressConversion = false) : Suppress(Suppress), SuppressConversion(SuppressConversion) {} - /// \brief Determine whether the specified type is a valid destination type + /// Determine whether the specified type is a valid destination type /// for this conversion. virtual bool match(QualType T) = 0; - /// \brief Emits a diagnostic complaining that the expression does not have + /// Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0; - /// \brief Emits a diagnostic when the expression has incomplete class type. + /// Emits a diagnostic when the expression has incomplete class type. virtual SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0; - /// \brief Emits a diagnostic when the only matching conversion function + /// Emits a diagnostic when the only matching conversion function /// is explicit. virtual SemaDiagnosticBuilder diagnoseExplicitConv( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; - /// \brief Emits a note for the explicit conversion function. + /// Emits a note for the explicit conversion function. virtual SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; - /// \brief Emits a diagnostic when there are multiple possible conversion + /// Emits a diagnostic when there are multiple possible conversion /// functions. virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0; - /// \brief Emits a note for one of the candidate conversions. + /// Emits a note for one of the candidate conversions. virtual SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; - /// \brief Emits a diagnostic when we picked a conversion function + /// Emits a diagnostic when we picked a conversion function /// (for cases when we are not allowed to pick a conversion function). virtual SemaDiagnosticBuilder diagnoseConversion( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; @@ -2651,7 +2675,7 @@ public: return diagnoseNotInt(S, Loc, T); } - /// \brief Emits a diagnostic complaining that the expression does not have + /// Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) = 0; @@ -2986,7 +3010,7 @@ public: /// the ability to distinguish among them. //@{ - /// @brief Describes the kind of name lookup to perform. + /// Describes the kind of name lookup to perform. enum LookupNameKind { /// Ordinary name lookup, which finds ordinary names (functions, /// variables, typedefs, etc.) in C and most kinds of names @@ -3028,22 +3052,22 @@ public: LookupObjCProtocolName, /// Look up implicit 'self' parameter of an objective-c method. LookupObjCImplicitSelfParam, - /// \brief Look up the name of an OpenMP user-defined reduction operation. + /// Look up the name of an OpenMP user-defined reduction operation. LookupOMPReductionName, - /// \brief Look up any declaration with any name. + /// Look up any declaration with any name. LookupAnyName }; - /// \brief Specifies whether (or how) name lookup is being performed for a + /// Specifies whether (or how) name lookup is being performed for a /// redeclaration (vs. a reference). enum RedeclarationKind { - /// \brief The lookup is a reference to this name that is not for the + /// The lookup is a reference to this name that is not for the /// purpose of redeclaring the name. NotForRedeclaration = 0, - /// \brief The lookup results will be used for redeclaration of a name, + /// The lookup results will be used for redeclaration of a name, /// if an entity by that name already exists and is visible. ForVisibleRedeclaration, - /// \brief The lookup results will be used for redeclaration of a name + /// The lookup results will be used for redeclaration of a name /// with external linkage; non-visible lookup results with external linkage /// may also be found. ForExternalRedeclaration @@ -3060,23 +3084,23 @@ public: return ForExternalRedeclaration; } - /// \brief The possible outcomes of name lookup for a literal operator. + /// The possible outcomes of name lookup for a literal operator. enum LiteralOperatorLookupResult { - /// \brief The lookup resulted in an error. + /// The lookup resulted in an error. LOLR_Error, - /// \brief The lookup found no match but no diagnostic was issued. + /// The lookup found no match but no diagnostic was issued. LOLR_ErrorNoDiagnostic, - /// \brief The lookup found a single 'cooked' literal operator, which + /// The lookup found a single 'cooked' literal operator, which /// expects a normal literal to be built and passed to it. LOLR_Cooked, - /// \brief The lookup found a single 'raw' literal operator, which expects + /// The lookup found a single 'raw' literal operator, which expects /// a string literal containing the spelling of the literal token. LOLR_Raw, - /// \brief The lookup found an overload set of literal operator templates, + /// The lookup found an overload set of literal operator templates, /// which expect the characters of the spelling of the literal token to be /// passed as a non-type template argument pack. LOLR_Template, - /// \brief The lookup found an overload set of literal operator templates, + /// The lookup found an overload set of literal operator templates, /// which expect the character type and characters of the spelling of the /// string literal token to be passed as template arguments. LOLR_StringTemplate @@ -3106,25 +3130,25 @@ private: TypoExprState &operator=(TypoExprState &&other) noexcept; }; - /// \brief The set of unhandled TypoExprs and their associated state. + /// The set of unhandled TypoExprs and their associated state. llvm::MapVector<TypoExpr *, TypoExprState> DelayedTypos; - /// \brief Creates a new TypoExpr AST node. + /// Creates a new TypoExpr AST node. TypoExpr *createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC); - // \brief The set of known/encountered (unique, canonicalized) NamespaceDecls. + // The set of known/encountered (unique, canonicalized) NamespaceDecls. // // The boolean value will be true to indicate that the namespace was loaded // from an AST/PCH file, or false otherwise. llvm::MapVector<NamespaceDecl*, bool> KnownNamespaces; - /// \brief Whether we have already loaded known namespaces from an extenal + /// Whether we have already loaded known namespaces from an extenal /// source. bool LoadedExternalKnownNamespaces; - /// \brief Helper for CorrectTypo and CorrectTypoDelayed used to create and + /// Helper for CorrectTypo and CorrectTypoDelayed used to create and /// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction /// should be skipped entirely. std::unique_ptr<TypoCorrectionConsumer> @@ -3139,10 +3163,10 @@ private: public: const TypoExprState &getTypoExprState(TypoExpr *TE) const; - /// \brief Clears the state of the given TypoExpr. + /// Clears the state of the given TypoExpr. void clearDelayedTypo(TypoExpr *TE); - /// \brief Look up a name, looking for a single declaration. Return + /// Look up a name, looking for a single declaration. Return /// null if the results were absent, ambiguous, or overloaded. /// /// It is preferable to use the elaborated form and explicitly handle @@ -3199,11 +3223,13 @@ public: void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, - bool IncludeGlobalScope = true); + bool IncludeGlobalScope = true, + bool LoadExternal = true); void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true, - bool IncludeDependentBases = false); + bool IncludeDependentBases = false, + bool LoadExternal = true); enum CorrectTypoKind { CTK_NonError, // CorrectTypo used in a non error recovery situation. @@ -3230,7 +3256,7 @@ public: bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr); - /// \brief Process any TypoExprs in the given Expr and its children, + /// Process any TypoExprs in the given Expr and its children, /// generating diagnostics as appropriate and returning a new Expr if there /// were typos that were all successfully corrected and ExprError if one or /// more typos could not be corrected. @@ -3308,11 +3334,12 @@ public: // Decl attributes - this routine is the top level dispatcher. void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); // Helper for delayed processing of attributes. - void ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList); - void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, - bool IncludeCXX11Attributes = true); + void ProcessDeclAttributeDelayed(Decl *D, + const ParsedAttributesView &AttrList); + void ProcessDeclAttributeList(Scope *S, Decl *D, const ParsedAttributesView &AL, + bool IncludeCXX11Attributes = true); bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, - const AttributeList *AttrList); + const ParsedAttributesView &AttrList); void checkUnusedDeclAttributes(Declarator &D); @@ -3322,13 +3349,13 @@ public: /// type as valid. bool isValidPointerAttrType(QualType T, bool RefOkay = false); - bool CheckRegparmAttr(const AttributeList &attr, unsigned &value); - bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, + bool CheckRegparmAttr(const ParsedAttr &attr, unsigned &value); + bool CheckCallingConvAttr(const ParsedAttr &attr, CallingConv &CC, const FunctionDecl *FD = nullptr); - bool CheckNoReturnAttr(const AttributeList &attr); - bool CheckNoCallerSavedRegsAttr(const AttributeList &attr); - bool checkStringLiteralArgumentAttr(const AttributeList &Attr, - unsigned ArgNum, StringRef &Str, + bool CheckAttrTarget(const ParsedAttr &CurrAttr); + bool CheckAttrNoArgs(const ParsedAttr &CurrAttr); + bool checkStringLiteralArgumentAttr(const ParsedAttr &Attr, unsigned ArgNum, + StringRef &Str, SourceLocation *ArgLocation = nullptr); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); @@ -3377,8 +3404,9 @@ public: bool isContextSensitive, bool allowArrayTypes); - /// \brief Stmt attributes - this routine is the top level dispatcher. - StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs, + /// Stmt attributes - this routine is the top level dispatcher. + StmtResult ProcessStmtAttributes(Stmt *Stmt, + const ParsedAttributesView &Attrs, SourceRange Range); void WarnConflictingTypedMethods(ObjCMethodDecl *Method, @@ -3520,7 +3548,7 @@ public: /// warns each time an exact match is found. void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); - /// \brief Add the given method to the list of globally-known methods. + /// Add the given method to the list of globally-known methods. void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); private: @@ -3535,7 +3563,7 @@ private: bool instance); public: - /// \brief - Returns instance or factory methods in global method pool for + /// - Returns instance or factory methods in global method pool for /// given selector. It checks the desired kind first, if none is found, and /// parameter checkTheOther is set, it then checks the other kind. If no such /// method or only one method is found, function returns false; otherwise, it @@ -3557,14 +3585,14 @@ public: bool receiverIdOrClass); private: - /// \brief - Returns a selector which best matches given argument list or + /// - Returns a selector which best matches given argument list or /// nullptr if none could be found ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance, SmallVectorImpl<ObjCMethodDecl*>& Methods); - /// \brief Record the typo correction failure and return an empty correction. + /// Record the typo correction failure and return an empty correction. TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc, bool RecordFailure = true) { if (RecordFailure) @@ -3664,16 +3692,16 @@ public: StmtResult ActOnNullStmt(SourceLocation SemiLoc, bool HasLeadingEmptyMacro = false); - void ActOnStartOfCompoundStmt(); + void ActOnStartOfCompoundStmt(bool IsStmtExpr); void ActOnFinishOfCompoundStmt(); StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef<Stmt *> Elts, bool isStmtExpr); - /// \brief A RAII object to enter scope of a compound statement. + /// A RAII object to enter scope of a compound statement. class CompoundScopeRAII { public: - CompoundScopeRAII(Sema &S): S(S) { - S.ActOnStartOfCompoundStmt(); + CompoundScopeRAII(Sema &S, bool IsStmtExpr = false) : S(S) { + S.ActOnStartOfCompoundStmt(IsStmtExpr); } ~CompoundScopeRAII() { @@ -3701,9 +3729,10 @@ public: SourceLocation EndLoc); void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); StmtResult ActOnForEachLValueExpr(Expr *E); - StmtResult ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, - SourceLocation DotDotDotLoc, Expr *RHSVal, - SourceLocation ColonLoc); + ExprResult ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val); + StmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprResult LHS, + SourceLocation DotDotDotLoc, ExprResult RHS, + SourceLocation ColonLoc); void ActOnCaseStmtBody(Stmt *CaseStmt, Stmt *SubStmt); StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, @@ -3797,10 +3826,22 @@ public: RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, unsigned NumParams); + + enum CopyElisionSemanticsKind { + CES_Strict = 0, + CES_AllowParameters = 1, + CES_AllowDifferentTypes = 2, + CES_AllowExceptionVariables = 4, + CES_FormerDefault = (CES_AllowParameters), + CES_Default = (CES_AllowParameters | CES_AllowDifferentTypes), + CES_AsIfByStdMove = (CES_AllowParameters | CES_AllowDifferentTypes | + CES_AllowExceptionVariables), + }; + VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, - bool AllowParamOrMoveConstructible); + CopyElisionSemanticsKind CESK); bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, - bool AllowParamOrMoveConstructible); + CopyElisionSemanticsKind CESK); StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, Scope *CurScope); @@ -3889,7 +3930,7 @@ public: bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; - /// \brief If it's a file scoped decl that must warn if not used, keep track + /// If it's a file scoped decl that must warn if not used, keep track /// of it. void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); @@ -3918,7 +3959,7 @@ public: void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation OpLoc); - /// \brief Warn if we're implicitly casting from a _Nullable pointer type to a + /// Warn if we're implicitly casting from a _Nullable pointer type to a /// _Nonnull one. void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, SourceLocation Loc); @@ -3941,7 +3982,7 @@ public: void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); - void DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, + void DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks = false); @@ -3949,14 +3990,14 @@ public: bool makeUnavailableInSystemHeader(SourceLocation loc, UnavailableAttr::ImplicitReason reason); - /// \brief Issue any -Wunguarded-availability warnings in \c FD + /// Issue any -Wunguarded-availability warnings in \c FD void DiagnoseUnguardedAvailabilityViolations(Decl *FD); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid); - bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, + bool DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass = nullptr, bool ObjCPropertyAccess = false, bool AvoidPartialAvailabilityChecks = false); @@ -3969,13 +4010,15 @@ public: void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ArrayRef<Expr *> Args); - void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, - Decl *LambdaContextDecl = nullptr, - bool IsDecltype = false); + void PushExpressionEvaluationContext( + ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, + ExpressionEvaluationContextRecord::ExpressionKind Type = + ExpressionEvaluationContextRecord::EK_Other); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; - void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, - ReuseLambdaContextDecl_t, - bool IsDecltype = false); + void PushExpressionEvaluationContext( + ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, + ExpressionEvaluationContextRecord::ExpressionKind Type = + ExpressionEvaluationContextRecord::EK_Other); void PopExpressionEvaluationContext(); void DiscardCleanupsInEvaluationContext(); @@ -4011,7 +4054,7 @@ public: TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef }; - /// \brief Try to capture the given variable. + /// Try to capture the given variable. /// /// \param Var The variable to capture. /// @@ -4050,15 +4093,15 @@ public: QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt); - /// \brief Try to capture the given variable. + /// Try to capture the given variable. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind = TryCapture_Implicit, SourceLocation EllipsisLoc = SourceLocation()); - /// \brief Checks if the variable must be captured. + /// Checks if the variable must be captured. bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc); - /// \brief Given a variable, determine the type that a reference to that + /// Given a variable, determine the type that a reference to that /// variable will have in the given scope. QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); @@ -4069,18 +4112,18 @@ public: void MarkDeclarationsReferencedInExpr(Expr *E, bool SkipLocalVariables = false); - /// \brief Try to recover by turning the given expression into a + /// Try to recover by turning the given expression into a /// call. Returns true if recovery was attempted or an error was /// emitted; this may also leave the ExprResult invalid. bool tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain = false, bool (*IsPlausibleResult)(QualType) = nullptr); - /// \brief Figure out if an expression could be turned into a call. + /// Figure out if an expression could be turned into a call. bool tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, UnresolvedSetImpl &NonTemplateOverloads); - /// \brief Conditionally issue a diagnostic based on the current + /// Conditionally issue a diagnostic based on the current /// evaluation context. /// /// \param Statement If Statement is non-null, delay reporting the @@ -4222,6 +4265,7 @@ public: ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, Expr *Input); + bool isQualifiedMemberAccess(Expr *E); QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc); ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, @@ -4354,7 +4398,7 @@ public: Expr *Op); CastKind PrepareScalarCast(ExprResult &src, QualType destType); - /// \brief Build an altivec or OpenCL literal. + /// Build an altivec or OpenCL literal. ExprResult BuildVectorLiteral(SourceLocation LParenLoc, SourceLocation RParenLoc, Expr *E, TypeSourceInfo *TInfo); @@ -4446,19 +4490,19 @@ public: bool CheckCaseExpression(Expr *E); - /// \brief Describes the result of an "if-exists" condition check. + /// Describes the result of an "if-exists" condition check. enum IfExistsResult { - /// \brief The symbol exists. + /// The symbol exists. IER_Exists, - /// \brief The symbol does not exist. + /// The symbol does not exist. IER_DoesNotExist, - /// \brief The name is a dependent name, so the results will differ + /// The name is a dependent name, so the results will differ /// from one instantiation to the next. IER_Dependent, - /// \brief An error occurred. + /// An error occurred. IER_Error }; @@ -4520,11 +4564,10 @@ public: // Act on C++ namespaces Decl *ActOnStartNamespaceDef(Scope *S, SourceLocation InlineLoc, SourceLocation NamespaceLoc, - SourceLocation IdentLoc, - IdentifierInfo *Ident, + SourceLocation IdentLoc, IdentifierInfo *Ident, SourceLocation LBrace, - AttributeList *AttrList, - UsingDirectiveDecl * &UsingDecl); + const ParsedAttributesView &AttrList, + UsingDirectiveDecl *&UsingDecl); void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace); NamespaceDecl *getStdNamespace() const; @@ -4535,27 +4578,41 @@ public: CXXRecordDecl *getStdBadAlloc() const; EnumDecl *getStdAlignValT() const; - /// \brief Tests whether Ty is an instance of std::initializer_list and, if +private: + // A cache representing if we've fully checked the various comparison category + // types stored in ASTContext. The bit-index corresponds to the integer value + // of a ComparisonCategoryType enumerator. + llvm::SmallBitVector FullyCheckedComparisonCategories; + +public: + /// Lookup the specified comparison category types in the standard + /// library, an check the VarDecls possibly returned by the operator<=> + /// builtins for that type. + /// + /// \return The type of the comparison category type corresponding to the + /// specified Kind, or a null type if an error occurs + QualType CheckComparisonCategoryType(ComparisonCategoryType Kind, + SourceLocation Loc); + + /// Tests whether Ty is an instance of std::initializer_list and, if /// it is and Element is not NULL, assigns the element type to Element. bool isStdInitializerList(QualType Ty, QualType *Element); - /// \brief Looks for the std::initializer_list template and instantiates it + /// Looks for the std::initializer_list template and instantiates it /// with Element, or emits an error if it's not found. /// /// \returns The instantiated template, or null on error. QualType BuildStdInitializerList(QualType Element, SourceLocation Loc); - /// \brief Determine whether Ctor is an initializer-list constructor, as + /// Determine whether Ctor is an initializer-list constructor, as /// defined in [dcl.init.list]p2. bool isInitListConstructor(const FunctionDecl *Ctor); - Decl *ActOnUsingDirective(Scope *CurScope, - SourceLocation UsingLoc, - SourceLocation NamespcLoc, - CXXScopeSpec &SS, + Decl *ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, + SourceLocation NamespcLoc, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, - AttributeList *AttrList); + const ParsedAttributesView &AttrList); void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); @@ -4586,15 +4643,11 @@ public: const DeclarationNameInfo &NameInfo, SourceLocation NameLoc); - NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, - SourceLocation UsingLoc, - bool HasTypenameKeyword, - SourceLocation TypenameLoc, - CXXScopeSpec &SS, - DeclarationNameInfo NameInfo, - SourceLocation EllipsisLoc, - AttributeList *AttrList, - bool IsInstantiation); + NamedDecl *BuildUsingDeclaration( + Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, + bool HasTypenameKeyword, SourceLocation TypenameLoc, CXXScopeSpec &SS, + DeclarationNameInfo NameInfo, SourceLocation EllipsisLoc, + const ParsedAttributesView &AttrList, bool IsInstantiation); NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom, ArrayRef<NamedDecl *> Expansions); @@ -4607,22 +4660,16 @@ public: findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *BaseCtor, ConstructorUsingShadowDecl *DerivedShadow); - Decl *ActOnUsingDeclaration(Scope *CurScope, - AccessSpecifier AS, + Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, SourceLocation UsingLoc, - SourceLocation TypenameLoc, - CXXScopeSpec &SS, - UnqualifiedId &Name, - SourceLocation EllipsisLoc, - AttributeList *AttrList); - Decl *ActOnAliasDeclaration(Scope *CurScope, - AccessSpecifier AS, + SourceLocation TypenameLoc, CXXScopeSpec &SS, + UnqualifiedId &Name, SourceLocation EllipsisLoc, + const ParsedAttributesView &AttrList); + Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, MultiTemplateParamsArg TemplateParams, - SourceLocation UsingLoc, - UnqualifiedId &Name, - AttributeList *AttrList, - TypeResult Type, - Decl *DeclFromDeclSpec); + SourceLocation UsingLoc, UnqualifiedId &Name, + const ParsedAttributesView &AttrList, + TypeResult Type, Decl *DeclFromDeclSpec); /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. @@ -4677,7 +4724,7 @@ public: /// constructed variable. void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); - /// \brief Helper class that collects exception specifications for + /// Helper class that collects exception specifications for /// implicitly-declared special member functions. class ImplicitExceptionSpecification { // Pointer to allow copying @@ -4704,26 +4751,26 @@ public: ComputedEST = EST_DynamicNone; } - /// \brief Get the computed exception specification type. + /// Get the computed exception specification type. ExceptionSpecificationType getExceptionSpecType() const { - assert(ComputedEST != EST_ComputedNoexcept && + assert(!isComputedNoexcept(ComputedEST) && "noexcept(expr) should not be a possible result"); return ComputedEST; } - /// \brief The number of exceptions in the exception specification. + /// The number of exceptions in the exception specification. unsigned size() const { return Exceptions.size(); } - /// \brief The set of exceptions in the exception specification. + /// The set of exceptions in the exception specification. const QualType *data() const { return Exceptions.data(); } - /// \brief Integrate another called method into the collected data. + /// Integrate another called method into the collected data. void CalledDecl(SourceLocation CallLoc, const CXXMethodDecl *Method); - /// \brief Integrate an invoked expression into the collected data. + /// Integrate an invoked expression into the collected data. void CalledExpr(Expr *E); - /// \brief Overwrite an EPI's exception specification with this + /// Overwrite an EPI's exception specification with this /// computed exception specification. FunctionProtoType::ExceptionSpecInfo getExceptionSpec() const { FunctionProtoType::ExceptionSpecInfo ESI; @@ -4734,7 +4781,7 @@ public: /// C++11 [except.spec]p14: /// The exception-specification is noexcept(false) if the set of /// potential exceptions of the special member function contains "any" - ESI.Type = EST_ComputedNoexcept; + ESI.Type = EST_NoexceptFalse; ESI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(), tok::kw_false).get(); } @@ -4742,50 +4789,55 @@ public: } }; - /// \brief Determine what sort of exception specification a defaulted + /// Determine what sort of exception specification a defaulted /// copy constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); - /// \brief Determine what sort of exception specification a defaulted + /// Determine what sort of exception specification a defaulted /// default constructor of a class will have, and whether the parameter /// will be const. ImplicitExceptionSpecification ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD); - /// \brief Determine what sort of exception specification a defautled + /// Determine what sort of exception specification a defautled /// copy assignment operator of a class will have, and whether the /// parameter will be const. ImplicitExceptionSpecification ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD); - /// \brief Determine what sort of exception specification a defaulted move + /// Determine what sort of exception specification a defaulted move /// constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD); - /// \brief Determine what sort of exception specification a defaulted move + /// Determine what sort of exception specification a defaulted move /// assignment operator of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD); - /// \brief Determine what sort of exception specification a defaulted + /// Determine what sort of exception specification a defaulted /// destructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD); - /// \brief Determine what sort of exception specification an inheriting + /// Determine what sort of exception specification an inheriting /// constructor of a class will have. ImplicitExceptionSpecification ComputeInheritingCtorExceptionSpec(SourceLocation Loc, CXXConstructorDecl *CD); - /// \brief Evaluate the implicit exception specification for a defaulted + /// Evaluate the implicit exception specification for a defaulted /// special member function. void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); - /// \brief Check the given exception-specification and update the + /// Check the given noexcept-specifier, convert its expression, and compute + /// the appropriate ExceptionSpecificationType. + ExprResult ActOnNoexceptSpec(SourceLocation NoexceptLoc, Expr *NoexceptExpr, + ExceptionSpecificationType &EST); + + /// Check the given exception-specification and update the /// exception specification information with the results. void checkExceptionSpecification(bool IsTopLevel, ExceptionSpecificationType EST, @@ -4795,11 +4847,11 @@ public: SmallVectorImpl<QualType> &Exceptions, FunctionProtoType::ExceptionSpecInfo &ESI); - /// \brief Determine if we're in a case where we need to (incorrectly) eagerly + /// Determine if we're in a case where we need to (incorrectly) eagerly /// parse an exception specification to work around a libstdc++ bug. bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D); - /// \brief Add an exception-specification to the given member function + /// Add an exception-specification to the given member function /// (or member function template). The exception-specification was parsed /// after the method itself was declared. void actOnDelayedExceptionSpecification(Decl *Method, @@ -4811,13 +4863,13 @@ public: class InheritedConstructorInfo; - /// \brief Determine if a special member function should have a deleted + /// Determine if a special member function should have a deleted /// definition when it is defaulted. bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, InheritedConstructorInfo *ICI = nullptr, bool Diagnose = false); - /// \brief Declare the implicit default constructor for the given class. + /// Declare the implicit default constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// default constructor will be added. @@ -4831,7 +4883,7 @@ public: void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); - /// \brief Declare the implicit destructor for the given class. + /// Declare the implicit destructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// destructor will be added. @@ -4844,18 +4896,18 @@ public: void DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor); - /// \brief Build an exception spec for destructors that don't have one. + /// Build an exception spec for destructors that don't have one. /// /// C++11 says that user-defined destructors with no exception spec get one /// that looks as if the destructor was implicitly declared. void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, CXXDestructorDecl *Destructor); - /// \brief Define the specified inheriting constructor. + /// Define the specified inheriting constructor. void DefineInheritingConstructor(SourceLocation UseLoc, CXXConstructorDecl *Constructor); - /// \brief Declare the implicit copy constructor for the given class. + /// Declare the implicit copy constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy constructor will be added. @@ -4868,7 +4920,7 @@ public: void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); - /// \brief Declare the implicit move constructor for the given class. + /// Declare the implicit move constructor for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move constructor will be added. @@ -4882,7 +4934,7 @@ public: void DefineImplicitMoveConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); - /// \brief Declare the implicit copy assignment operator for the given class. + /// Declare the implicit copy assignment operator for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy assignment operator will be added. @@ -4890,11 +4942,11 @@ public: /// \returns The implicitly-declared copy assignment operator. CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl); - /// \brief Defines an implicitly-declared copy assignment operator. + /// Defines an implicitly-declared copy assignment operator. void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); - /// \brief Declare the implicit move assignment operator for the given class. + /// Declare the implicit move assignment operator for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move assignment operator will be added. @@ -4903,32 +4955,32 @@ public: /// wasn't declared. CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl); - /// \brief Defines an implicitly-declared move assignment operator. + /// Defines an implicitly-declared move assignment operator. void DefineImplicitMoveAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); - /// \brief Force the declaration of any implicitly-declared members of this + /// Force the declaration of any implicitly-declared members of this /// class. void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class); - /// \brief Check a completed declaration of an implicit special member. + /// Check a completed declaration of an implicit special member. void CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD); - /// \brief Determine whether the given function is an implicitly-deleted + /// Determine whether the given function is an implicitly-deleted /// special member function. bool isImplicitlyDeleted(FunctionDecl *FD); - /// \brief Check whether 'this' shows up in the type of a static member + /// Check whether 'this' shows up in the type of a static member /// function after the (naturally empty) cv-qualifier-seq would be. /// /// \returns true if an error occurred. bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method); - /// \brief Whether this' shows up in the exception specification of a static + /// Whether this' shows up in the exception specification of a static /// member function. bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method); - /// \brief Check whether 'this' shows up in the attributes of the given + /// Check whether 'this' shows up in the attributes of the given /// static member function. /// /// \returns true if an error occurred. @@ -4950,6 +5002,9 @@ public: SourceLocation NameLoc, IdentifierInfo &Name); + ParsedType getConstructorName(IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, CXXScopeSpec &SS, + bool EnteringContext); ParsedType getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, @@ -5010,7 +5065,7 @@ public: void *TyOrExpr, SourceLocation RParenLoc); - /// \brief Handle a C++1z fold-expression: ( expr op ... op expr ). + /// Handle a C++1z fold-expression: ( expr op ... op expr ). ExprResult ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, tok::TokenKind Operator, SourceLocation EllipsisLoc, Expr *RHS, @@ -5025,17 +5080,17 @@ public: //// ActOnCXXThis - Parse 'this' pointer. ExprResult ActOnCXXThis(SourceLocation loc); - /// \brief Try to retrieve the type of the 'this' pointer. + /// Try to retrieve the type of the 'this' pointer. /// /// \returns The type of 'this', if possible. Otherwise, returns a NULL type. QualType getCurrentThisType(); - /// \brief When non-NULL, the C++ 'this' expression is allowed despite the + /// When non-NULL, the C++ 'this' expression is allowed despite the /// current context not being a non-static member function. In such cases, /// this provides the type used for 'this'. QualType CXXThisTypeOverride; - /// \brief RAII object used to temporarily allow the C++ 'this' expression + /// RAII object used to temporarily allow the C++ 'this' expression /// to be used, with the given qualifiers on the current class type. class CXXThisScopeRAII { Sema &S; @@ -5043,7 +5098,7 @@ public: bool Enabled; public: - /// \brief Introduce a new scope where 'this' may be allowed (when enabled), + /// Introduce a new scope where 'this' may be allowed (when enabled), /// using the given declaration (which is either a class template or a /// class) along with the given qualifiers. /// along with the qualifiers placed on '*this'. @@ -5053,7 +5108,7 @@ public: ~CXXThisScopeRAII(); }; - /// \brief Make sure the value of 'this' is actually available in the current + /// Make sure the value of 'this' is actually available in the current /// context, if it is a potentially evaluated context. /// /// \param Loc The location at which the capture of 'this' occurs. @@ -5073,7 +5128,7 @@ public: const unsigned *const FunctionScopeIndexToStopAt = nullptr, bool ByCopy = false); - /// \brief Determine whether the given type is the type of *this that is used + /// Determine whether the given type is the type of *this that is used /// outside of the body of a member function for a type that is currently /// being defined. bool isThisOutsideMemberFunctionBody(QualType BaseType); @@ -5103,14 +5158,16 @@ public: /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, - SourceLocation LParenLoc, + SourceLocation LParenOrBraceLoc, MultiExprArg Exprs, - SourceLocation RParenLoc); + SourceLocation RParenOrBraceLoc, + bool ListInitialization); ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, MultiExprArg Exprs, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + bool ListInitialization); /// ActOnCXXNew - Parsed a C++ 'new' expression. ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, @@ -5132,11 +5189,29 @@ public: bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R); + + /// The scope in which to find allocation functions. + enum AllocationFunctionScope { + /// Only look for allocation functions in the global scope. + AFS_Global, + /// Only look for allocation functions in the scope of the + /// allocated class. + AFS_Class, + /// Look for allocation functions in both the global scope + /// and in the scope of the allocated class. + AFS_Both + }; + + /// Finds the overloads of operator new and delete that are appropriate + /// for the allocation. bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, - bool UseGlobal, QualType AllocType, bool IsArray, + AllocationFunctionScope NewScope, + AllocationFunctionScope DeleteScope, + QualType AllocType, bool IsArray, bool &PassAlignment, MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, - FunctionDecl *&OperatorDelete); + FunctionDecl *&OperatorDelete, + bool Diagnose = true); void DeclareGlobalNewDelete(); void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, ArrayRef<QualType> Params); @@ -5165,7 +5240,7 @@ public: ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen); - /// \brief Parsed one of the type trait support pseudo-functions. + /// Parsed one of the type trait support pseudo-functions. ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef<ParsedType> Args, SourceLocation RParenLoc); @@ -5260,7 +5335,7 @@ public: bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); - /// \brief The parser has parsed a global nested-name-specifier '::'. + /// The parser has parsed a global nested-name-specifier '::'. /// /// \param CCLoc The location of the '::'. /// @@ -5270,7 +5345,7 @@ public: /// \returns true if an error occurred, false otherwise. bool ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS); - /// \brief The parser has parsed a '__super' nested-name-specifier. + /// The parser has parsed a '__super' nested-name-specifier. /// /// \param SuperLoc The location of the '__super' keyword. /// @@ -5287,23 +5362,23 @@ public: bool *CanCorrect = nullptr); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); - /// \brief Keeps information about an identifier in a nested-name-spec. + /// Keeps information about an identifier in a nested-name-spec. /// struct NestedNameSpecInfo { - /// \brief The type of the object, if we're parsing nested-name-specifier in + /// The type of the object, if we're parsing nested-name-specifier in /// a member access expression. ParsedType ObjectType; - /// \brief The identifier preceding the '::'. + /// The identifier preceding the '::'. IdentifierInfo *Identifier; - /// \brief The location of the identifier. + /// The location of the identifier. SourceLocation IdentifierLoc; - /// \brief The location of the '::'. + /// The location of the '::'. SourceLocation CCLoc; - /// \brief Creates info object for the most typical case. + /// Creates info object for the most typical case. NestedNameSpecInfo(IdentifierInfo *II, SourceLocation IdLoc, SourceLocation ColonColonLoc, ParsedType ObjectType = ParsedType()) : ObjectType(ObjectType), Identifier(II), IdentifierLoc(IdLoc), @@ -5329,7 +5404,7 @@ public: bool *IsCorrectedToColon = nullptr, bool OnlyNamespace = false); - /// \brief The parser has parsed a nested-name-specifier 'identifier::'. + /// The parser has parsed a nested-name-specifier 'identifier::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// @@ -5372,7 +5447,7 @@ public: NestedNameSpecInfo &IdInfo, bool EnteringContext); - /// \brief The parser has parsed a nested-name-specifier + /// The parser has parsed a nested-name-specifier /// 'template[opt] template-name < template-args >::'. /// /// \param S The scope in which this nested-name-specifier occurs. @@ -5406,7 +5481,7 @@ public: SourceLocation CCLoc, bool EnteringContext); - /// \brief Given a C++ nested-name-specifier, produce an annotation value + /// Given a C++ nested-name-specifier, produce an annotation value /// that the parser can use later to reconstruct the given /// nested-name-specifier. /// @@ -5416,7 +5491,7 @@ public: /// nested-name-specifier \p SS. void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS); - /// \brief Given an annotation pointer for a nested-name-specifier, restore + /// Given an annotation pointer for a nested-name-specifier, restore /// the nested-name-specifier structure. /// /// \param Annotation The annotation pointer, produced by @@ -5458,13 +5533,13 @@ public: /// initializer for the declaration 'Dcl'. void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); - /// \brief Create a new lambda closure type. + /// Create a new lambda closure type. CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info, bool KnownDependent, LambdaCaptureDefault CaptureDefault); - /// \brief Start the definition of a lambda expression. + /// Start the definition of a lambda expression. CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, @@ -5472,7 +5547,7 @@ public: ArrayRef<ParmVarDecl *> Params, bool IsConstexprSpecified); - /// \brief Endow the lambda scope info with the relevant properties. + /// Endow the lambda scope info with the relevant properties. void buildLambdaScope(sema::LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, SourceRange IntroducerRange, @@ -5482,7 +5557,7 @@ public: bool ExplicitResultType, bool Mutable); - /// \brief Perform initialization analysis of the init-capture and perform + /// Perform initialization analysis of the init-capture and perform /// any implicit conversions such as an lvalue-to-rvalue conversion if /// not being used to initialize a reference. ParsedType actOnLambdaInitCaptureInitialization( @@ -5495,7 +5570,7 @@ public: IdentifierInfo *Id, bool DirectInit, Expr *&Init); - /// \brief Create a dummy variable within the declcontext of the lambda's + /// Create a dummy variable within the declcontext of the lambda's /// call operator, for name lookup purposes for a lambda init capture. /// /// CodeGen handles emission of lambda captures, ignoring these dummy @@ -5505,17 +5580,17 @@ public: IdentifierInfo *Id, unsigned InitStyle, Expr *Init); - /// \brief Build the implicit field for an init-capture. + /// Build the implicit field for an init-capture. FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var); - /// \brief Note that we have finished the explicit captures for the + /// Note that we have finished the explicit captures for the /// given lambda. void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); - /// \brief Introduce the lambda parameters into scope. + /// Introduce the lambda parameters into scope. void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope); - /// \brief Deduce a block or lambda's return type based on the return + /// Deduce a block or lambda's return type based on the return /// statements present in the body. void deduceClosureReturnType(sema::CapturingScopeInfo &CSI); @@ -5536,13 +5611,15 @@ public: ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope); - /// \brief Does copying/destroying the captured variable have side effects? - bool CaptureHasSideEffects(const sema::LambdaScopeInfo::Capture &From); + /// Does copying/destroying the captured variable have side effects? + bool CaptureHasSideEffects(const sema::Capture &From); - /// \brief Diagnose if an explicit lambda capture is unused. - void DiagnoseUnusedLambdaCapture(const sema::LambdaScopeInfo::Capture &From); + /// Diagnose if an explicit lambda capture is unused. Returns true if a + /// diagnostic is emitted. + bool DiagnoseUnusedLambdaCapture(SourceRange CaptureRange, + const sema::Capture &From); - /// \brief Complete a lambda-expression having processed and attached the + /// Complete a lambda-expression having processed and attached the /// lambda body. ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, sema::LambdaScopeInfo *LSI); @@ -5552,7 +5629,7 @@ public: QualType getLambdaConversionFunctionResultType(const FunctionProtoType *CallOpType); - /// \brief Define the "body" of the conversion from a lambda object to a + /// Define the "body" of the conversion from a lambda object to a /// function pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills @@ -5562,7 +5639,7 @@ public: void DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLoc, CXXConversionDecl *Conv); - /// \brief Define the "body" of the conversion from a lambda object to a + /// Define the "body" of the conversion from a lambda object to a /// block pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills @@ -5650,14 +5727,14 @@ public: //===--------------------------------------------------------------------===// // C++ Classes // + CXXRecordDecl *getCurrentClass(Scope *S, const CXXScopeSpec *SS); bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = nullptr); bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS); - bool ActOnAccessSpecifier(AccessSpecifier Access, - SourceLocation ASLoc, + bool ActOnAccessSpecifier(AccessSpecifier Access, SourceLocation ASLoc, SourceLocation ColonLoc, - AttributeList *Attrs = nullptr); + const ParsedAttributesView &Attrs); NamedDecl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, @@ -5731,30 +5808,30 @@ public: void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, CXXRecordDecl *Record); - /// \brief The list of classes whose vtables have been used within + /// The list of classes whose vtables have been used within /// this translation unit, and the source locations at which the /// first use occurred. typedef std::pair<CXXRecordDecl*, SourceLocation> VTableUse; - /// \brief The list of vtables that are required but have not yet been + /// The list of vtables that are required but have not yet been /// materialized. SmallVector<VTableUse, 16> VTableUses; - /// \brief The set of classes whose vtables have been used within + /// The set of classes whose vtables have been used within /// this translation unit, and a bit that will be true if the vtable is /// required to be emitted (otherwise, it should be emitted only if needed /// by code generation). llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed; - /// \brief Load any externally-stored vtable uses. + /// Load any externally-stored vtable uses. void LoadExternalVTableUses(); - /// \brief Note that the vtable for the given class was used at the + /// Note that the vtable for the given class was used at the /// given location. void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired = false); - /// \brief Mark the exception specifications of all virtual member functions + /// Mark the exception specifications of all virtual member functions /// in the given class as needed. void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, const CXXRecordDecl *RD); @@ -5764,7 +5841,7 @@ public: void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD); - /// \brief Define all of the vtables that have been used in this + /// Define all of the vtables that have been used in this /// translation unit and reference any virtual members used by those /// vtables. /// @@ -5778,10 +5855,11 @@ public: ArrayRef<CXXCtorInitializer*> MemInits, bool AnyErrors); - /// \brief Check class-level dllimport/dllexport attribute. The caller must + /// Check class-level dllimport/dllexport attribute. The caller must /// ensure that referenceDLLExportedClassMethods is called some point later /// when all outer classes of Class are complete. void checkClassLevelDLLAttribute(CXXRecordDecl *Class); + void checkClassLevelCodeSegAttribute(CXXRecordDecl *Class); void referenceDLLExportedClassMethods(); @@ -5791,11 +5869,15 @@ public: SourceLocation BaseLoc); void CheckCompletedCXXClass(CXXRecordDecl *Record); - void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, - Decl *TagDecl, - SourceLocation LBrac, + + /// Check that the C++ class annoated with "trivial_abi" satisfies all the + /// conditions that are needed for the attribute to have an effect. + void checkIllFormedTrivialABIStruct(CXXRecordDecl &RD); + + void ActOnFinishCXXMemberSpecification(Scope *S, SourceLocation RLoc, + Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, - AttributeList *AttrList); + const ParsedAttributesView &AttrList); void ActOnFinishCXXMemberDecls(); void ActOnFinishCXXNonNestedClass(Decl *D); @@ -5989,7 +6071,7 @@ public: void HandleDelayedAccessCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); - /// \brief When true, access checking violations are treated as SFINAE + /// When true, access checking violations are treated as SFINAE /// failures rather than hard errors. bool AccessCheckingSFINAE; @@ -6032,14 +6114,15 @@ public: bool hasAnyAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true); - void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, + bool LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, - bool &MemberOfUnknownSpecialization); + bool &MemberOfUnknownSpecialization, + SourceLocation TemplateKWLoc = SourceLocation()); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, - UnqualifiedId &Name, + const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, @@ -6107,7 +6190,7 @@ public: SourceLocation RAngleLoc, Expr *RequiresClause); - /// \brief The context in which we are checking a template parameter list. + /// The context in which we are checking a template parameter list. enum TemplateParamListContext { TPC_ClassTemplate, TPC_VarTemplate, @@ -6128,17 +6211,14 @@ public: ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend, bool &IsMemberSpecialization, bool &Invalid); - DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, - TemplateParameterList *TemplateParams, - AccessSpecifier AS, - SourceLocation ModulePrivateLoc, - SourceLocation FriendLoc, - unsigned NumOuterTemplateParamLists, - TemplateParameterList **OuterTemplateParamLists, - SkipBodyInfo *SkipBody = nullptr); + DeclResult CheckClassTemplate( + Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, + const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, + AccessSpecifier AS, SourceLocation ModulePrivateLoc, + SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, + TemplateParameterList **OuterTemplateParamLists, + SkipBodyInfo *SkipBody = nullptr); TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, QualType NTTPType, @@ -6147,6 +6227,8 @@ public: void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); + ParsedTemplateArgument ActOnTemplateTypeArgument(TypeResult ParsedType); + void NoteAllFoundTemplates(TemplateName Name); QualType CheckTemplateIdType(TemplateName Template, @@ -6163,7 +6245,7 @@ public: bool IsCtorOrDtorName = false, bool IsClassName = false); - /// \brief Parsed an elaborated-type-specifier that refers to a template-id, + /// Parsed an elaborated-type-specifier that refers to a template-id, /// such as \c class T::template apply<U>. TypeResult ActOnTagTemplateIdType(TagUseKind TUK, TypeSpecifierType TagSpec, @@ -6192,6 +6274,8 @@ public: SourceLocation TemplateLoc, const TemplateArgumentListInfo *TemplateArgs); + void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc); + ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -6205,17 +6289,15 @@ public: TemplateNameKind ActOnDependentTemplateName( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, + const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool AllowInjectedClassName = false); - DeclResult - ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, - SourceLocation ModulePrivateLoc, - TemplateIdAnnotation &TemplateId, - AttributeList *Attr, - MultiTemplateParamsArg TemplateParameterLists, - SkipBodyInfo *SkipBody = nullptr); + DeclResult ActOnClassTemplateSpecialization( + Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, + const ParsedAttributesView &Attr, + MultiTemplateParamsArg TemplateParameterLists, + SkipBodyInfo *SkipBody = nullptr); bool CheckTemplatePartialSpecializationArgs(SourceLocation Loc, TemplateDecl *PrimaryTemplate, @@ -6248,30 +6330,19 @@ public: bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous); - DeclResult - ActOnExplicitInstantiation(Scope *S, - SourceLocation ExternLoc, - SourceLocation TemplateLoc, - unsigned TagSpec, - SourceLocation KWLoc, - const CXXScopeSpec &SS, - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation RAngleLoc, - AttributeList *Attr); + DeclResult ActOnExplicitInstantiation( + Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, + TemplateTy Template, SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, const ParsedAttributesView &Attr); - DeclResult - ActOnExplicitInstantiation(Scope *S, - SourceLocation ExternLoc, - SourceLocation TemplateLoc, - unsigned TagSpec, - SourceLocation KWLoc, - CXXScopeSpec &SS, - IdentifierInfo *Name, - SourceLocation NameLoc, - AttributeList *Attr); + DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, + CXXScopeSpec &SS, IdentifierInfo *Name, + SourceLocation NameLoc, + const ParsedAttributesView &Attr); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, @@ -6287,18 +6358,18 @@ public: &Converted, bool &HasDefaultArg); - /// \brief Specifies the context in which a particular template + /// Specifies the context in which a particular template /// argument is being checked. enum CheckTemplateArgumentKind { - /// \brief The template argument was specified in the code or was + /// The template argument was specified in the code or was /// instantiated with some deduced template arguments. CTAK_Specified, - /// \brief The template argument was deduced via template argument + /// The template argument was deduced via template argument /// deduction. CTAK_Deduced, - /// \brief The template argument was deduced from an array bound + /// The template argument was deduced from an array bound /// via template argument deduction. CTAK_DeducedFromArrayBound }; @@ -6312,7 +6383,7 @@ public: SmallVectorImpl<TemplateArgument> &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); - /// \brief Check that the given template arguments can be be provided to + /// Check that the given template arguments can be be provided to /// the given template, converting the arguments along the way. /// /// \param Template The template to which the template arguments are being @@ -6354,9 +6425,8 @@ public: QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); - bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, - TemplateArgumentLoc &Arg, - unsigned ArgumentPackIndex); + bool CheckTemplateTemplateArgument(TemplateParameterList *Params, + TemplateArgumentLoc &Arg); ExprResult BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, @@ -6366,10 +6436,10 @@ public: BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc); - /// \brief Enumeration describing how template parameter lists are compared + /// Enumeration describing how template parameter lists are compared /// for equality. enum TemplateParameterListEqualKind { - /// \brief We are matching the template parameter lists of two templates + /// We are matching the template parameter lists of two templates /// that might be redeclarations. /// /// \code @@ -6378,7 +6448,7 @@ public: /// \endcode TPL_TemplateMatch, - /// \brief We are matching the template parameter lists of two template + /// We are matching the template parameter lists of two template /// template parameters as part of matching the template parameter lists /// of two templates that might be redeclarations. /// @@ -6388,7 +6458,7 @@ public: /// \endcode TPL_TemplateTemplateParmMatch, - /// \brief We are matching the template parameter lists of a template + /// We are matching the template parameter lists of a template /// template argument against the template parameter lists of a template /// template parameter. /// @@ -6409,7 +6479,7 @@ public: bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); - /// \brief Called when the parser has parsed a C++ typename + /// Called when the parser has parsed a C++ typename /// specifier, e.g., "typename T::type". /// /// \param S The scope in which this typename type occurs. @@ -6422,7 +6492,7 @@ public: const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc); - /// \brief Called when the parser has parsed a C++ typename + /// Called when the parser has parsed a C++ typename /// specifier that ends in a template-id, e.g., /// "typename MetaFun::template apply<T1, T2>". /// @@ -6479,74 +6549,74 @@ public: /// location. Useful for error recovery. bool isUnexpandedParameterPackPermitted(); - /// \brief The context in which an unexpanded parameter pack is + /// The context in which an unexpanded parameter pack is /// being diagnosed. /// /// Note that the values of this enumeration line up with the first /// argument to the \c err_unexpanded_parameter_pack diagnostic. enum UnexpandedParameterPackContext { - /// \brief An arbitrary expression. + /// An arbitrary expression. UPPC_Expression = 0, - /// \brief The base type of a class type. + /// The base type of a class type. UPPC_BaseType, - /// \brief The type of an arbitrary declaration. + /// The type of an arbitrary declaration. UPPC_DeclarationType, - /// \brief The type of a data member. + /// The type of a data member. UPPC_DataMemberType, - /// \brief The size of a bit-field. + /// The size of a bit-field. UPPC_BitFieldWidth, - /// \brief The expression in a static assertion. + /// The expression in a static assertion. UPPC_StaticAssertExpression, - /// \brief The fixed underlying type of an enumeration. + /// The fixed underlying type of an enumeration. UPPC_FixedUnderlyingType, - /// \brief The enumerator value. + /// The enumerator value. UPPC_EnumeratorValue, - /// \brief A using declaration. + /// A using declaration. UPPC_UsingDeclaration, - /// \brief A friend declaration. + /// A friend declaration. UPPC_FriendDeclaration, - /// \brief A declaration qualifier. + /// A declaration qualifier. UPPC_DeclarationQualifier, - /// \brief An initializer. + /// An initializer. UPPC_Initializer, - /// \brief A default argument. + /// A default argument. UPPC_DefaultArgument, - /// \brief The type of a non-type template parameter. + /// The type of a non-type template parameter. UPPC_NonTypeTemplateParameterType, - /// \brief The type of an exception. + /// The type of an exception. UPPC_ExceptionType, - /// \brief Partial specialization. + /// Partial specialization. UPPC_PartialSpecialization, - /// \brief Microsoft __if_exists. + /// Microsoft __if_exists. UPPC_IfExists, - /// \brief Microsoft __if_not_exists. + /// Microsoft __if_not_exists. UPPC_IfNotExists, - /// \brief Lambda expression. + /// Lambda expression. UPPC_Lambda, - /// \brief Block expression, + /// Block expression, UPPC_Block }; - /// \brief Diagnose unexpanded parameter packs. + /// Diagnose unexpanded parameter packs. /// /// \param Loc The location at which we should emit the diagnostic. /// @@ -6560,7 +6630,7 @@ public: UnexpandedParameterPackContext UPPC, ArrayRef<UnexpandedParameterPack> Unexpanded); - /// \brief If the given type contains an unexpanded parameter pack, + /// If the given type contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The source location where a diagnostc should be emitted. @@ -6572,7 +6642,7 @@ public: bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, UnexpandedParameterPackContext UPPC); - /// \brief If the given expression contains an unexpanded parameter + /// If the given expression contains an unexpanded parameter /// pack, diagnose the error. /// /// \param E The expression that is being checked for unexpanded @@ -6582,7 +6652,7 @@ public: bool DiagnoseUnexpandedParameterPack(Expr *E, UnexpandedParameterPackContext UPPC = UPPC_Expression); - /// \brief If the given nested-name-specifier contains an unexpanded + /// If the given nested-name-specifier contains an unexpanded /// parameter pack, diagnose the error. /// /// \param SS The nested-name-specifier that is being checked for @@ -6592,7 +6662,7 @@ public: bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, UnexpandedParameterPackContext UPPC); - /// \brief If the given name contains an unexpanded parameter pack, + /// If the given name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param NameInfo The name (with source location information) that @@ -6602,7 +6672,7 @@ public: bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, UnexpandedParameterPackContext UPPC); - /// \brief If the given template name contains an unexpanded parameter pack, + /// If the given template name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The location of the template name. @@ -6615,7 +6685,7 @@ public: TemplateName Template, UnexpandedParameterPackContext UPPC); - /// \brief If the given template argument contains an unexpanded parameter + /// If the given template argument contains an unexpanded parameter /// pack, diagnose the error. /// /// \param Arg The template argument that is being checked for unexpanded @@ -6625,7 +6695,7 @@ public: bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, UnexpandedParameterPackContext UPPC); - /// \brief Collect the set of unexpanded parameter packs within the given + /// Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find @@ -6633,7 +6703,7 @@ public: void collectUnexpandedParameterPacks(TemplateArgument Arg, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); - /// \brief Collect the set of unexpanded parameter packs within the given + /// Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find @@ -6641,7 +6711,7 @@ public: void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); - /// \brief Collect the set of unexpanded parameter packs within the given + /// Collect the set of unexpanded parameter packs within the given /// type. /// /// \param T The type that will be traversed to find @@ -6649,7 +6719,7 @@ public: void collectUnexpandedParameterPacks(QualType T, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); - /// \brief Collect the set of unexpanded parameter packs within the given + /// Collect the set of unexpanded parameter packs within the given /// type. /// /// \param TL The type that will be traversed to find @@ -6657,7 +6727,7 @@ public: void collectUnexpandedParameterPacks(TypeLoc TL, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); - /// \brief Collect the set of unexpanded parameter packs within the given + /// Collect the set of unexpanded parameter packs within the given /// nested-name-specifier. /// /// \param NNS The nested-name-specifier that will be traversed to find @@ -6665,7 +6735,7 @@ public: void collectUnexpandedParameterPacks(NestedNameSpecifierLoc NNS, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); - /// \brief Collect the set of unexpanded parameter packs within the given + /// Collect the set of unexpanded parameter packs within the given /// name. /// /// \param NameInfo The name that will be traversed to find @@ -6673,7 +6743,7 @@ public: void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); - /// \brief Invoked when parsing a template argument followed by an + /// Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// /// \param Arg The template argument preceding the ellipsis, which @@ -6683,7 +6753,7 @@ public: ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc); - /// \brief Invoked when parsing a type followed by an ellipsis, which + /// Invoked when parsing a type followed by an ellipsis, which /// creates a pack expansion. /// /// \param Type The type preceding the ellipsis, which will become @@ -6692,20 +6762,20 @@ public: /// \param EllipsisLoc The location of the ellipsis. TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); - /// \brief Construct a pack expansion type from the pattern of the pack + /// Construct a pack expansion type from the pattern of the pack /// expansion. TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc, Optional<unsigned> NumExpansions); - /// \brief Construct a pack expansion type from the pattern of the pack + /// Construct a pack expansion type from the pattern of the pack /// expansion. QualType CheckPackExpansion(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, Optional<unsigned> NumExpansions); - /// \brief Invoked when parsing an expression followed by an ellipsis, which + /// Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become @@ -6714,7 +6784,7 @@ public: /// \param EllipsisLoc The location of the ellipsis. ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc); - /// \brief Invoked when parsing an expression followed by an ellipsis, which + /// Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become @@ -6724,7 +6794,7 @@ public: ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, Optional<unsigned> NumExpansions); - /// \brief Determine whether we could expand a pack expansion with the + /// Determine whether we could expand a pack expansion with the /// given set of parameter packs into separate arguments by repeatedly /// transforming the pattern. /// @@ -6766,7 +6836,7 @@ public: bool &RetainExpansion, Optional<unsigned> &NumExpansions); - /// \brief Determine the number of arguments in the given pack expansion + /// Determine the number of arguments in the given pack expansion /// type. /// /// This routine assumes that the number of arguments in the expansion is @@ -6776,7 +6846,7 @@ public: Optional<unsigned> getNumArgumentsInExpansion(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs); - /// \brief Determine whether the given declarator contains any unexpanded + /// Determine whether the given declarator contains any unexpanded /// parameter packs. /// /// This routine is used by the parser to disambiguate function declarators @@ -6793,7 +6863,7 @@ public: /// false otherwise. bool containsUnexpandedParameterPacks(Declarator &D); - /// \brief Returns the pattern of the pack expansion for a template argument. + /// Returns the pattern of the pack expansion for a template argument. /// /// \param OrigLoc The template argument to expand. /// @@ -6825,7 +6895,7 @@ public: QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType, bool AdjustExceptionSpec = false); - /// \brief Describes the result of template argument deduction. + /// Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of /// template argument deduction, as returned from @@ -6835,51 +6905,54 @@ public: /// list (if successful) or the specific template parameters or /// deduced arguments that were involved in the failure. enum TemplateDeductionResult { - /// \brief Template argument deduction was successful. + /// Template argument deduction was successful. TDK_Success = 0, - /// \brief The declaration was invalid; do nothing. + /// The declaration was invalid; do nothing. TDK_Invalid, - /// \brief Template argument deduction exceeded the maximum template + /// Template argument deduction exceeded the maximum template /// instantiation depth (which has already been diagnosed). TDK_InstantiationDepth, - /// \brief Template argument deduction did not deduce a value + /// Template argument deduction did not deduce a value /// for every template parameter. TDK_Incomplete, - /// \brief Template argument deduction produced inconsistent + /// Template argument deduction did not deduce a value for every + /// expansion of an expanded template parameter pack. + TDK_IncompletePack, + /// Template argument deduction produced inconsistent /// deduced values for the given template parameter. TDK_Inconsistent, - /// \brief Template argument deduction failed due to inconsistent + /// Template argument deduction failed due to inconsistent /// cv-qualifiers on a template parameter type that would /// otherwise be deduced, e.g., we tried to deduce T in "const T" /// but were given a non-const "X". TDK_Underqualified, - /// \brief Substitution of the deduced template argument values + /// Substitution of the deduced template argument values /// resulted in an error. TDK_SubstitutionFailure, - /// \brief After substituting deduced template arguments, a dependent + /// After substituting deduced template arguments, a dependent /// parameter type did not match the corresponding argument. TDK_DeducedMismatch, - /// \brief After substituting deduced template arguments, an element of + /// After substituting deduced template arguments, an element of /// a dependent parameter type did not match the corresponding element /// of the corresponding argument (when deducing from an initializer list). TDK_DeducedMismatchNested, - /// \brief A non-depnedent component of the parameter did not match the + /// A non-depnedent component of the parameter did not match the /// corresponding component of the argument. TDK_NonDeducedMismatch, - /// \brief When performing template argument deduction for a function + /// When performing template argument deduction for a function /// template, there were too many call arguments. TDK_TooManyArguments, - /// \brief When performing template argument deduction for a function + /// When performing template argument deduction for a function /// template, there were too few call arguments. TDK_TooFewArguments, - /// \brief The explicitly-specified template arguments were not valid + /// The explicitly-specified template arguments were not valid /// template arguments for the given template. TDK_InvalidExplicitArguments, - /// \brief Checking non-dependent argument conversions failed. + /// Checking non-dependent argument conversions failed. TDK_NonDependentConversionFailure, - /// \brief Deduction failed; that's all we know. + /// Deduction failed; that's all we know. TDK_MiscellaneousDeductionFailure, - /// \brief CUDA Target attributes do not match. + /// CUDA Target attributes do not match. TDK_CUDATargetMismatch }; @@ -6952,16 +7025,16 @@ public: sema::TemplateDeductionInfo &Info, bool IsAddressOfFunction = false); - /// \brief Substitute Replacement for \p auto in \p TypeWithAuto + /// Substitute Replacement for \p auto in \p TypeWithAuto QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement); - /// \brief Substitute Replacement for auto in TypeWithAuto + /// Substitute Replacement for auto in TypeWithAuto TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); - /// \brief Completely replace the \c auto in \p TypeWithAuto by + /// Completely replace the \c auto in \p TypeWithAuto by /// \p Replacement. This does not retain any \c auto type sugar. QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement); - /// \brief Result type of DeduceAutoType. + /// Result type of DeduceAutoType. enum DeduceAutoResult { DAR_Succeeded, DAR_Failed, @@ -6978,7 +7051,7 @@ public: bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, bool Diagnose = true); - /// \brief Declare implicit deduction guides for a class template if we've + /// Declare implicit deduction guides for a class template if we've /// not already done so. void DeclareImplicitDeductionGuides(TemplateDecl *Template, SourceLocation Loc); @@ -7059,7 +7132,7 @@ public: /// alone is not sufficient to identify the context). This covers template /// instantiation and various forms of implicitly-generated functions. struct CodeSynthesisContext { - /// \brief The kind of template instantiation we are performing + /// The kind of template instantiation we are performing enum SynthesisKind { /// We are instantiating a template declaration. The entity is /// the declaration we're instantiating (e.g., a CXXRecordDecl). @@ -7107,33 +7180,39 @@ public: /// We are defining a synthesized function (such as a defaulted special /// member). DefiningSynthesizedFunction, + + /// Added for Template instantiation observation. + /// Memoization means we are _not_ instantiating a template because + /// it is already instantiated (but we entered a context where we + /// would have had to if it was not already instantiated). + Memoization } Kind; - /// \brief Was the enclosing context a non-instantiation SFINAE context? + /// Was the enclosing context a non-instantiation SFINAE context? bool SavedInNonInstantiationSFINAEContext; - /// \brief The point of instantiation or synthesis within the source code. + /// The point of instantiation or synthesis within the source code. SourceLocation PointOfInstantiation; - /// \brief The entity that is being synthesized. + /// The entity that is being synthesized. Decl *Entity; - /// \brief The template (or partial specialization) in which we are + /// The template (or partial specialization) in which we are /// performing the instantiation, for substitutions of prior template /// arguments. NamedDecl *Template; - /// \brief The list of template arguments we are substituting, if they + /// The list of template arguments we are substituting, if they /// are not part of the entity. const TemplateArgument *TemplateArgs; // FIXME: Wrap this union around more members, or perhaps store the // kind-specific members in the RAII object owning the context. union { - /// \brief The number of template arguments in TemplateArgs. + /// The number of template arguments in TemplateArgs. unsigned NumTemplateArgs; - /// \brief The special member being declared or defined. + /// The special member being declared or defined. CXXSpecialMember SpecialMember; }; @@ -7142,11 +7221,11 @@ public: return {TemplateArgs, NumTemplateArgs}; } - /// \brief The template deduction info object associated with the + /// The template deduction info object associated with the /// substitution or checking of explicit or deduced template arguments. sema::TemplateDeductionInfo *DeductionInfo; - /// \brief The source range that covers the construct that cause + /// The source range that covers the construct that cause /// the instantiation, e.g., the template-id that causes a class /// template instantiation. SourceRange InstantiationRange; @@ -7155,12 +7234,12 @@ public: : Kind(TemplateInstantiation), Entity(nullptr), Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {} - /// \brief Determines whether this template is an actual instantiation + /// Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. bool isInstantiationRecord() const; }; - /// \brief List of active code synthesis contexts. + /// List of active code synthesis contexts. /// /// This vector is treated as a stack. As synthesis of one entity requires /// synthesis of another, additional contexts are pushed onto the stack. @@ -7173,32 +7252,32 @@ public: /// by some template instantiation. llvm::DenseSet<QualType> InstantiatedNonDependentTypes; - /// \brief Extra modules inspected when performing a lookup during a template + /// Extra modules inspected when performing a lookup during a template /// instantiation. Computed lazily. SmallVector<Module*, 16> CodeSynthesisContextLookupModules; - /// \brief Cache of additional modules that should be used for name lookup + /// Cache of additional modules that should be used for name lookup /// within the current template instantiation. Computed lazily; use /// getLookupModules() to get a complete set. llvm::DenseSet<Module*> LookupModulesCache; - /// \brief Get the set of additional modules that should be checked during + /// Get the set of additional modules that should be checked during /// name lookup. A module and its imports become visible when instanting a /// template defined within it. llvm::DenseSet<Module*> &getLookupModules(); - /// \brief Map from the most recent declaration of a namespace to the most + /// Map from the most recent declaration of a namespace to the most /// recent visible declaration of that namespace. llvm::DenseMap<NamedDecl*, NamedDecl*> VisibleNamespaceCache; - /// \brief Whether we are in a SFINAE context that is not associated with + /// Whether we are in a SFINAE context that is not associated with /// template instantiation. /// /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside /// of a template instantiation or template argument deduction. bool InNonInstantiationSFINAEContext; - /// \brief The number of \p CodeSynthesisContexts that are not template + /// The number of \p CodeSynthesisContexts that are not template /// instantiations and, therefore, should not be counted as part of the /// instantiation depth. /// @@ -7207,7 +7286,7 @@ public: // FIXME: Should we have a similar limit for other forms of synthesis? unsigned NonInstantiationEntries; - /// \brief The depth of the context stack at the point when the most recent + /// The depth of the context stack at the point when the most recent /// error or warning was produced. /// /// This value is used to suppress printing of redundant context stacks @@ -7215,7 +7294,15 @@ public: // FIXME: Does this belong in Sema? It's tough to implement it anywhere else. unsigned LastEmittedCodeSynthesisContextDepth = 0; - /// \brief The current index into pack expansion arguments that will be + /// The template instantiation callbacks to trace or track + /// instantiations (objects can be chained). + /// + /// This callbacks is used to print, trace or track template + /// instantiations as they are being constructed. + std::vector<std::unique_ptr<TemplateInstantiationCallback>> + TemplateInstCallbacks; + + /// The current index into pack expansion arguments that will be /// used for substitution of parameter packs. /// /// The pack expansion index will be -1 to indicate that parameter packs @@ -7223,7 +7310,7 @@ public: /// which argument within the parameter pack will be used for substitution. int ArgumentPackSubstitutionIndex; - /// \brief RAII object used to change the argument pack substitution index + /// RAII object used to change the argument pack substitution index /// within a \c Sema object. /// /// See \c ArgumentPackSubstitutionIndex for more information. @@ -7244,7 +7331,7 @@ public: friend class ArgumentPackSubstitutionRAII; - /// \brief For each declaration that involved template argument deduction, the + /// For each declaration that involved template argument deduction, the /// set of diagnostics that were suppressed during that template argument /// deduction. /// @@ -7253,7 +7340,7 @@ public: SuppressedDiagnosticsMap; SuppressedDiagnosticsMap SuppressedDiagnostics; - /// \brief A stack object to be created when performing template + /// A stack object to be created when performing template /// instantiation. /// /// Construction of an object of type \c InstantiatingTemplate @@ -7265,7 +7352,7 @@ public: /// Destruction of this object will pop the named instantiation off /// the stack. struct InstantiatingTemplate { - /// \brief Note that we are instantiating a class template, + /// Note that we are instantiating a class template, /// function template, variable template, alias template, /// or a member thereof. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -7273,20 +7360,20 @@ public: SourceRange InstantiationRange = SourceRange()); struct ExceptionSpecification {}; - /// \brief Note that we are instantiating an exception specification + /// Note that we are instantiating an exception specification /// of a function template. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity, ExceptionSpecification, SourceRange InstantiationRange = SourceRange()); - /// \brief Note that we are instantiating a default argument in a + /// Note that we are instantiating a default argument in a /// template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateParameter Param, TemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange = SourceRange()); - /// \brief Note that we are substituting either explicitly-specified or + /// Note that we are substituting either explicitly-specified or /// deduced template arguments during function template argument deduction. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *FunctionTemplate, @@ -7295,7 +7382,7 @@ public: sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); - /// \brief Note that we are instantiating as part of template + /// Note that we are instantiating as part of template /// argument deduction for a class template declaration. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, @@ -7303,7 +7390,7 @@ public: sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); - /// \brief Note that we are instantiating as part of template + /// Note that we are instantiating as part of template /// argument deduction for a class template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -7312,7 +7399,7 @@ public: sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); - /// \brief Note that we are instantiating as part of template + /// Note that we are instantiating as part of template /// argument deduction for a variable template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -7321,14 +7408,14 @@ public: sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); - /// \brief Note that we are instantiating a default argument for a function + /// Note that we are instantiating a default argument for a function /// parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange = SourceRange()); - /// \brief Note that we are substituting prior template arguments into a + /// Note that we are substituting prior template arguments into a /// non-type parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, @@ -7336,7 +7423,7 @@ public: ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange); - /// \brief Note that we are substituting prior template arguments into a + /// Note that we are substituting prior template arguments into a /// template template parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, @@ -7344,7 +7431,7 @@ public: ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange); - /// \brief Note that we are checking the default template argument + /// Note that we are checking the default template argument /// against the template parameter for a given template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, @@ -7353,16 +7440,16 @@ public: SourceRange InstantiationRange); - /// \brief Note that we have finished instantiating this template. + /// Note that we have finished instantiating this template. void Clear(); ~InstantiatingTemplate() { Clear(); } - /// \brief Determines whether we have exceeded the maximum + /// Determines whether we have exceeded the maximum /// recursive template instantiations. bool isInvalid() const { return Invalid; } - /// \brief Determine whether we are already instantiating this + /// Determine whether we are already instantiating this /// specialization in some surrounding active instantiation. bool isAlreadyInstantiating() const { return AlreadyInstantiating; } @@ -7407,7 +7494,7 @@ public: void PrintPragmaAttributeInstantiationPoint(); - /// \brief Determines whether we are currently in a context where + /// Determines whether we are currently in a context where /// template argument substitution failures are not considered /// errors. /// @@ -7417,7 +7504,7 @@ public: /// diagnostics that will be suppressed. Optional<sema::TemplateDeductionInfo *> isSFINAEContext() const; - /// \brief Determines whether we are currently in a context that + /// Determines whether we are currently in a context that /// is not evaluated as per C++ [expr] p5. bool isUnevaluatedContext() const { assert(!ExprEvalContexts.empty() && @@ -7425,7 +7512,7 @@ public: return ExprEvalContexts.back().isUnevaluated(); } - /// \brief RAII class used to determine whether SFINAE has + /// RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument /// deduction. class SFINAETrap { @@ -7458,13 +7545,13 @@ public: PrevLastDiagnosticIgnored); } - /// \brief Determine whether any SFINAE errors have been trapped. + /// Determine whether any SFINAE errors have been trapped. bool hasErrorOccurred() const { return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; } }; - /// \brief RAII class used to indicate that we are performing provisional + /// RAII class used to indicate that we are performing provisional /// semantic analysis to determine the validity of a construct, so /// typo-correction and diagnostics in the immediate context (not within /// implicitly-instantiated templates) should be suppressed. @@ -7484,30 +7571,30 @@ public: } }; - /// \brief The current instantiation scope used to store local + /// The current instantiation scope used to store local /// variables. LocalInstantiationScope *CurrentInstantiationScope; - /// \brief Tracks whether we are in a context where typo correction is + /// Tracks whether we are in a context where typo correction is /// disabled. bool DisableTypoCorrection; - /// \brief The number of typos corrected by CorrectTypo. + /// The number of typos corrected by CorrectTypo. unsigned TyposCorrected; typedef llvm::SmallSet<SourceLocation, 2> SrcLocSet; typedef llvm::DenseMap<IdentifierInfo *, SrcLocSet> IdentifierSourceLocations; - /// \brief A cache containing identifiers for which typo correction failed and + /// A cache containing identifiers for which typo correction failed and /// their locations, so that repeated attempts to correct an identifier in a /// given location are ignored if typo correction already failed for it. IdentifierSourceLocations TypoCorrectionFailures; - /// \brief Worker object for performing CFG-based warnings. + /// Worker object for performing CFG-based warnings. sema::AnalysisBasedWarnings AnalysisWarnings; threadSafety::BeforeSet *ThreadSafetyDeclCache; - /// \brief An entity for which implicit template instantiation is required. + /// An entity for which implicit template instantiation is required. /// /// The source location associated with the declaration is the first place in /// the source code where the declaration was "used". It is not necessarily @@ -7517,10 +7604,14 @@ public: /// because users will need to know what code triggered the instantiation. typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation; - /// \brief The queue of implicit template instantiations that are required + /// The queue of implicit template instantiations that are required /// but have not yet been performed. std::deque<PendingImplicitInstantiation> PendingInstantiations; + /// Queue of implicit template instantiations that cannot be performed + /// eagerly. + SmallVector<PendingImplicitInstantiation, 1> LateParsedInstantiations; + class GlobalEagerInstantiationScope { public: GlobalEagerInstantiationScope(Sema &S, bool Enabled) @@ -7559,7 +7650,7 @@ public: bool Enabled; }; - /// \brief The queue of implicit template instantiations that are required + /// The queue of implicit template instantiations that are required /// and must be performed within the current local scope. /// /// This queue is only used for member functions of local classes in @@ -7658,7 +7749,7 @@ public: ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); - /// \brief Substitute the given template arguments into a list of + /// Substitute the given template arguments into a list of /// expressions, expanding pack expansions if required. /// /// \param Exprs The list of expressions to substitute into. @@ -7678,6 +7769,10 @@ public: StmtResult SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs); + TemplateParameterList * + SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs); + Decl *SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); @@ -7835,20 +7930,14 @@ public: SourceLocation rAngleLoc); void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); - Decl *ActOnStartClassInterface(Scope *S, - SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, - SourceLocation ClassLoc, - ObjCTypeParamList *typeParamList, - IdentifierInfo *SuperName, - SourceLocation SuperLoc, - ArrayRef<ParsedType> SuperTypeArgs, - SourceRange SuperTypeArgsRange, - Decl * const *ProtoRefs, - unsigned NumProtoRefs, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, - AttributeList *AttrList); + Decl *ActOnStartClassInterface( + Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, + IdentifierInfo *SuperName, SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, SourceRange SuperTypeArgsRange, + Decl *const *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, + const ParsedAttributesView &AttrList); void ActOnSuperClassOfClassInterface(Scope *S, SourceLocation AtInterfaceLoc, @@ -7876,24 +7965,18 @@ public: const ObjCList<ObjCProtocolDecl> &PList); Decl *ActOnStartProtocolInterface( - SourceLocation AtProtoInterfaceLoc, - IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, - Decl * const *ProtoRefNames, unsigned NumProtoRefs, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, - AttributeList *AttrList); - - Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, - SourceLocation ClassLoc, - ObjCTypeParamList *typeParamList, - IdentifierInfo *CategoryName, - SourceLocation CategoryLoc, - Decl * const *ProtoRefs, - unsigned NumProtoRefs, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, - AttributeList *AttrList); + SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, + SourceLocation ProtocolLoc, Decl *const *ProtoRefNames, + unsigned NumProtoRefs, const SourceLocation *ProtoLocs, + SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); + + Decl *ActOnStartCategoryInterface( + SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, + IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + Decl *const *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, + const ParsedAttributesView &AttrList); Decl *ActOnStartClassImplementation( SourceLocation AtClassImplLoc, @@ -7916,9 +7999,10 @@ public: ArrayRef<ObjCTypeParamList *> TypeParamLists, unsigned NumElts); - DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, - ArrayRef<IdentifierLocPair> IdentList, - AttributeList *attrList); + DeclGroupPtrTy + ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, + ArrayRef<IdentifierLocPair> IdentList, + const ParsedAttributesView &attrList); void FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, ArrayRef<IdentifierLocPair> ProtocolId, @@ -8053,22 +8137,21 @@ public: ObjCDeclSpec DeclSpec; /// ArgAttrs - Attribute list for this argument. - AttributeList *ArgAttrs; + ParsedAttributesView ArgAttrs; }; Decl *ActOnMethodDeclaration( - Scope *S, - SourceLocation BeginLoc, // location of the + or -. - SourceLocation EndLoc, // location of the ; or {. - tok::TokenKind MethodType, - ObjCDeclSpec &ReturnQT, ParsedType ReturnType, - ArrayRef<SourceLocation> SelectorLocs, Selector Sel, - // optional arguments. The number of types/arguments is obtained - // from the Sel.getNumArgs(). - ObjCArgInfo *ArgInfo, - DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args - AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, - bool isVariadic, bool MethodDefinition); + Scope *S, + SourceLocation BeginLoc, // location of the + or -. + SourceLocation EndLoc, // location of the ; or {. + tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, + ArrayRef<SourceLocation> SelectorLocs, Selector Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + ObjCArgInfo *ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo, + unsigned CNumArgs, // c-style args + const ParsedAttributesView &AttrList, tok::ObjCKeywordKind MethodImplKind, + bool isVariadic, bool MethodDefinition); ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, const ObjCObjectPointerType *OPT, @@ -8096,14 +8179,14 @@ public: ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc); - /// \brief Describes the kind of message expression indicated by a message + /// Describes the kind of message expression indicated by a message /// send that starts with an identifier. enum ObjCMessageKind { - /// \brief The message is sent to 'super'. + /// The message is sent to 'super'. ObjCSuperMessage, - /// \brief The message is an instance message. + /// The message is an instance message. ObjCInstanceMessage, - /// \brief The message is a class message, and the identifier is a type + /// The message is a class message, and the identifier is a type /// name. ObjCClassMessage }; @@ -8212,12 +8295,12 @@ public: bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); - /// \brief Check whether the given new method is a valid override of the + /// Check whether the given new method is a valid override of the /// given overridden method, and set any properties that should be inherited. void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden); - /// \brief Describes the compatibility of a result type with its method. + /// Describes the compatibility of a result type with its method. enum ResultTypeCompatibilityKind { RTC_Compatible, RTC_Incompatible, @@ -8274,7 +8357,7 @@ public: LangOptions::PragmaMSPointersToMembersKind Kind, SourceLocation PragmaLoc); - /// \brief Called on well formed \#pragma vtordisp(). + /// Called on well formed \#pragma vtordisp(). void ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, SourceLocation PragmaLoc, MSVtorDispAttr::Mode Value); @@ -8293,22 +8376,22 @@ public: int SectionFlags, SourceLocation PragmaSectionLocation); - /// \brief Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg. + /// Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg. void ActOnPragmaMSSeg(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, StringLiteral *SegmentName, llvm::StringRef PragmaName); - /// \brief Called on well formed \#pragma section(). + /// Called on well formed \#pragma section(). void ActOnPragmaMSSection(SourceLocation PragmaLocation, int SectionFlags, StringLiteral *SegmentName); - /// \brief Called on well-formed \#pragma init_seg(). + /// Called on well-formed \#pragma init_seg(). void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, StringLiteral *SegmentName); - /// \brief Called on #pragma clang __debug dump II + /// Called on #pragma clang __debug dump II void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II); /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch @@ -8384,35 +8467,34 @@ public: /// the appropriate attribute. void AddCFAuditedAttribute(Decl *D); - /// \brief Called on well-formed '\#pragma clang attribute push'. - void ActOnPragmaAttributePush(AttributeList &Attribute, - SourceLocation PragmaLoc, + /// Called on well-formed '\#pragma clang attribute push'. + void ActOnPragmaAttributePush(ParsedAttr &Attribute, SourceLocation PragmaLoc, attr::ParsedSubjectMatchRuleSet Rules); - /// \brief Called on well-formed '\#pragma clang attribute pop'. + /// Called on well-formed '\#pragma clang attribute pop'. void ActOnPragmaAttributePop(SourceLocation PragmaLoc); - /// \brief Adds the attributes that have been specified using the + /// Adds the attributes that have been specified using the /// '\#pragma clang attribute push' directives to the given declaration. void AddPragmaAttributes(Scope *S, Decl *D); void DiagnoseUnterminatedPragmaAttribute(); - /// \brief Called on well formed \#pragma clang optimize. + /// Called on well formed \#pragma clang optimize. void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc); - /// \brief Get the location for the currently active "\#pragma clang optimize + /// Get the location for the currently active "\#pragma clang optimize /// off". If this location is invalid, then the state of the pragma is "on". SourceLocation getOptimizeOffPragmaLocation() const { return OptimizeOffPragmaLocation; } - /// \brief Only called on function definitions; if there is a pragma in scope + /// Only called on function definitions; if there is a pragma in scope /// with the effect of a range-based optnone, consider marking the function /// with attribute optnone. void AddRangeBasedOptnone(FunctionDecl *FD); - /// \brief Adds the 'optnone' attribute to the function declaration if there + /// Adds the 'optnone' attribute to the function declaration if there /// are no conflicts; Loc represents the location causing the 'optnone' /// attribute to be added (usually because of a pragma). void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc); @@ -8473,8 +8555,11 @@ public: StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E, bool IsImplicit = false); StmtResult BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs); + bool buildCoroutineParameterMoves(SourceLocation Loc); VarDecl *buildCoroutinePromise(SourceLocation Loc); void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body); + ClassTemplateDecl *lookupCoroutineTraits(SourceLocation KwLoc, + SourceLocation FuncLoc); //===--------------------------------------------------------------------===// // OpenCL extensions. @@ -8493,36 +8578,36 @@ public: CurrOpenCLExtension = Ext; } - /// \brief Set OpenCL extensions for a type which can only be used when these + /// Set OpenCL extensions for a type which can only be used when these /// OpenCL extensions are enabled. If \p Exts is empty, do nothing. /// \param Exts A space separated list of OpenCL extensions. void setOpenCLExtensionForType(QualType T, llvm::StringRef Exts); - /// \brief Set OpenCL extensions for a declaration which can only be + /// Set OpenCL extensions for a declaration which can only be /// used when these OpenCL extensions are enabled. If \p Exts is empty, do /// nothing. /// \param Exts A space separated list of OpenCL extensions. void setOpenCLExtensionForDecl(Decl *FD, llvm::StringRef Exts); - /// \brief Set current OpenCL extensions for a type which can only be used + /// Set current OpenCL extensions for a type which can only be used /// when these OpenCL extensions are enabled. If current OpenCL extension is /// empty, do nothing. void setCurrentOpenCLExtensionForType(QualType T); - /// \brief Set current OpenCL extensions for a declaration which + /// Set current OpenCL extensions for a declaration which /// can only be used when these OpenCL extensions are enabled. If current /// OpenCL extension is empty, do nothing. void setCurrentOpenCLExtensionForDecl(Decl *FD); bool isOpenCLDisabledDecl(Decl *FD); - /// \brief Check if type \p T corresponding to declaration specifier \p DS + /// Check if type \p T corresponding to declaration specifier \p DS /// is disabled due to required OpenCL extensions being disabled. If so, /// emit diagnostics. /// \return true if type is disabled. bool checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType T); - /// \brief Check if declaration \p D used by expression \p E + /// Check if declaration \p D used by expression \p E /// is disabled due to required OpenCL extensions being disabled. If so, /// emit diagnostics. /// \return true if type is disabled. @@ -8535,7 +8620,7 @@ private: void *VarDataSharingAttributesStack; /// Set to true inside '#pragma omp declare target' region. bool IsInOpenMPDeclareTargetContext = false; - /// \brief Initialization of data-sharing attributes stack. + /// Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); ExprResult @@ -8570,87 +8655,86 @@ private: SourceRange SrcRange = SourceRange()); public: - /// \brief Return true if the provided declaration \a VD should be captured by + /// Return true if the provided declaration \a VD should be captured by /// reference. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. - bool IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level); + bool isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const; - /// \brief Check if the specified variable is used in one of the private + /// Check if the specified variable is used in one of the private /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP /// constructs. - VarDecl *IsOpenMPCapturedDecl(ValueDecl *D); + VarDecl *isOpenMPCapturedDecl(ValueDecl *D) const; ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, ExprObjectKind OK, SourceLocation Loc); - /// \brief Check if the specified variable is used in 'private' clause. + /// Check if the specified variable is used in 'private' clause. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. - bool isOpenMPPrivateDecl(ValueDecl *D, unsigned Level); + bool isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const; /// Sets OpenMP capture kind (OMPC_private, OMPC_firstprivate, OMPC_map etc.) /// for \p FD based on DSA for the provided corresponding captured declaration /// \p D. - void setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level); + void setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, unsigned Level); - /// \brief Check if the specified variable is captured by 'target' directive. + /// Check if the specified variable is captured by 'target' directive. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. - bool isOpenMPTargetCapturedDecl(ValueDecl *D, unsigned Level); + bool isOpenMPTargetCapturedDecl(const ValueDecl *D, unsigned Level) const; ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); - /// \brief Called on start of new data sharing attribute block. + /// Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc); - /// \brief Start analysis of clauses. + /// Start analysis of clauses. void StartOpenMPClause(OpenMPClauseKind K); - /// \brief End analysis of clauses. + /// End analysis of clauses. void EndOpenMPClause(); - /// \brief Called on end of data sharing attribute block. + /// Called on end of data sharing attribute block. void EndOpenMPDSABlock(Stmt *CurDirective); - /// \brief Check if the current region is an OpenMP loop region and if it is, + /// Check if the current region is an OpenMP loop region and if it is, /// mark loop control variable, used in \p Init for loop initialization, as /// private by default. /// \param Init First part of the for loop. void ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init); // OpenMP directives and clauses. - /// \brief Called on correct id-expression from the '#pragma omp + /// Called on correct id-expression from the '#pragma omp /// threadprivate'. ExprResult ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id); - /// \brief Called on well-formed '#pragma omp threadprivate'. + /// Called on well-formed '#pragma omp threadprivate'. DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( SourceLocation Loc, ArrayRef<Expr *> VarList); - /// \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness. - OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl( - SourceLocation Loc, - ArrayRef<Expr *> VarList); - /// \brief Check if the specified type is allowed to be used in 'omp declare + /// Builds a new OpenMPThreadPrivateDecl and checks its correctness. + OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(SourceLocation Loc, + ArrayRef<Expr *> VarList); + /// Check if the specified type is allowed to be used in 'omp declare /// reduction' construct. QualType ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, TypeResult ParsedType); - /// \brief Called on start of '#pragma omp declare reduction'. + /// Called on start of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveStart( Scope *S, DeclContext *DC, DeclarationName Name, ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes, AccessSpecifier AS, Decl *PrevDeclInScope = nullptr); - /// \brief Initialize declare reduction construct initializer. + /// Initialize declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D); - /// \brief Finish current declare reduction construct initializer. + /// Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner); - /// \brief Initialize declare reduction construct initializer. + /// Initialize declare reduction construct initializer. /// \return omp_priv variable. VarDecl *ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); - /// \brief Finish current declare reduction construct initializer. + /// Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer, VarDecl *OmpPrivParm); - /// \brief Called at the end of '#pragma omp declare reduction'. + /// Called at the end of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd( Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid); @@ -8682,9 +8766,9 @@ public: /// Return the number of captured regions created for an OpenMP directive. static int getOpenMPCaptureLevels(OpenMPDirectiveKind Kind); - /// \brief Initialization of captured region for OpenMP region. + /// Initialization of captured region for OpenMP region. void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); - /// \brief End of OpenMP region. + /// End of OpenMP region. /// /// \param S Statement associated with the current OpenMP region. /// \param Clauses List of clauses for the current OpenMP region. @@ -8695,230 +8779,220 @@ public: OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp parallel' after parsing + /// Called on well-formed '\#pragma omp parallel' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp simd' after parsing + using VarsWithInheritedDSAType = + llvm::SmallDenseMap<const ValueDecl *, const Expr *, 4>; + /// Called on well-formed '\#pragma omp simd' after parsing /// of the associated statement. - StmtResult ActOnOpenMPSimdDirective( - ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp for' after parsing + StmtResult + ActOnOpenMPSimdDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp for' after parsing /// of the associated statement. - StmtResult ActOnOpenMPForDirective( - ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp for simd' after parsing + StmtResult + ActOnOpenMPForDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp for simd' after parsing /// of the associated statement. - StmtResult ActOnOpenMPForSimdDirective( - ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp sections' after parsing + StmtResult + ActOnOpenMPForSimdDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp sections' after parsing /// of the associated statement. StmtResult ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp section' after parsing of the + /// Called on well-formed '\#pragma omp section' after parsing of the /// associated statement. StmtResult ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp single' after parsing of the + /// Called on well-formed '\#pragma omp single' after parsing of the /// associated statement. StmtResult ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp master' after parsing of the + /// Called on well-formed '\#pragma omp master' after parsing of the /// associated statement. StmtResult ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp critical' after parsing of the + /// Called on well-formed '\#pragma omp critical' after parsing of the /// associated statement. StmtResult ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp parallel for' after parsing + /// Called on well-formed '\#pragma omp parallel for' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp parallel for simd' after + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp parallel sections' after + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp parallel sections' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp task' after parsing of the + /// Called on well-formed '\#pragma omp task' after parsing of the /// associated statement. StmtResult ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp taskyield'. + /// Called on well-formed '\#pragma omp taskyield'. StmtResult ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp barrier'. + /// Called on well-formed '\#pragma omp barrier'. StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp taskwait'. + /// Called on well-formed '\#pragma omp taskwait'. StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp taskgroup'. + /// Called on well-formed '\#pragma omp taskgroup'. StmtResult ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp flush'. + /// Called on well-formed '\#pragma omp flush'. StmtResult ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp ordered' after parsing of the + /// Called on well-formed '\#pragma omp ordered' after parsing of the /// associated statement. StmtResult ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp atomic' after parsing of the + /// Called on well-formed '\#pragma omp atomic' after parsing of the /// associated statement. StmtResult ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp target' after parsing of the + /// Called on well-formed '\#pragma omp target' after parsing of the /// associated statement. StmtResult ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp target data' after parsing of + /// Called on well-formed '\#pragma omp target data' after parsing of /// the associated statement. StmtResult ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp target enter data' after + /// Called on well-formed '\#pragma omp target enter data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AStmt); - /// \brief Called on well-formed '\#pragma omp target exit data' after + /// Called on well-formed '\#pragma omp target exit data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AStmt); - /// \brief Called on well-formed '\#pragma omp target parallel' after + /// Called on well-formed '\#pragma omp target parallel' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp target parallel for' after + /// Called on well-formed '\#pragma omp target parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp teams' after parsing of the + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp teams' after parsing of the /// associated statement. StmtResult ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed '\#pragma omp cancellation point'. + /// Called on well-formed '\#pragma omp cancellation point'. StmtResult ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); - /// \brief Called on well-formed '\#pragma omp cancel'. + /// Called on well-formed '\#pragma omp cancel'. StmtResult ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); - /// \brief Called on well-formed '\#pragma omp taskloop' after parsing of the + /// Called on well-formed '\#pragma omp taskloop' after parsing of the /// associated statement. - StmtResult ActOnOpenMPTaskLoopDirective( - ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp taskloop simd' after parsing of + StmtResult + ActOnOpenMPTaskLoopDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp taskloop simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPTaskLoopSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp distribute' after parsing + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp distribute' after parsing /// of the associated statement. - StmtResult ActOnOpenMPDistributeDirective( - ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp target update'. + StmtResult + ActOnOpenMPDistributeDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target update'. StmtResult ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AStmt); - /// \brief Called on well-formed '\#pragma omp distribute parallel for' after + /// Called on well-formed '\#pragma omp distribute parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp distribute parallel for simd' + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp distribute parallel for simd' /// after parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp distribute simd' after + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp distribute simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp target parallel for simd' after + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); - /// \brief Called on well-formed '\#pragma omp target simd' after parsing of + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Called on well-formed '\#pragma omp target simd' after parsing of /// the associated statement. - StmtResult ActOnOpenMPTargetSimdDirective( - ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); + StmtResult + ActOnOpenMPTargetSimdDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute' after parsing of /// the associated statement. StmtResult ActOnOpenMPTeamsDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPTeamsDistributeSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute parallel for simd' /// after parsing of the associated statement. StmtResult ActOnOpenMPTeamsDistributeParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute parallel for' /// after parsing of the associated statement. StmtResult ActOnOpenMPTeamsDistributeParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams' after parsing of the /// associated statement. StmtResult ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, @@ -8929,36 +9003,32 @@ public: /// of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute parallel for' /// after parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute parallel for /// simd' after parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA); + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Checks correctness of linear modifiers. bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, SourceLocation LinLoc); /// Checks that the specified declaration matches requirements for the linear /// decls. - bool CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc, + bool CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, OpenMPLinearClauseKind LinKind, QualType Type); - /// \brief Called on well-formed '\#pragma omp declare simd' after parsing of + /// Called on well-formed '\#pragma omp declare simd' after parsing of /// the associated method/function. DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective( DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, @@ -8971,50 +9041,50 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'if' clause. + /// Called on well-formed 'if' clause. OMPClause *ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation NameModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'final' clause. + /// Called on well-formed 'final' clause. OMPClause *ActOnOpenMPFinalClause(Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'num_threads' clause. + /// Called on well-formed 'num_threads' clause. OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'safelen' clause. + /// Called on well-formed 'safelen' clause. OMPClause *ActOnOpenMPSafelenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'simdlen' clause. + /// Called on well-formed 'simdlen' clause. OMPClause *ActOnOpenMPSimdlenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'collapse' clause. + /// Called on well-formed 'collapse' clause. OMPClause *ActOnOpenMPCollapseClause(Expr *NumForLoops, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'ordered' clause. + /// Called on well-formed 'ordered' clause. OMPClause * ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc, SourceLocation LParenLoc = SourceLocation(), Expr *NumForLoops = nullptr); - /// \brief Called on well-formed 'grainsize' clause. + /// Called on well-formed 'grainsize' clause. OMPClause *ActOnOpenMPGrainsizeClause(Expr *Size, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'num_tasks' clause. + /// Called on well-formed 'num_tasks' clause. OMPClause *ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'hint' clause. + /// Called on well-formed 'hint' clause. OMPClause *ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); @@ -9025,13 +9095,13 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'default' clause. + /// Called on well-formed 'default' clause. OMPClause *ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'proc_bind' clause. + /// Called on well-formed 'proc_bind' clause. OMPClause *ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, @@ -9043,7 +9113,7 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, ArrayRef<SourceLocation> ArgumentsLoc, SourceLocation DelimLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'schedule' clause. + /// Called on well-formed 'schedule' clause. OMPClause *ActOnOpenMPScheduleClause( OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, @@ -9052,37 +9122,37 @@ public: OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'nowait' clause. + /// Called on well-formed 'nowait' clause. OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'untied' clause. + /// Called on well-formed 'untied' clause. OMPClause *ActOnOpenMPUntiedClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'mergeable' clause. + /// Called on well-formed 'mergeable' clause. OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'read' clause. + /// Called on well-formed 'read' clause. OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'write' clause. + /// Called on well-formed 'write' clause. OMPClause *ActOnOpenMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'update' clause. + /// Called on well-formed 'update' clause. OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'capture' clause. + /// Called on well-formed 'capture' clause. OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'seq_cst' clause. + /// Called on well-formed 'seq_cst' clause. OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'threads' clause. + /// Called on well-formed 'threads' clause. OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'simd' clause. + /// Called on well-formed 'simd' clause. OMPClause *ActOnOpenMPSIMDClause(SourceLocation StartLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'nogroup' clause. + /// Called on well-formed 'nogroup' clause. OMPClause *ActOnOpenMPNogroupClause(SourceLocation StartLoc, SourceLocation EndLoc); @@ -9095,27 +9165,27 @@ public: OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation DepLinMapLoc); - /// \brief Called on well-formed 'private' clause. + /// Called on well-formed 'private' clause. OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'firstprivate' clause. + /// Called on well-formed 'firstprivate' clause. OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'lastprivate' clause. + /// Called on well-formed 'lastprivate' clause. OMPClause *ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'shared' clause. + /// Called on well-formed 'shared' clause. OMPClause *ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'reduction' clause. + /// Called on well-formed 'reduction' clause. OMPClause *ActOnOpenMPReductionClause( ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, @@ -9136,80 +9206,80 @@ public: CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef<Expr *> UnresolvedReductions = llvm::None); - /// \brief Called on well-formed 'linear' clause. + /// Called on well-formed 'linear' clause. OMPClause * ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind, SourceLocation LinLoc, SourceLocation ColonLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'aligned' clause. + /// Called on well-formed 'aligned' clause. OMPClause *ActOnOpenMPAlignedClause(ArrayRef<Expr *> VarList, Expr *Alignment, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'copyin' clause. + /// Called on well-formed 'copyin' clause. OMPClause *ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'copyprivate' clause. + /// Called on well-formed 'copyprivate' clause. OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'flush' pseudo clause. + /// Called on well-formed 'flush' pseudo clause. OMPClause *ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'depend' clause. + /// Called on well-formed 'depend' clause. OMPClause * ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'device' clause. + /// Called on well-formed 'device' clause. OMPClause *ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'map' clause. + /// Called on well-formed 'map' clause. OMPClause * ActOnOpenMPMapClause(OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'num_teams' clause. + /// Called on well-formed 'num_teams' clause. OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'thread_limit' clause. + /// Called on well-formed 'thread_limit' clause. OMPClause *ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'priority' clause. + /// Called on well-formed 'priority' clause. OMPClause *ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'dist_schedule' clause. + /// Called on well-formed 'dist_schedule' clause. OMPClause *ActOnOpenMPDistScheduleClause( OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'defaultmap' clause. + /// Called on well-formed 'defaultmap' clause. OMPClause *ActOnOpenMPDefaultmapClause( OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, SourceLocation KindLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'to' clause. + /// Called on well-formed 'to' clause. OMPClause *ActOnOpenMPToClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief Called on well-formed 'from' clause. + /// Called on well-formed 'from' clause. OMPClause *ActOnOpenMPFromClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -9225,18 +9295,25 @@ public: SourceLocation LParenLoc, SourceLocation EndLoc); - /// \brief The kind of conversion being performed. + /// The kind of conversion being performed. enum CheckedConversionKind { - /// \brief An implicit conversion. + /// An implicit conversion. CCK_ImplicitConversion, - /// \brief A C-style cast. + /// A C-style cast. CCK_CStyleCast, - /// \brief A functional-style cast. + /// A functional-style cast. CCK_FunctionalCast, - /// \brief A cast other than a C-style cast. - CCK_OtherCast + /// A cast other than a C-style cast. + CCK_OtherCast, + /// A conversion for an operand of a builtin overloaded operator. + CCK_ForBuiltinOverloadedOp }; + static bool isCast(CheckedConversionKind CCK) { + return CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast || + CCK == CCK_OtherCast; + } + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. @@ -9470,7 +9547,7 @@ public: QualType LHSType, ExprResult &RHS, bool Diagnose = true, bool DiagnoseCFAudited = false, bool ConvertRHS = true); - // \brief If the lhs type is a transparent union, check whether we + // If the lhs type is a transparent union, check whether we // can initialize the transparent union with the given expression. AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &RHS); @@ -9523,8 +9600,8 @@ public: ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, bool IsCompAssign = false); QualType CheckCompareOperands( // C99 6.5.8/9 - ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, - BinaryOperatorKind Opc, bool isRelational); + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc); QualType CheckBitwiseOperands( // C99 6.5.[10...12] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); @@ -9580,7 +9657,8 @@ public: bool AllowBothBool, bool AllowBoolConversion); QualType GetSignedVectorType(QualType V); QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc, bool isRelational); + SourceLocation Loc, + BinaryOperatorKind Opc); QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc); @@ -9617,11 +9695,11 @@ public: Expr *CastExpr, CastKind &CastKind, ExprValueKind &VK, CXXCastPath &Path); - /// \brief Force an expression with unknown-type to an expression of the + /// Force an expression with unknown-type to an expression of the /// given type. ExprResult forceUnknownAnyToType(Expr *E, QualType ToType); - /// \brief Type-check an expression that's being passed to an + /// Type-check an expression that's being passed to an /// __unknown_anytype parameter. ExprResult checkUnknownAnyArg(SourceLocation callLoc, Expr *result, QualType ¶mType); @@ -9633,7 +9711,7 @@ public: bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, CastKind &Kind); - /// \brief Prepare `SplattedExpr` for a vector splat operation, adding + /// Prepare `SplattedExpr` for a vector splat operation, adding /// implicit casts if necessary. ExprResult prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr); @@ -9652,7 +9730,7 @@ public: enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error }; - /// \brief Checks for invalid conversions and casts between + /// Checks for invalid conversions and casts between /// retainable pointers and other pointer kinds for ARC and Weak. ARCConversionResult CheckObjCConversion(SourceRange castRange, QualType castType, Expr *&op, @@ -9695,18 +9773,18 @@ public: SourceRange RecRange, QualType &ReturnType, ExprValueKind &VK); - /// \brief Determine the result of a message send expression based on + /// Determine the result of a message send expression based on /// the type of the receiver, the method expected to receive the message, /// and the form of the message send. QualType getMessageSendResultType(QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage); - /// \brief If the given expression involves a message send to a method + /// If the given expression involves a message send to a method /// with a related result type, emit a note describing what happened. void EmitRelatedResultTypeNote(const Expr *E); - /// \brief Given that we had incompatible pointer types in a return + /// Given that we had incompatible pointer types in a return /// statement, check whether we're in a method with a related result /// type, and if so, emit a note describing what happened. void EmitRelatedResultTypeNoteForReturn(QualType destType); @@ -9780,7 +9858,7 @@ public: /// being used as a boolean condition, warn if it's an assignment. void DiagnoseAssignmentAsCondition(Expr *E); - /// \brief Redundant parentheses over an equality comparison can indicate + /// Redundant parentheses over an equality comparison can indicate /// that the user intended an assignment used as condition. void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE); @@ -9799,7 +9877,7 @@ public: /// in the global scope. bool CheckObjCDeclScope(Decl *D); - /// \brief Abstract base class used for diagnosing integer constant + /// Abstract base class used for diagnosing integer constant /// expression violations. class VerifyICEDiagnoser { public: @@ -9995,7 +10073,7 @@ public: /// will get it wrong. Returns CFT_Host if D is null. CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D, bool IgnoreImplicitHDAttr = false); - CUDAFunctionTarget IdentifyCUDATarget(const AttributeList *Attr); + CUDAFunctionTarget IdentifyCUDATarget(const ParsedAttributesView &Attrs); /// Gets the CUDA target for the current context. CUDAFunctionTarget CurrentCUDATarget() { @@ -10094,6 +10172,16 @@ public: bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD); bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD); + // \brief Checks that initializers of \p Var satisfy CUDA restrictions. In + // case of error emits appropriate diagnostic and invalidates \p Var. + // + // \details CUDA allows only empty constructors as initializers for global + // variables (see E.2.3.1, CUDA 7.5). The same restriction also applies to all + // __shared__ variables whether they are local or not (they all are implicitly + // static in CUDA). One exception is that CUDA allows constant initializers + // for __constant__ and __device__ variables. + void checkAllowedCUDAInitializer(VarDecl *VD); + /// Check whether NewFD is a valid overload for CUDA. Emits /// diagnostics and invalidates NewFD if not. void checkCUDATargetOverload(FunctionDecl *NewFD, @@ -10103,48 +10191,48 @@ public: /// \name Code completion //@{ - /// \brief Describes the context in which code completion occurs. + /// Describes the context in which code completion occurs. enum ParserCompletionContext { - /// \brief Code completion occurs at top-level or namespace context. + /// Code completion occurs at top-level or namespace context. PCC_Namespace, - /// \brief Code completion occurs within a class, struct, or union. + /// Code completion occurs within a class, struct, or union. PCC_Class, - /// \brief Code completion occurs within an Objective-C interface, protocol, + /// Code completion occurs within an Objective-C interface, protocol, /// or category. PCC_ObjCInterface, - /// \brief Code completion occurs within an Objective-C implementation or + /// Code completion occurs within an Objective-C implementation or /// category implementation PCC_ObjCImplementation, - /// \brief Code completion occurs within the list of instance variables + /// Code completion occurs within the list of instance variables /// in an Objective-C interface, protocol, category, or implementation. PCC_ObjCInstanceVariableList, - /// \brief Code completion occurs following one or more template + /// Code completion occurs following one or more template /// headers. PCC_Template, - /// \brief Code completion occurs following one or more template + /// Code completion occurs following one or more template /// headers within a class. PCC_MemberTemplate, - /// \brief Code completion occurs within an expression. + /// Code completion occurs within an expression. PCC_Expression, - /// \brief Code completion occurs within a statement, which may + /// Code completion occurs within a statement, which may /// also be an expression or a declaration. PCC_Statement, - /// \brief Code completion occurs at the beginning of the + /// Code completion occurs at the beginning of the /// initialization statement (or expression) in a for loop. PCC_ForInit, - /// \brief Code completion occurs within the condition of an if, + /// Code completion occurs within the condition of an if, /// while, switch, or for statement. PCC_Condition, - /// \brief Code completion occurs within the body of a function on a + /// Code completion occurs within the body of a function on a /// recovery path, where we do not have a specific handle on our position /// in the grammar. PCC_RecoveryInFunction, - /// \brief Code completion occurs where only a type is permitted. + /// Code completion occurs where only a type is permitted. PCC_Type, - /// \brief Code completion occurs in a parenthesized expression, which + /// Code completion occurs in a parenthesized expression, which /// might also be a type cast. PCC_ParenthesizedExpression, - /// \brief Code completion occurs within a sequence of declaration + /// Code completion occurs within a sequence of declaration /// specifiers within a function, method, or block. PCC_LocalDeclarationSpecifiers }; @@ -10159,7 +10247,7 @@ public: struct CodeCompleteExpressionData; void CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data); - void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, + void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, bool IsBaseExprStatement); void CodeCompletePostfixExpression(Scope *S, ExprResult LHS); @@ -10309,6 +10397,9 @@ private: bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall); + bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); bool CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall); @@ -10341,10 +10432,12 @@ private: ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); + ExprResult SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, + bool IsDelete); bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); - bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, - int Low, int High); + bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, + int High, bool RangeIsError = true); bool SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, unsigned Multiple); bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, @@ -10405,13 +10498,16 @@ private: const AttrVec *Attrs = nullptr, const FunctionDecl *FD = nullptr); - void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); +public: + void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS); + +private: void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); void CheckBoolLikeConversion(Expr *E, SourceLocation CC); void CheckForIntOverflow(Expr *E); void CheckUnsequencedOperations(Expr *E); - /// \brief Perform semantic checks on a completed expression. This will either + /// Perform semantic checks on a completed expression. This will either /// be a full-expression or a default argument expression. void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation(), bool IsConstexpr = false); @@ -10424,11 +10520,11 @@ private: DeclarationName FieldName, const CXXRecordDecl *RD); - /// \brief Check if the given expression contains 'break' or 'continue' + /// Check if the given expression contains 'break' or 'continue' /// statement that produces control flow different from GCC. void CheckBreakContinueBinding(Expr *E); - /// \brief Check whether receiver is mutable ObjC container which + /// Check whether receiver is mutable ObjC container which /// attempts to add itself into the container void CheckObjCCircularContainer(ObjCMessageExpr *Message); @@ -10436,7 +10532,7 @@ private: void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, bool DeleteWasArrayForm); public: - /// \brief Register a magic integral constant to be used as a type tag. + /// Register a magic integral constant to be used as a type tag. void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, bool LayoutCompatible, bool MustBeNull); @@ -10462,21 +10558,21 @@ public: typedef std::pair<const IdentifierInfo *, uint64_t> TypeTagMagicValue; private: - /// \brief A map from magic value to type information. + /// A map from magic value to type information. std::unique_ptr<llvm::DenseMap<TypeTagMagicValue, TypeTagData>> TypeTagForDatatypeMagicValues; - /// \brief Peform checks on a call of a function with argument_with_type_tag + /// Peform checks on a call of a function with argument_with_type_tag /// or pointer_with_type_tag attributes. void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, const ArrayRef<const Expr *> ExprArgs, SourceLocation CallSiteLoc); - /// \brief Check if we are taking the address of a packed field + /// Check if we are taking the address of a packed field /// as this may be a problem if the pointer value is dereferenced. void CheckAddressOfPackedMember(Expr *rhs); - /// \brief The parser's current scope. + /// The parser's current scope. /// /// The parser maintains this state here. Scope *CurScope; @@ -10491,7 +10587,7 @@ private: IdentifierInfo *Ident_NSError = nullptr; - /// \brief The handler for the FileChanged preprocessor events. + /// The handler for the FileChanged preprocessor events. /// /// Used for diagnostics that implement custom semantic analysis for #include /// directives, like -Wpragma-pack. @@ -10514,7 +10610,7 @@ public: /// Retrieve the identifier "NSError". IdentifierInfo *getNSErrorIdent(); - /// \brief Retrieve the parser's current scope. + /// Retrieve the parser's current scope. /// /// This routine must only be used when it is certain that semantic analysis /// and the parser are in precisely the same context, which is not the case @@ -10545,7 +10641,7 @@ public: return DC; } - /// \brief To be used for checking whether the arguments being passed to + /// To be used for checking whether the arguments being passed to /// function exceeds the number of parameters expected for it. static bool TooManyArguments(size_t NumParams, size_t NumArgs, bool PartialOverloading = false) { @@ -10590,7 +10686,7 @@ private: } }; - /// \brief Helper class that collects misaligned member designations and + /// Helper class that collects misaligned member designations and /// their location info for delayed diagnostics. struct MisalignedMember { Expr *E; @@ -10607,28 +10703,28 @@ private: bool operator==(const MisalignedMember &m) { return this->E == m.E; } }; - /// \brief Small set of gathered accesses to potentially misaligned members + /// Small set of gathered accesses to potentially misaligned members /// due to the packed attribute. SmallVector<MisalignedMember, 4> MisalignedMembers; - /// \brief Adds an expression to the set of gathered misaligned members. + /// Adds an expression to the set of gathered misaligned members. void AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, CharUnits Alignment); public: - /// \brief Diagnoses the current set of gathered accesses. This typically + /// Diagnoses the current set of gathered accesses. This typically /// happens at full expression level. The set is cleared after emitting the /// diagnostics. void DiagnoseMisalignedMembers(); - /// \brief This function checks if the expression is in the sef of potentially + /// This function checks if the expression is in the sef of potentially /// misaligned members and it is converted to some pointer type T with lower /// or equal alignment requirements. If so it removes it. This is used when /// we do not want to diagnose such misaligned access (e.g. in conversions to /// void*). void DiscardMisalignedMemberAddress(const Type *T, Expr *E); - /// \brief This function calls Action when it determines that E designates a + /// This function calls Action when it determines that E designates a /// misaligned member due to the packed attribute. This is used to emit /// local diagnostics like in reference binding. void RefersToMemberWithReducedAlignment( @@ -10637,31 +10733,31 @@ public: Action); }; -/// \brief RAII object that enters a new expression evaluation context. +/// RAII object that enters a new expression evaluation context. class EnterExpressionEvaluationContext { Sema &Actions; bool Entered = true; public: - - EnterExpressionEvaluationContext(Sema &Actions, - Sema::ExpressionEvaluationContext NewContext, - Decl *LambdaContextDecl = nullptr, - bool IsDecltype = false, - bool ShouldEnter = true) + EnterExpressionEvaluationContext( + Sema &Actions, Sema::ExpressionEvaluationContext NewContext, + Decl *LambdaContextDecl = nullptr, + Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = + Sema::ExpressionEvaluationContextRecord::EK_Other, + bool ShouldEnter = true) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, - IsDecltype); + ExprContext); } - EnterExpressionEvaluationContext(Sema &Actions, - Sema::ExpressionEvaluationContext NewContext, - Sema::ReuseLambdaContextDecl_t, - bool IsDecltype = false) - : Actions(Actions) { - Actions.PushExpressionEvaluationContext(NewContext, - Sema::ReuseLambdaContextDecl, - IsDecltype); + EnterExpressionEvaluationContext( + Sema &Actions, Sema::ExpressionEvaluationContext NewContext, + Sema::ReuseLambdaContextDecl_t, + Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = + Sema::ExpressionEvaluationContextRecord::EK_Other) + : Actions(Actions) { + Actions.PushExpressionEvaluationContext( + NewContext, Sema::ReuseLambdaContextDecl, ExprContext); } enum InitListTag { InitList }; @@ -10675,7 +10771,7 @@ public: if (ShouldEnter && Actions.isUnevaluatedContext() && Actions.getLangOpts().CPlusPlus11) { Actions.PushExpressionEvaluationContext( - Sema::ExpressionEvaluationContext::UnevaluatedList, nullptr, false); + Sema::ExpressionEvaluationContext::UnevaluatedList); Entered = true; } } @@ -10690,11 +10786,11 @@ DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, sema::TemplateDeductionInfo &Info); -/// \brief Contains a late templated function. +/// Contains a late templated function. /// Will be parsed at the end of the translation unit, used by Sema & Parser. struct LateParsedTemplate { CachedTokens Toks; - /// \brief The template function declaration to be late parsed. + /// The template function declaration to be late parsed. Decl *D; }; diff --git a/gnu/llvm/tools/clang/lib/Analysis/FormatString.cpp b/gnu/llvm/tools/clang/lib/Analysis/FormatString.cpp index 7e8930c964a..f2ebc52274d 100644 --- a/gnu/llvm/tools/clang/lib/Analysis/FormatString.cpp +++ b/gnu/llvm/tools/clang/lib/Analysis/FormatString.cpp @@ -407,7 +407,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { case WIntTy: { - QualType PromoArg = + QualType PromoArg = argTy->isPromotableIntegerType() ? C.getPromotedIntegerType(argTy) : argTy; @@ -623,7 +623,7 @@ const char *ConversionSpecifier::toString() const { Optional<ConversionSpecifier> ConversionSpecifier::getStandardSpecifier() const { ConversionSpecifier::Kind NewKind; - + switch (getKind()) { default: return None; @@ -672,7 +672,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { switch (LM.getKind()) { case LengthModifier::None: return true; - + // Handle most integer flags case LengthModifier::AsShort: if (Target.getTriple().isOSMSVCRT()) { @@ -716,7 +716,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { default: return false; } - + // Handle 'l' flag case LengthModifier::AsLong: // or AsWideChar switch (CS.getKind()) { @@ -753,7 +753,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { default: return false; } - + case LengthModifier::AsLongDouble: switch (CS.getKind()) { case ConversionSpecifier::aArg: diff --git a/gnu/llvm/tools/clang/lib/Basic/Targets.cpp b/gnu/llvm/tools/clang/lib/Basic/Targets.cpp index 7deebc06c3e..1ef2fe3b814 100644 --- a/gnu/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/gnu/llvm/tools/clang/lib/Basic/Targets.cpp @@ -29,6 +29,7 @@ #include "Targets/OSTargets.h" #include "Targets/PNaCl.h" #include "Targets/PPC.h" +#include "Targets/RISCV.h" #include "Targets/SPIR.h" #include "Targets/Sparc.h" #include "Targets/SystemZ.h" @@ -37,6 +38,7 @@ #include "Targets/X86.h" #include "Targets/XCore.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" using namespace clang; @@ -370,6 +372,17 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::r600: return new AMDGPUTargetInfo(Triple, Opts); + case llvm::Triple::riscv32: + // TODO: add cases for FreeBSD, NetBSD, RTEMS once tested. + if (os == llvm::Triple::Linux) + return new LinuxTargetInfo<RISCV32TargetInfo>(Triple, Opts); + return new RISCV32TargetInfo(Triple, Opts); + case llvm::Triple::riscv64: + // TODO: add cases for FreeBSD, NetBSD, RTEMS once tested. + if (os == llvm::Triple::Linux) + return new LinuxTargetInfo<RISCV64TargetInfo>(Triple, Opts); + return new RISCV64TargetInfo(Triple, Opts); + case llvm::Triple::sparc: switch (os) { case llvm::Triple::Linux: @@ -595,6 +608,10 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, // Set the target CPU if specified. if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) { Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU; + SmallVector<StringRef, 32> ValidList; + Target->fillValidCPUList(ValidList); + if (!ValidList.empty()) + Diags.Report(diag::note_valid_options) << llvm::join(ValidList, ", "); return nullptr; } @@ -621,6 +638,9 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, Opts->Features.clear(); for (const auto &F : Features) Opts->Features.push_back((F.getValue() ? "+" : "-") + F.getKey().str()); + // Sort here, so we handle the features in a predictable order. (This matters + // when we're dealing with features that overlap.) + llvm::sort(Opts->Features.begin(), Opts->Features.end()); if (!Target->handleTargetFeatures(Opts->Features, Diags)) return nullptr; @@ -632,5 +652,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, if (!Target->validateTarget(Diags)) return nullptr; + Target->CheckFixedPointBits(); + return Target.release(); } diff --git a/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp index de67ee39c14..6fe84a07e38 100644 --- a/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp +++ b/gnu/llvm/tools/clang/lib/CodeGen/CGCall.cpp @@ -29,15 +29,15 @@ #include "clang/CodeGen/SwiftCallingConv.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Attributes.h" -#include "llvm/IR/CallingConv.h" #include "llvm/IR/CallSite.h" +#include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" -#include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicInst.h" -#include "llvm/Transforms/Utils/Local.h" +#include "llvm/IR/Intrinsics.h" using namespace clang; using namespace CodeGen; @@ -255,6 +255,16 @@ CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD, FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>(), MD); } +/// Set calling convention for CUDA/HIP kernel. +static void setCUDAKernelCallingConvention(CanQualType &FTy, CodeGenModule &CGM, + const FunctionDecl *FD) { + if (FD->hasAttr<CUDAGlobalAttr>()) { + const FunctionType *FT = FTy->getAs<FunctionType>(); + CGM.getTargetCodeGenInfo().setCUDAKernelCallingConvention(FT); + FTy = FT->getCanonicalTypeUnqualified(); + } +} + /// Arrange the argument and result information for a declaration or /// definition of the given C++ non-static member function. The /// member function must be an ordinary function, i.e. not a @@ -264,7 +274,9 @@ CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) { assert(!isa<CXXConstructorDecl>(MD) && "wrong method for constructors!"); assert(!isa<CXXDestructorDecl>(MD) && "wrong method for destructors!"); - CanQual<FunctionProtoType> prototype = GetFormalType(MD); + CanQualType FT = GetFormalType(MD).getAs<Type>(); + setCUDAKernelCallingConvention(FT, CGM, MD); + auto prototype = FT.getAs<FunctionProtoType>(); if (MD->isInstance()) { // The abstract case is perfectly fine. @@ -424,6 +436,7 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) { CanQualType FTy = FD->getType()->getCanonicalTypeUnqualified(); assert(isa<FunctionType>(FTy)); + setCUDAKernelCallingConvention(FTy, CGM, FD); // When declaring a function without a prototype, always use a // non-variadic type. @@ -513,8 +526,8 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) { /// correct type, and the caller will bitcast the function to the correct /// prototype. const CGFunctionInfo & -CodeGenTypes::arrangeMSMemberPointerThunk(const CXXMethodDecl *MD) { - assert(MD->isVirtual() && "only virtual memptrs have thunks"); +CodeGenTypes::arrangeUnprototypedMustTailThunk(const CXXMethodDecl *MD) { + assert(MD->isVirtual() && "only methods have thunks"); CanQual<FunctionProtoType> FTP = GetFormalType(MD); CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) }; return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false, @@ -776,7 +789,7 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType, bool erased = FunctionsBeingProcessed.erase(FI); (void)erased; assert(erased && "Not in set?"); - + return *FI; } @@ -803,6 +816,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, FI->NoReturn = info.getNoReturn(); FI->ReturnsRetained = info.getProducesResult(); FI->NoCallerSavedRegs = info.getNoCallerSavedRegs(); + FI->NoCfCheck = info.getNoCfCheck(); FI->Required = required; FI->HasRegParm = info.getHasRegParm(); FI->RegParm = info.getRegParm(); @@ -904,8 +918,7 @@ getTypeExpansion(QualType Ty, const ASTContext &Context) { CharUnits UnionSize = CharUnits::Zero(); for (const auto *FD : RD->fields()) { - // Skip zero length bitfields. - if (FD->isBitField() && FD->getBitWidthValue(Context) == 0) + if (FD->isZeroLengthBitField(Context)) continue; assert(!FD->isBitField() && "Cannot expand structure with bit-field members."); @@ -926,8 +939,7 @@ getTypeExpansion(QualType Ty, const ASTContext &Context) { } for (const auto *FD : RD->fields()) { - // Skip zero length bitfields. - if (FD->isBitField() && FD->getBitWidthValue(Context) == 0) + if (FD->isZeroLengthBitField(Context)) continue; assert(!FD->isBitField() && "Cannot expand structure with bit-field members."); @@ -1040,42 +1052,49 @@ void CodeGenFunction::ExpandTypeFromArgs( } void CodeGenFunction::ExpandTypeToArgs( - QualType Ty, RValue RV, llvm::FunctionType *IRFuncTy, + QualType Ty, CallArg Arg, llvm::FunctionType *IRFuncTy, SmallVectorImpl<llvm::Value *> &IRCallArgs, unsigned &IRCallArgPos) { auto Exp = getTypeExpansion(Ty, getContext()); if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) { - forConstantArrayExpansion(*this, CAExp, RV.getAggregateAddress(), - [&](Address EltAddr) { - RValue EltRV = - convertTempToRValue(EltAddr, CAExp->EltTy, SourceLocation()); - ExpandTypeToArgs(CAExp->EltTy, EltRV, IRFuncTy, IRCallArgs, IRCallArgPos); - }); + Address Addr = Arg.hasLValue() ? Arg.getKnownLValue().getAddress() + : Arg.getKnownRValue().getAggregateAddress(); + forConstantArrayExpansion( + *this, CAExp, Addr, [&](Address EltAddr) { + CallArg EltArg = CallArg( + convertTempToRValue(EltAddr, CAExp->EltTy, SourceLocation()), + CAExp->EltTy); + ExpandTypeToArgs(CAExp->EltTy, EltArg, IRFuncTy, IRCallArgs, + IRCallArgPos); + }); } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) { - Address This = RV.getAggregateAddress(); + Address This = Arg.hasLValue() ? Arg.getKnownLValue().getAddress() + : Arg.getKnownRValue().getAggregateAddress(); for (const CXXBaseSpecifier *BS : RExp->Bases) { // Perform a single step derived-to-base conversion. Address Base = GetAddressOfBaseClass(This, Ty->getAsCXXRecordDecl(), &BS, &BS + 1, /*NullCheckValue=*/false, SourceLocation()); - RValue BaseRV = RValue::getAggregate(Base); + CallArg BaseArg = CallArg(RValue::getAggregate(Base), BS->getType()); // Recurse onto bases. - ExpandTypeToArgs(BS->getType(), BaseRV, IRFuncTy, IRCallArgs, + ExpandTypeToArgs(BS->getType(), BaseArg, IRFuncTy, IRCallArgs, IRCallArgPos); } LValue LV = MakeAddrLValue(This, Ty); for (auto FD : RExp->Fields) { - RValue FldRV = EmitRValueForField(LV, FD, SourceLocation()); - ExpandTypeToArgs(FD->getType(), FldRV, IRFuncTy, IRCallArgs, + CallArg FldArg = + CallArg(EmitRValueForField(LV, FD, SourceLocation()), FD->getType()); + ExpandTypeToArgs(FD->getType(), FldArg, IRFuncTy, IRCallArgs, IRCallArgPos); } } else if (isa<ComplexExpansion>(Exp.get())) { - ComplexPairTy CV = RV.getComplexVal(); + ComplexPairTy CV = Arg.getKnownRValue().getComplexVal(); IRCallArgs[IRCallArgPos++] = CV.first; IRCallArgs[IRCallArgPos++] = CV.second; } else { assert(isa<NoExpansion>(Exp.get())); + auto RV = Arg.getKnownRValue(); assert(RV.isScalar() && "Unexpected non-scalar rvalue during struct expansion."); @@ -1325,7 +1344,7 @@ static void CreateCoercedStore(llvm::Value *Src, } static Address emitAddressAtOffset(CodeGenFunction &CGF, Address addr, - const ABIArgInfo &info) { + const ABIArgInfo &info) { if (unsigned offset = info.getDirectOffset()) { addr = CGF.Builder.CreateElementBitCast(addr, CGF.Int8Ty); addr = CGF.Builder.CreateConstInBoundsByteGEP(addr, @@ -1479,7 +1498,8 @@ void ClangToLLVMArgMapping::construct(const ASTContext &Context, /***/ bool CodeGenModule::ReturnTypeUsesSRet(const CGFunctionInfo &FI) { - return FI.getReturnInfo().isIndirect(); + const auto &RI = FI.getReturnInfo(); + return RI.isIndirect() || (RI.isInAlloca() && RI.getInAllocaSRet()); } bool CodeGenModule::ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI) { @@ -1655,7 +1675,7 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) { if (!isFuncTypeConvertible(FPT)) return llvm::StructType::get(getLLVMContext()); - + const CGFunctionInfo *Info; if (isa<CXXDestructorDecl>(MD)) Info = @@ -1672,7 +1692,7 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx, return; if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) && - FPT->isNothrow(Ctx)) + FPT->isNothrow()) FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); } @@ -1714,12 +1734,19 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, FuncAttrs.addAttribute("less-precise-fpmad", llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD)); + if (CodeGenOpts.NullPointerIsValid) + FuncAttrs.addAttribute("null-pointer-is-valid", "true"); if (!CodeGenOpts.FPDenormalMode.empty()) FuncAttrs.addAttribute("denormal-fp-math", CodeGenOpts.FPDenormalMode); FuncAttrs.addAttribute("no-trapping-math", llvm::toStringRef(CodeGenOpts.NoTrappingMath)); + // Strict (compliant) code is the default, so only add this attribute to + // indicate that we are trying to workaround a problem case. + if (!CodeGenOpts.StrictFloatCastOverflow) + FuncAttrs.addAttribute("strict-float-cast-overflow", "false"); + // TODO: Are these all needed? // unsafe/inf/nan/nsz are handled by instruction-level FastMathFlags. FuncAttrs.addAttribute("no-infs-fp-math", @@ -1738,6 +1765,10 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, "correctly-rounded-divide-sqrt-fp-math", llvm::toStringRef(CodeGenOpts.CorrectlyRoundedDivSqrt)); + if (getLangOpts().OpenCL) + FuncAttrs.addAttribute("denorms-are-zero", + llvm::toStringRef(CodeGenOpts.FlushDenorm)); + // TODO: Reciprocal estimate codegen options should apply to instructions? const std::vector<std::string> &Recips = CodeGenOpts.Reciprocals; if (!Recips.empty()) @@ -1769,7 +1800,7 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); // Respect -fcuda-flush-denormals-to-zero. - if (getLangOpts().CUDADeviceFlushDenormalsToZero) + if (CodeGenOpts.FlushDenorm) FuncAttrs.addAttribute("nvptx-f32ftz", "true"); } } @@ -1793,7 +1824,7 @@ void CodeGenModule::ConstructAttributeList( FuncAttrs.addAttribute(llvm::Attribute::NoReturn); // If we have information about the function prototype, we can learn - // attributes form there. + // attributes from there. AddAttributesFromFunctionProtoType(getContext(), FuncAttrs, CalleeInfo.getCalleeFunctionProtoType()); @@ -1838,18 +1869,20 @@ void CodeGenModule::ConstructAttributeList( } if (TargetDecl->hasAttr<RestrictAttr>()) RetAttrs.addAttribute(llvm::Attribute::NoAlias); - if (TargetDecl->hasAttr<ReturnsNonNullAttr>()) + if (TargetDecl->hasAttr<ReturnsNonNullAttr>() && + !CodeGenOpts.NullPointerIsValid) RetAttrs.addAttribute(llvm::Attribute::NonNull); if (TargetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>()) FuncAttrs.addAttribute("no_caller_saved_registers"); + if (TargetDecl->hasAttr<AnyX86NoCfCheckAttr>()) + FuncAttrs.addAttribute(llvm::Attribute::NoCfCheck); HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>(); if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) { Optional<unsigned> NumElemsParam; - // alloc_size args are base-1, 0 means not present. - if (unsigned N = AllocSize->getNumElemsParam()) - NumElemsParam = N - 1; - FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam() - 1, + if (AllocSize->getNumElemsParam().isValid()) + NumElemsParam = AllocSize->getNumElemsParam().getLLVMIndex(); + FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam().getLLVMIndex(), NumElemsParam); } } @@ -1870,56 +1903,42 @@ void CodeGenModule::ConstructAttributeList( } } + if (TargetDecl && TargetDecl->hasAttr<OpenCLKernelAttr>()) { + if (getLangOpts().OpenCLVersion <= 120) { + // OpenCL v1.2 Work groups are always uniform + FuncAttrs.addAttribute("uniform-work-group-size", "true"); + } else { + // OpenCL v2.0 Work groups may be whether uniform or not. + // '-cl-uniform-work-group-size' compile option gets a hint + // to the compiler that the global work-size be a multiple of + // the work-group size specified to clEnqueueNDRangeKernel + // (i.e. work groups are uniform). + FuncAttrs.addAttribute("uniform-work-group-size", + llvm::toStringRef(CodeGenOpts.UniformWGSize)); + } + } + if (!AttrOnCallSite) { - bool DisableTailCalls = - CodeGenOpts.DisableTailCalls || - (TargetDecl && (TargetDecl->hasAttr<DisableTailCallsAttr>() || - TargetDecl->hasAttr<AnyX86InterruptAttr>())); + bool DisableTailCalls = false; + + if (CodeGenOpts.DisableTailCalls) + DisableTailCalls = true; + else if (TargetDecl) { + if (TargetDecl->hasAttr<DisableTailCallsAttr>() || + TargetDecl->hasAttr<AnyX86InterruptAttr>()) + DisableTailCalls = true; + else if (CodeGenOpts.NoEscapingBlockTailCalls) { + if (const auto *BD = dyn_cast<BlockDecl>(TargetDecl)) + if (!BD->doesNotEscape()) + DisableTailCalls = true; + } + } + FuncAttrs.addAttribute("disable-tail-calls", llvm::toStringRef(DisableTailCalls)); - if (CodeGenOpts.ReturnProtector) FuncAttrs.addAttribute("ret-protector"); - - // Add target-cpu and target-features attributes to functions. If - // we have a decl for the function and it has a target attribute then - // parse that and add it to the feature set. - StringRef TargetCPU = getTarget().getTargetOpts().CPU; - std::vector<std::string> Features; - const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl); - if (FD && FD->hasAttr<TargetAttr>()) { - llvm::StringMap<bool> FeatureMap; - getFunctionFeatureMap(FeatureMap, FD); - - // Produce the canonical string for this set of features. - for (llvm::StringMap<bool>::const_iterator it = FeatureMap.begin(), - ie = FeatureMap.end(); - it != ie; ++it) - Features.push_back((it->second ? "+" : "-") + it->first().str()); - - // Now add the target-cpu and target-features to the function. - // While we populated the feature map above, we still need to - // get and parse the target attribute so we can get the cpu for - // the function. - const auto *TD = FD->getAttr<TargetAttr>(); - TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse(); - if (ParsedAttr.Architecture != "" && - getTarget().isValidCPUName(ParsedAttr.Architecture)) - TargetCPU = ParsedAttr.Architecture; - } else { - // Otherwise just add the existing target cpu and target features to the - // function. - Features = getTarget().getTargetOpts().Features; - } - - if (TargetCPU != "") - FuncAttrs.addAttribute("target-cpu", TargetCPU); - if (!Features.empty()) { - std::sort(Features.begin(), Features.end()); - FuncAttrs.addAttribute( - "target-features", - llvm::join(Features, ",")); - } + GetCPUAndFeaturesAttributes(TargetDecl, FuncAttrs); } ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI); @@ -1928,9 +1947,9 @@ void CodeGenModule::ConstructAttributeList( const ABIArgInfo &RetAI = FI.getReturnInfo(); switch (RetAI.getKind()) { case ABIArgInfo::Extend: - if (RetTy->hasSignedIntegerRepresentation()) + if (RetAI.isSignExt()) RetAttrs.addAttribute(llvm::Attribute::SExt); - else if (RetTy->hasUnsignedIntegerRepresentation()) + else RetAttrs.addAttribute(llvm::Attribute::ZExt); LLVM_FALLTHROUGH; case ABIArgInfo::Direct: @@ -1960,7 +1979,8 @@ void CodeGenModule::ConstructAttributeList( if (!PTy->isIncompleteType() && PTy->isConstantSizeType()) RetAttrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy) .getQuantity()); - else if (getContext().getTargetAddressSpace(PTy) == 0) + else if (getContext().getTargetAddressSpace(PTy) == 0 && + !CodeGenOpts.NullPointerIsValid) RetAttrs.addAttribute(llvm::Attribute::NonNull); } @@ -1970,7 +1990,8 @@ void CodeGenModule::ConstructAttributeList( // Attach attributes to sret. if (IRFunctionArgs.hasSRetArg()) { llvm::AttrBuilder SRETAttrs; - SRETAttrs.addAttribute(llvm::Attribute::StructRet); + if (!RetAI.getSuppressSRet()) + SRETAttrs.addAttribute(llvm::Attribute::StructRet); hasUsedSRet = true; if (RetAI.getInReg()) SRETAttrs.addAttribute(llvm::Attribute::InReg); @@ -2009,14 +2030,10 @@ void CodeGenModule::ConstructAttributeList( // sense to do it here because parameters are so messed up. switch (AI.getKind()) { case ABIArgInfo::Extend: - if (ParamType->isSignedIntegerOrEnumerationType()) + if (AI.isSignExt()) Attrs.addAttribute(llvm::Attribute::SExt); - else if (ParamType->isUnsignedIntegerOrEnumerationType()) { - if (getTypes().getABIInfo().shouldSignExtUnsignedType(ParamType)) - Attrs.addAttribute(llvm::Attribute::SExt); - else - Attrs.addAttribute(llvm::Attribute::ZExt); - } + else + Attrs.addAttribute(llvm::Attribute::ZExt); LLVM_FALLTHROUGH; case ABIArgInfo::Direct: if (ArgNo == 0 && FI.isChainCall()) @@ -2073,7 +2090,8 @@ void CodeGenModule::ConstructAttributeList( if (!PTy->isIncompleteType() && PTy->isConstantSizeType()) Attrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy) .getQuantity()); - else if (getContext().getTargetAddressSpace(PTy) == 0) + else if (getContext().getTargetAddressSpace(PTy) == 0 && + !CodeGenOpts.NullPointerIsValid) Attrs.addAttribute(llvm::Attribute::NonNull); } @@ -2258,11 +2276,16 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i, ++info_it, ++ArgNo) { const VarDecl *Arg = *i; - QualType Ty = info_it->type; const ABIArgInfo &ArgI = info_it->info; bool isPromoted = isa<ParmVarDecl>(Arg) && cast<ParmVarDecl>(Arg)->isKNRPromoted(); + // We are converting from ABIArgInfo type to VarDecl type directly, unless + // the parameter is promoted. In this case we convert to + // CGFunctionInfo::ArgInfo type with subsequent argument demotion. + QualType Ty = isPromoted ? info_it->type : Arg->getType(); + assert(hasScalarEvaluationKind(Ty) == + hasScalarEvaluationKind(Arg->getType())); unsigned FirstIRArg, NumIRArgs; std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo); @@ -2328,7 +2351,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) { if (getNonNullAttr(CurCodeDecl, PVD, PVD->getType(), - PVD->getFunctionScopeIndex())) + PVD->getFunctionScopeIndex()) && + !CGM.getCodeGenOpts().NullPointerIsValid) AI->addAttr(llvm::Attribute::NonNull); QualType OTy = PVD->getOriginalType(); @@ -2347,7 +2371,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, Attrs.addDereferenceableAttr( getContext().getTypeSizeInChars(ETy).getQuantity()*ArrSize); AI->addAttrs(Attrs); - } else if (getContext().getTargetAddressSpace(ETy) == 0) { + } else if (getContext().getTargetAddressSpace(ETy) == 0 && + !CGM.getCodeGenOpts().NullPointerIsValid) { AI->addAttr(llvm::Attribute::NonNull); } } @@ -2357,7 +2382,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // we can't use the dereferenceable attribute, but in addrspace(0) // we know that it must be nonnull. if (ArrTy->getSizeModifier() == VariableArrayType::Static && - !getContext().getTargetAddressSpace(ArrTy->getElementType())) + !getContext().getTargetAddressSpace(ArrTy->getElementType()) && + !CGM.getCodeGenOpts().NullPointerIsValid) AI->addAttr(llvm::Attribute::NonNull); } @@ -2659,7 +2685,7 @@ static llvm::Value *tryRemoveRetainOfSelf(CodeGenFunction &CGF, llvm::Value *retainedValue = retainCall->getArgOperand(0); llvm::LoadInst *load = dyn_cast<llvm::LoadInst>(retainedValue->stripPointerCasts()); - if (!load || load->isAtomic() || load->isVolatile() || + if (!load || load->isAtomic() || load->isVolatile() || load->getPointerOperand() != CGF.GetAddrOfLocalVar(self).getPointer()) return nullptr; @@ -3025,7 +3051,8 @@ static AggValueSlot createPlaceholderSlot(CodeGenFunction &CGF, Ty.getQualifiers(), AggValueSlot::IsNotDestructed, AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased); + AggValueSlot::IsNotAliased, + AggValueSlot::DoesNotOverlap); } void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, @@ -3065,6 +3092,19 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, } else { args.add(convertTempToRValue(local, type, loc), type); } + + // Deactivate the cleanup for the callee-destructed param that was pushed. + if (hasAggregateEvaluationKind(type) && !CurFuncIsThunk && + type->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee() && + type.isDestructedType()) { + EHScopeStack::stable_iterator cleanup = + CalleeDestructedParamCleanups.lookup(cast<ParmVarDecl>(param)); + assert(cleanup.isValid() && + "cleanup for callee-destructed param not recorded"); + // This unreachable is a temporary marker which will be removed later. + llvm::Instruction *isActive = Builder.CreateUnreachable(); + args.addArgCleanupDeactivation(cleanup, isActive); + } } static bool isProvablyNull(llvm::Value *addr) { @@ -3101,7 +3141,7 @@ static void emitWriteback(CodeGenFunction &CGF, // Cast it back, in case we're writing an id to a Foo* or something. value = CGF.Builder.CreateBitCast(value, srcAddr.getElementType(), "icr.writeback-cast"); - + // Perform the writeback. // If we have a "to use" value, it's something we need to emit a use @@ -3146,7 +3186,6 @@ static void emitWritebacks(CodeGenFunction &CGF, static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF, const CallArgList &CallArgs) { - assert(CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()); ArrayRef<CallArgList::CallArgCleanup> Cleanups = CallArgs.getCleanupsToDeactivate(); // Iterate in reverse to increase the likelihood of popping the cleanup. @@ -3208,7 +3247,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, // isn't null, so we need to register a dominating point so that the cleanups // system will make valid IR. CodeGenFunction::ConditionalEvaluation condEval(CGF); - + // Zero-initialize it if we're not doing a copy-initialization. bool shouldCopy = CRE->shouldCopy(); if (!shouldCopy) { @@ -3232,7 +3271,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr.getPointer(), "icr.isnull"); - finalArgument = CGF.Builder.CreateSelect(isNull, + finalArgument = CGF.Builder.CreateSelect(isNull, llvm::ConstantPointerNull::get(destType), temp.getPointer(), "icr.argument"); @@ -3272,7 +3311,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, valueToUse = src; } } - + // Finish the control flow if we needed it. if (shouldCopy && !provablyNonNull) { llvm::BasicBlock *copyBB = CGF.Builder.GetInsertBlock(); @@ -3323,7 +3362,7 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, auto PVD = ParmNum < AC.getNumParams() ? AC.getParamDecl(ParmNum) : nullptr; unsigned ArgNo = PVD ? PVD->getFunctionScopeIndex() : ParmNum; - // Prefer the nonnull attribute if it's present. + // Prefer the nonnull attribute if it's present. const NonNullAttr *NNAttr = nullptr; if (SanOpts.has(SanitizerKind::NonnullAttribute)) NNAttr = getNonNullAttr(AC.getDecl(), PVD, ArgType, ArgNo); @@ -3433,13 +3472,17 @@ void CodeGenFunction::EmitCallArgs( assert(InitialArgSize + 1 == Args.size() && "The code below depends on only adding one arg per EmitCallArg"); (void)InitialArgSize; - RValue RVArg = Args.back().RV; - EmitNonNullArgCheck(RVArg, ArgTypes[Idx], (*Arg)->getExprLoc(), AC, - ParamsToSkip + Idx); - // @llvm.objectsize should never have side-effects and shouldn't need - // destruction/cleanups, so we can safely "emit" it after its arg, - // regardless of right-to-leftness - MaybeEmitImplicitObjectSize(Idx, *Arg, RVArg); + // Since pointer argument are never emitted as LValue, it is safe to emit + // non-null argument check for r-value only. + if (!Args.back().hasLValue()) { + RValue RVArg = Args.back().getKnownRValue(); + EmitNonNullArgCheck(RVArg, ArgTypes[Idx], (*Arg)->getExprLoc(), AC, + ParamsToSkip + Idx); + // @llvm.objectsize should never have side-effects and shouldn't need + // destruction/cleanups, so we can safely "emit" it after its arg, + // regardless of right-to-leftness + MaybeEmitImplicitObjectSize(Idx, *Arg, RVArg); + } } if (!LeftToRight) { @@ -3459,10 +3502,15 @@ struct DestroyUnpassedArg final : EHScopeStack::Cleanup { QualType Ty; void Emit(CodeGenFunction &CGF, Flags flags) override { - const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor(); - assert(!Dtor->isTrivial()); - CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false, - /*Delegating=*/false, Addr); + QualType::DestructionKind DtorKind = Ty.isDestructedType(); + if (DtorKind == QualType::DK_cxx_destructor) { + const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor(); + assert(!Dtor->isTrivial()); + CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false, + /*Delegating=*/false, Addr); + } else { + CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Ty)); + } } }; @@ -3481,6 +3529,33 @@ struct DisableDebugLocationUpdates { } // end anonymous namespace +RValue CallArg::getRValue(CodeGenFunction &CGF) const { + if (!HasLV) + return RV; + LValue Copy = CGF.MakeAddrLValue(CGF.CreateMemTemp(Ty), Ty); + CGF.EmitAggregateCopy(Copy, LV, Ty, AggValueSlot::DoesNotOverlap, + LV.isVolatile()); + IsUsed = true; + return RValue::getAggregate(Copy.getAddress()); +} + +void CallArg::copyInto(CodeGenFunction &CGF, Address Addr) const { + LValue Dst = CGF.MakeAddrLValue(Addr, Ty); + if (!HasLV && RV.isScalar()) + CGF.EmitStoreOfScalar(RV.getScalarVal(), Dst, /*init=*/true); + else if (!HasLV && RV.isComplex()) + CGF.EmitStoreOfComplex(RV.getComplexVal(), Dst, /*init=*/true); + else { + auto Addr = HasLV ? LV.getAddress() : RV.getAggregateAddress(); + LValue SrcLV = CGF.MakeAddrLValue(Addr, Ty); + // We assume that call args are never copied into subobjects. + CGF.EmitAggregateCopy(Dst, SrcLV, Ty, AggValueSlot::DoesNotOverlap, + HasLV ? LV.isVolatileQualified() + : RV.isVolatileQualified()); + } + IsUsed = true; +} + void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, QualType type) { DisableDebugLocationUpdates Dis(*this, E); @@ -3504,7 +3579,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, // However, we still have to push an EH-only cleanup in case we unwind before // we make it to the call. if (HasAggregateEvalKind && - CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) { + type->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) { // If we're using inalloca, use the argument memory. Otherwise, use a // temporary. AggValueSlot Slot; @@ -3513,10 +3588,12 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, else Slot = CreateAggTemp(type, "agg.tmp"); - const CXXRecordDecl *RD = type->getAsCXXRecordDecl(); - bool DestroyedInCallee = - RD && RD->hasNonTrivialDestructor() && - CGM.getCXXABI().getRecordArgABI(RD) != CGCXXABI::RAA_Default; + bool DestroyedInCallee = true, NeedsEHCleanup = true; + if (const auto *RD = type->getAsCXXRecordDecl()) + DestroyedInCallee = RD->hasNonTrivialDestructor(); + else + NeedsEHCleanup = needsEHCleanup(type.isDestructedType()); + if (DestroyedInCallee) Slot.setExternallyDestructed(); @@ -3524,7 +3601,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, RValue RV = Slot.asRValue(); args.add(RV, type); - if (DestroyedInCallee) { + if (DestroyedInCallee && NeedsEHCleanup) { // Create a no-op GEP between the placeholder and the cleanup so we can // RAUW it successfully. It also serves as a marker of the first // instruction where the cleanup is active. @@ -3541,15 +3618,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) { LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr()); assert(L.isSimple()); - if (L.getAlignment() >= getContext().getTypeAlignInChars(type)) { - args.add(L.asAggregateRValue(), type, /*NeedsCopy*/true); - } else { - // We can't represent a misaligned lvalue in the CallArgList, so copy - // to an aligned temporary now. - Address tmp = CreateMemTemp(type); - EmitAggregateCopy(tmp, L.getAddress(), type, L.isVolatile()); - args.add(RValue::getAggregate(tmp), type); - } + args.addUncopiedAggregate(L, type); return; } @@ -3611,20 +3680,21 @@ CodeGenFunction::EmitRuntimeCall(llvm::Value *callee, // Calls which may throw must have operand bundles indicating which funclet // they are nested within. -static void -getBundlesForFunclet(llvm::Value *Callee, llvm::Instruction *CurrentFuncletPad, - SmallVectorImpl<llvm::OperandBundleDef> &BundleList) { +SmallVector<llvm::OperandBundleDef, 1> +CodeGenFunction::getBundlesForFunclet(llvm::Value *Callee) { + SmallVector<llvm::OperandBundleDef, 1> BundleList; // There is no need for a funclet operand bundle if we aren't inside a // funclet. if (!CurrentFuncletPad) - return; + return BundleList; // Skip intrinsics which cannot throw. auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts()); if (CalleeFn && CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow()) - return; + return BundleList; BundleList.emplace_back("funclet", CurrentFuncletPad); + return BundleList; } /// Emits a simple call (never an invoke) to the given runtime function. @@ -3632,10 +3702,8 @@ llvm::CallInst * CodeGenFunction::EmitRuntimeCall(llvm::Value *callee, ArrayRef<llvm::Value*> args, const llvm::Twine &name) { - SmallVector<llvm::OperandBundleDef, 1> BundleList; - getBundlesForFunclet(callee, CurrentFuncletPad, BundleList); - - llvm::CallInst *call = Builder.CreateCall(callee, args, BundleList, name); + llvm::CallInst *call = + Builder.CreateCall(callee, args, getBundlesForFunclet(callee), name); call->setCallingConv(getRuntimeCC()); return call; } @@ -3643,11 +3711,11 @@ CodeGenFunction::EmitRuntimeCall(llvm::Value *callee, /// Emits a call or invoke to the given noreturn runtime function. void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee, ArrayRef<llvm::Value*> args) { - SmallVector<llvm::OperandBundleDef, 1> BundleList; - getBundlesForFunclet(callee, CurrentFuncletPad, BundleList); + SmallVector<llvm::OperandBundleDef, 1> BundleList = + getBundlesForFunclet(callee); if (getInvokeDest()) { - llvm::InvokeInst *invoke = + llvm::InvokeInst *invoke = Builder.CreateInvoke(callee, getUnreachableBlock(), getInvokeDest(), @@ -3687,8 +3755,8 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee, ArrayRef<llvm::Value *> Args, const Twine &Name) { llvm::BasicBlock *InvokeDest = getInvokeDest(); - SmallVector<llvm::OperandBundleDef, 1> BundleList; - getBundlesForFunclet(Callee, CurrentFuncletPad, BundleList); + SmallVector<llvm::OperandBundleDef, 1> BundleList = + getBundlesForFunclet(Callee); llvm::Instruction *Inst; if (!InvokeDest) @@ -3708,16 +3776,6 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee, return llvm::CallSite(Inst); } -/// \brief Store a non-aggregate value to an address to initialize it. For -/// initialization, a non-atomic store will be used. -static void EmitInitStoreOfNonAggregate(CodeGenFunction &CGF, RValue Src, - LValue Dst) { - if (Src.isScalar()) - CGF.EmitStoreOfScalar(Src.getScalarVal(), Dst, /*init=*/true); - else - CGF.EmitStoreOfComplex(Src.getComplexVal(), Dst, /*init=*/true); -} - void CodeGenFunction::deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New) { DeferredReplacements.push_back(std::make_pair(Old, New)); @@ -3731,7 +3789,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, SourceLocation Loc) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. - assert(Callee.isOrdinary()); + assert(Callee.isOrdinary() || Callee.isVirtual()); // Handle struct-return functions by passing a pointer to the // location that we would like to return into. @@ -3778,17 +3836,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If the call returns a temporary with struct return, create a temporary // alloca to hold the result, unless one is given to us. Address SRetPtr = Address::invalid(); - size_t UnusedReturnSize = 0; + Address SRetAlloca = Address::invalid(); + llvm::Value *UnusedReturnSizePtr = nullptr; if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) { if (!ReturnValue.isNull()) { SRetPtr = ReturnValue.getValue(); } else { - SRetPtr = CreateMemTemp(RetTy); + SRetPtr = CreateMemTemp(RetTy, "tmp", &SRetAlloca); if (HaveInsertPoint() && ReturnValue.isUnused()) { uint64_t size = CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(RetTy)); - if (EmitLifetimeStart(size, SRetPtr.getPointer())) - UnusedReturnSize = size; + UnusedReturnSizePtr = EmitLifetimeStart(size, SRetAlloca.getPointer()); } } if (IRFunctionArgs.hasSRetArg()) { @@ -3810,7 +3868,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end(); I != E; ++I, ++info_it, ++ArgNo) { const ABIArgInfo &ArgInfo = info_it->info; - RValue RV = I->RV; // Insert a padding argument to ensure proper alignment. if (IRFunctionArgs.hasPaddingArg(ArgNo)) @@ -3824,13 +3881,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::InAlloca: { assert(NumIRArgs == 0); assert(getTarget().getTriple().getArch() == llvm::Triple::x86); - if (RV.isAggregate()) { + if (I->isAggregate()) { // Replace the placeholder with the appropriate argument slot GEP. + Address Addr = I->hasLValue() + ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress(); llvm::Instruction *Placeholder = - cast<llvm::Instruction>(RV.getAggregatePointer()); + cast<llvm::Instruction>(Addr.getPointer()); CGBuilderTy::InsertPoint IP = Builder.saveIP(); Builder.SetInsertPoint(Placeholder); - Address Addr = createInAllocaStructGEP(ArgInfo.getInAllocaFieldIndex()); + Addr = createInAllocaStructGEP(ArgInfo.getInAllocaFieldIndex()); Builder.restoreIP(IP); deferPlaceholderReplacement(Placeholder, Addr.getPointer()); } else { @@ -3843,22 +3903,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // from {}* to (%struct.foo*)*. if (Addr.getType() != MemType) Addr = Builder.CreateBitCast(Addr, MemType); - LValue argLV = MakeAddrLValue(Addr, I->Ty); - EmitInitStoreOfNonAggregate(*this, RV, argLV); + I->copyInto(*this, Addr); } break; } case ABIArgInfo::Indirect: { assert(NumIRArgs == 1); - if (RV.isScalar() || RV.isComplex()) { + if (!I->isAggregate()) { // Make a temporary alloca to pass the argument. - Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(), - "indirect-arg-temp", false); + Address Addr = CreateMemTempWithoutCast( + I->Ty, ArgInfo.getIndirectAlign(), "indirect-arg-temp"); IRCallArgs[FirstIRArg] = Addr.getPointer(); - LValue argLV = MakeAddrLValue(Addr, I->Ty); - EmitInitStoreOfNonAggregate(*this, RV, argLV); + I->copyInto(*this, Addr); } else { // We want to avoid creating an unnecessary temporary+copy here; // however, we need one in three cases: @@ -3866,30 +3924,51 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // source. (This case doesn't occur on any common architecture.) // 2. If the argument is byval, RV is not sufficiently aligned, and // we cannot force it to be sufficiently aligned. - // 3. If the argument is byval, but RV is located in an address space - // different than that of the argument (0). - Address Addr = RV.getAggregateAddress(); + // 3. If the argument is byval, but RV is not located in default + // or alloca address space. + Address Addr = I->hasLValue() + ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress(); + llvm::Value *V = Addr.getPointer(); CharUnits Align = ArgInfo.getIndirectAlign(); const llvm::DataLayout *TD = &CGM.getDataLayout(); - const unsigned RVAddrSpace = Addr.getType()->getAddressSpace(); - const unsigned ArgAddrSpace = - (FirstIRArg < IRFuncTy->getNumParams() - ? IRFuncTy->getParamType(FirstIRArg)->getPointerAddressSpace() - : 0); - if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) || - (ArgInfo.getIndirectByVal() && Addr.getAlignment() < Align && - llvm::getOrEnforceKnownAlignment(Addr.getPointer(), - Align.getQuantity(), *TD) - < Align.getQuantity()) || - (ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) { + + assert((FirstIRArg >= IRFuncTy->getNumParams() || + IRFuncTy->getParamType(FirstIRArg)->getPointerAddressSpace() == + TD->getAllocaAddrSpace()) && + "indirect argument must be in alloca address space"); + + bool NeedCopy = false; + + if (Addr.getAlignment() < Align && + llvm::getOrEnforceKnownAlignment(V, Align.getQuantity(), *TD) < + Align.getQuantity()) { + NeedCopy = true; + } else if (I->hasLValue()) { + auto LV = I->getKnownLValue(); + auto AS = LV.getAddressSpace(); + if ((!ArgInfo.getIndirectByVal() && + (LV.getAlignment() >= + getContext().getTypeAlignInChars(I->Ty))) || + (ArgInfo.getIndirectByVal() && + ((AS != LangAS::Default && AS != LangAS::opencl_private && + AS != CGM.getASTAllocaAddressSpace())))) { + NeedCopy = true; + } + } + if (NeedCopy) { // Create an aligned temporary, and copy to it. - Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(), - "byval-temp", false); + Address AI = CreateMemTempWithoutCast( + I->Ty, ArgInfo.getIndirectAlign(), "byval-temp"); IRCallArgs[FirstIRArg] = AI.getPointer(); - EmitAggregateCopy(AI, Addr, I->Ty, RV.isVolatileQualified()); + I->copyInto(*this, AI); } else { // Skip the extra memcpy call. - IRCallArgs[FirstIRArg] = Addr.getPointer(); + auto *T = V->getType()->getPointerElementType()->getPointerTo( + CGM.getDataLayout().getAllocaAddrSpace()); + IRCallArgs[FirstIRArg] = getTargetHooks().performAddrSpaceCast( + *this, V, LangAS::Default, CGM.getASTAllocaAddressSpace(), T, + true); } } break; @@ -3906,10 +3985,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, ArgInfo.getDirectOffset() == 0) { assert(NumIRArgs == 1); llvm::Value *V; - if (RV.isScalar()) - V = RV.getScalarVal(); + if (!I->isAggregate()) + V = I->getKnownRValue().getScalarVal(); else - V = Builder.CreateLoad(RV.getAggregateAddress()); + V = Builder.CreateLoad( + I->hasLValue() ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress()); // Implement swifterror by copying into a new swifterror argument. // We'll write back in the normal path out of the call. @@ -3947,12 +4028,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // FIXME: Avoid the conversion through memory if possible. Address Src = Address::invalid(); - if (RV.isScalar() || RV.isComplex()) { + if (!I->isAggregate()) { Src = CreateMemTemp(I->Ty, "coerce"); - LValue SrcLV = MakeAddrLValue(Src, I->Ty); - EmitInitStoreOfNonAggregate(*this, RV, SrcLV); + I->copyInto(*this, Src); } else { - Src = RV.getAggregateAddress(); + Src = I->hasLValue() ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress(); } // If the value is offset in memory, apply the offset now. @@ -4006,22 +4087,26 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *tempSize = nullptr; Address addr = Address::invalid(); - if (RV.isAggregate()) { - addr = RV.getAggregateAddress(); + Address AllocaAddr = Address::invalid(); + if (I->isAggregate()) { + addr = I->hasLValue() ? I->getKnownLValue().getAddress() + : I->getKnownRValue().getAggregateAddress(); + } else { + RValue RV = I->getKnownRValue(); assert(RV.isScalar()); // complex should always just be direct llvm::Type *scalarType = RV.getScalarVal()->getType(); auto scalarSize = CGM.getDataLayout().getTypeAllocSize(scalarType); auto scalarAlign = CGM.getDataLayout().getPrefTypeAlignment(scalarType); - tempSize = llvm::ConstantInt::get(CGM.Int64Ty, scalarSize); - // Materialize to a temporary. addr = CreateTempAlloca(RV.getScalarVal()->getType(), - CharUnits::fromQuantity(std::max(layout->getAlignment(), - scalarAlign))); - EmitLifetimeStart(scalarSize, addr.getPointer()); + CharUnits::fromQuantity(std::max( + layout->getAlignment(), scalarAlign)), + "tmp", + /*ArraySize=*/nullptr, &AllocaAddr); + tempSize = EmitLifetimeStart(scalarSize, AllocaAddr.getPointer()); Builder.CreateStore(RV.getScalarVal(), addr); } @@ -4039,7 +4124,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, assert(IRArgPos == FirstIRArg + NumIRArgs); if (tempSize) { - EmitLifetimeEnd(tempSize, addr.getPointer()); + EmitLifetimeEnd(tempSize, AllocaAddr.getPointer()); } break; @@ -4047,13 +4132,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::Expand: unsigned IRArgPos = FirstIRArg; - ExpandTypeToArgs(I->Ty, RV, IRFuncTy, IRCallArgs, IRArgPos); + ExpandTypeToArgs(I->Ty, *I, IRFuncTy, IRCallArgs, IRArgPos); assert(IRArgPos == FirstIRArg + NumIRArgs); break; } } - llvm::Value *CalleePtr = Callee.getFunctionPointer(); + const CGCallee &ConcreteCallee = Callee.prepareConcreteCallee(*this); + llvm::Value *CalleePtr = ConcreteCallee.getFunctionPointer(); // If we're using inalloca, set up that argument. if (ArgMemory.isValid()) { @@ -4194,10 +4280,19 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, CannotThrow = Attrs.hasAttribute(llvm::AttributeList::FunctionIndex, llvm::Attribute::NoUnwind); } + + // If we made a temporary, be sure to clean up after ourselves. Note that we + // can't depend on being inside of an ExprWithCleanups, so we need to manually + // pop this cleanup later on. Being eager about this is OK, since this + // temporary is 'invisible' outside of the callee. + if (UnusedReturnSizePtr) + pushFullExprCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, SRetAlloca, + UnusedReturnSizePtr); + llvm::BasicBlock *InvokeDest = CannotThrow ? nullptr : getInvokeDest(); - SmallVector<llvm::OperandBundleDef, 1> BundleList; - getBundlesForFunclet(CalleePtr, CurrentFuncletPad, BundleList); + SmallVector<llvm::OperandBundleDef, 1> BundleList = + getBundlesForFunclet(CalleePtr); // Emit the actual call/invoke instruction. llvm::CallSite CS; @@ -4247,9 +4342,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // insertion point; this allows the rest of IRGen to discard // unreachable code. if (CS.doesNotReturn()) { - if (UnusedReturnSize) - EmitLifetimeEnd(llvm::ConstantInt::get(Int64Ty, UnusedReturnSize), - SRetPtr.getPointer()); + if (UnusedReturnSizePtr) + PopCleanupBlock(); // Strip away the noreturn attribute to better diagnose unreachable UB. if (SanOpts.has(SanitizerKind::Unreachable)) { @@ -4318,9 +4412,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::InAlloca: case ABIArgInfo::Indirect: { RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation()); - if (UnusedReturnSize) - EmitLifetimeEnd(llvm::ConstantInt::get(Int64Ty, UnusedReturnSize), - SRetPtr.getPointer()); + if (UnusedReturnSizePtr) + PopCleanupBlock(); return ret; } @@ -4398,7 +4491,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, OffsetValue); } else if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) { llvm::Value *ParamVal = - CallArgs[AA->getParamIndex() - 1].RV.getScalarVal(); + CallArgs[AA->getParamIndex().getLLVMIndex()].getRValue( + *this).getScalarVal(); EmitAlignmentAssumption(Ret.getScalarVal(), ParamVal); } } @@ -4406,6 +4500,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, return Ret; } +CGCallee CGCallee::prepareConcreteCallee(CodeGenFunction &CGF) const { + if (isVirtual()) { + const CallExpr *CE = getVirtualCallExpr(); + return CGF.CGM.getCXXABI().getVirtualFunctionPointer( + CGF, getVirtualMethodDecl(), getThisAddress(), + getFunctionType(), CE ? CE->getLocStart() : SourceLocation()); + } + + return *this; +} + /* VarArg handling */ Address CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr) { diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 6c3ae24ce1a..b3c5ce1d8cb 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -69,6 +69,9 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, std::pair<StringRef, StringRef> Split = Mcpu.split("+"); CPU = Split.first; + if (CPU == "native") + CPU = llvm::sys::getHostCPUName(); + if (CPU == "generic") { Features.push_back("+neon"); } else { @@ -202,6 +205,9 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, if (Args.hasArg(options::OPT_ffixed_x18)) Features.push_back("+reserve-x18"); + if (Args.hasArg(options::OPT_ffixed_x20)) + Features.push_back("+reserve-x20"); + if (Args.hasArg(options::OPT_mno_neg_immediates)) Features.push_back("+no-neg-immediates"); } diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 696cb15ae44..886d947c586 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -391,12 +391,22 @@ void arm::getARMTargetFeatures(const ToolChain &TC, } else if (HDivArg) getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features); - // Setting -msoft-float effectively disables NEON because of the GCC - // implementation, although the same isn't true of VFP or VFP3. + // Setting -msoft-float/-mfloat-abi=soft effectively disables the FPU (GCC + // ignores the -mfpu options in this case). + // Note that the ABI can also be set implicitly by the target selected. if (ABI == arm::FloatABI::Soft) { - Features.push_back("-neon"); - // Also need to explicitly disable features which imply NEON. - Features.push_back("-crypto"); + llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); + + // Disable hardware FP features which have been enabled. + // FIXME: Disabling vfp2 and neon should be enough as all the other + // features are dependent on these 2 features in LLVM. However + // there is currently no easy way to test this in clang, so for + // now just be explicit and disable all known dependent features + // as well. + for (std::string Feature : {"vfp2", "vfp3", "vfp4", "fp-armv8", "fullfp16", + "neon", "crypto", "dotprod"}) + if (std::find(std::begin(Features), std::end(Features), "+" + Feature) != std::end(Features)) + Features.push_back(Args.MakeArgString("-" + Feature)); } // En/disable crc code generation. @@ -438,7 +448,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC, if (B->getOption().matches(options::OPT_mlong_calls)) D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); } - Features.push_back("+execute-only"); + Features.push_back("+execute-only"); } } } diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp index 5c3953bd478..9c9c1404cba 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp @@ -12,6 +12,7 @@ #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" +#include "Arch/RISCV.h" #include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "Arch/X86.h" @@ -24,12 +25,12 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" -#include "clang/Config/config.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/XRayArgs.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compression.h" @@ -130,6 +131,10 @@ forAllAssociatedToolChains(Compilation &C, const JobAction &JA, Work(*C.getSingleOffloadToolChain<Action::OFK_Cuda>()); else if (JA.isDeviceOffloading(Action::OFK_Cuda)) Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); + else if (JA.isHostOffloading(Action::OFK_HIP)) + Work(*C.getSingleOffloadToolChain<Action::OFK_HIP>()); + else if (JA.isDeviceOffloading(Action::OFK_HIP)) + Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); if (JA.isHostOffloading(Action::OFK_OpenMP)) { auto TCs = C.getOffloadToolChains<Action::OFK_OpenMP>(); @@ -327,6 +332,10 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, case llvm::Triple::ppc64le: ppc::getPPCTargetFeatures(D, Triple, Args, Features); break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + riscv::getRISCVTargetFeatures(D, Args, Features); + break; case llvm::Triple::systemz: systemz::getSystemZTargetFeatures(Args, Features); break; @@ -403,7 +412,6 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, const ToolChain &TC, bool KernelOrKext, const ObjCRuntime &objcRuntime, ArgStringList &CmdArgs) { - const Driver &D = TC.getDriver(); const llvm::Triple &Triple = TC.getTriple(); if (KernelOrKext) { @@ -445,21 +453,6 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, ExceptionArg->getOption().matches(options::OPT_fexceptions); if (CXXExceptionsEnabled) { - if (Triple.isPS4CPU()) { - ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); - assert(ExceptionArg && - "On the PS4 exceptions should only be enabled if passing " - "an argument"); - if (RTTIMode == ToolChain::RM_DisabledExplicitly) { - const Arg *RTTIArg = TC.getRTTIArg(); - assert(RTTIArg && "RTTI disabled explicitly but no RTTIArg!"); - D.Diag(diag::err_drv_argument_not_allowed_with) - << RTTIArg->getAsString(Args) << ExceptionArg->getAsString(Args); - } else if (RTTIMode == ToolChain::RM_EnabledImplicitly) - D.Diag(diag::warn_drv_enabling_rtti_with_exceptions); - } else - assert(TC.getRTTIMode() != ToolChain::RM_DisabledImplicitly); - CmdArgs.push_back("-fcxx-exceptions"); EH = true; @@ -524,10 +517,17 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, // XCore never wants frame pointers, regardless of OS. // WebAssembly never wants frame pointers. return false; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + return !areOptimizationsEnabled(Args); default: break; } + if (Triple.getOS() == llvm::Triple::NetBSD) { + return !areOptimizationsEnabled(Args); + } + if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI) { switch (Triple.getArch()) { // Don't use a frame pointer on linux if optimizing for certain targets. @@ -604,7 +604,19 @@ static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { } } -/// \brief Vectorize at all optimization levels greater than 1 except for -Oz. +/// Add a CC1 and CC1AS option to specify the debug file path prefix map. +static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { + for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; + else + CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); + A->claim(); + } +} + +/// Vectorize at all optimization levels greater than 1 except for -Oz. /// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled. static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) { if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { @@ -826,7 +838,7 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, } } -/// \brief Check whether the given input tree contains any compilation actions. +/// Check whether the given input tree contains any compilation actions. static bool ContainsCompileAction(const Action *A) { if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A)) return true; @@ -838,7 +850,7 @@ static bool ContainsCompileAction(const Action *A) { return false; } -/// \brief Check if -relax-all should be passed to the internal assembler. +/// Check if -relax-all should be passed to the internal assembler. /// This is done by default when compiling non-assembler source with -O0. static bool UseRelaxAll(Compilation &C, const ArgList &Args) { bool RelaxDefault = true; @@ -907,34 +919,46 @@ static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, } } +static bool checkDebugInfoOption(const Arg *A, const ArgList &Args, + const Driver &D, const ToolChain &TC) { + assert(A && "Expected non-nullptr argument."); + if (TC.supportsDebugInfoOption(A)) + return true; + D.Diag(diag::warn_drv_unsupported_debug_info_opt_for_target) + << A->getAsString(Args) << TC.getTripleString(); + return false; +} + static void RenderDebugInfoCompressionArgs(const ArgList &Args, ArgStringList &CmdArgs, - const Driver &D) { + const Driver &D, + const ToolChain &TC) { const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ); if (!A) return; + if (checkDebugInfoOption(A, Args, D, TC)) { + if (A->getOption().getID() == options::OPT_gz) { + if (llvm::zlib::isAvailable()) + CmdArgs.push_back("-compress-debug-sections"); + else + D.Diag(diag::warn_debug_compression_unavailable); + return; + } - if (A->getOption().getID() == options::OPT_gz) { - if (llvm::zlib::isAvailable()) - CmdArgs.push_back("-compress-debug-sections"); - else - D.Diag(diag::warn_debug_compression_unavailable); - return; - } - - StringRef Value = A->getValue(); - if (Value == "none") { - CmdArgs.push_back("-compress-debug-sections=none"); - } else if (Value == "zlib" || Value == "zlib-gnu") { - if (llvm::zlib::isAvailable()) { - CmdArgs.push_back( - Args.MakeArgString("-compress-debug-sections=" + Twine(Value))); + StringRef Value = A->getValue(); + if (Value == "none") { + CmdArgs.push_back("-compress-debug-sections=none"); + } else if (Value == "zlib" || Value == "zlib-gnu") { + if (llvm::zlib::isAvailable()) { + CmdArgs.push_back( + Args.MakeArgString("-compress-debug-sections=" + Twine(Value))); + } else { + D.Diag(diag::warn_debug_compression_unavailable); + } } else { - D.Diag(diag::warn_debug_compression_unavailable); + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; } - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; } } @@ -1064,73 +1088,28 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // wonky, but we include looking for .gch so we can support seamless // replacement into a build system already set up to be generating // .gch files. - int YcIndex = -1, YuIndex = -1; - { - int AI = -1; + + if (getToolChain().getDriver().IsCLMode()) { const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); - for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - // Walk the whole i_Group and skip non "-include" flags so that the index - // here matches the index in the next loop below. - ++AI; - if (!A->getOption().matches(options::OPT_include)) - continue; - if (YcArg && strcmp(A->getValue(), YcArg->getValue()) == 0) - YcIndex = AI; - if (YuArg && strcmp(A->getValue(), YuArg->getValue()) == 0) - YuIndex = AI; + if (YcArg && JA.getKind() >= Action::PrecompileJobClass && + JA.getKind() <= Action::AssembleJobClass) { + CmdArgs.push_back(Args.MakeArgString("-building-pch-with-obj")); + } + if (YcArg || YuArg) { + StringRef ThroughHeader = YcArg ? YcArg->getValue() : YuArg->getValue(); + if (!isa<PrecompileJobAction>(JA)) { + CmdArgs.push_back("-include-pch"); + CmdArgs.push_back(Args.MakeArgString(D.GetClPchPath(C, ThroughHeader))); + } + CmdArgs.push_back( + Args.MakeArgString(Twine("-pch-through-header=") + ThroughHeader)); } - } - if (isa<PrecompileJobAction>(JA) && YcIndex != -1) { - Driver::InputList Inputs; - D.BuildInputs(getToolChain(), C.getArgs(), Inputs); - assert(Inputs.size() == 1 && "Need one input when building pch"); - CmdArgs.push_back(Args.MakeArgString(Twine("-find-pch-source=") + - Inputs[0].second->getValue())); } bool RenderedImplicitInclude = false; - int AI = -1; for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - ++AI; - - if (getToolChain().getDriver().IsCLMode() && - A->getOption().matches(options::OPT_include)) { - // In clang-cl mode, /Ycfoo.h means that all code up to a foo.h - // include is compiled into foo.h, and everything after goes into - // the .obj file. /Yufoo.h means that all includes prior to and including - // foo.h are completely skipped and replaced with a use of the pch file - // for foo.h. (Each flag can have at most one value, multiple /Yc flags - // just mean that the last one wins.) If /Yc and /Yu are both present - // and refer to the same file, /Yc wins. - // Note that OPT__SLASH_FI gets mapped to OPT_include. - // FIXME: The code here assumes that /Yc and /Yu refer to the same file. - // cl.exe seems to support both flags with different values, but that - // seems strange (which flag does /Fp now refer to?), so don't implement - // that until someone needs it. - int PchIndex = YcIndex != -1 ? YcIndex : YuIndex; - if (PchIndex != -1) { - if (isa<PrecompileJobAction>(JA)) { - // When building the pch, skip all includes after the pch. - assert(YcIndex != -1 && PchIndex == YcIndex); - if (AI >= YcIndex) - continue; - } else { - // When using the pch, skip all includes prior to the pch. - if (AI < PchIndex) { - A->claim(); - continue; - } - if (AI == PchIndex) { - A->claim(); - CmdArgs.push_back("-include-pch"); - CmdArgs.push_back( - Args.MakeArgString(D.GetClPchPath(C, A->getValue()))); - continue; - } - } - } - } else if (A->getOption().matches(options::OPT_include)) { + if (A->getOption().matches(options::OPT_include)) { // Handling of gcc-style gch precompiled headers. bool IsFirstImplicitInclude = !RenderedImplicitInclude; RenderedImplicitInclude = true; @@ -1282,6 +1261,8 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { case llvm::Triple::hexagon: case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: case llvm::Triple::systemz: case llvm::Triple::xcore: return false; @@ -1291,6 +1272,8 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { static bool isNoCommonDefault(const llvm::Triple &Triple) { switch (Triple.getArch()) { default: + if (Triple.isOSFuchsia()) + return true; return false; case llvm::Triple::xcore: @@ -1338,7 +1321,7 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, // Forward the -mglobal-merge option for explicit control over the pass. if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, options::OPT_mno_global_merge)) { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); if (A->getOption().matches(options::OPT_mno_global_merge)) CmdArgs.push_back("-arm-global-merge=false"); else @@ -1391,6 +1374,11 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, AddPPCTargetArgs(Args, CmdArgs); break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + AddRISCVTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: @@ -1447,21 +1435,21 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769, options::OPT_mno_fix_cortex_a53_835769)) { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769)) CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); else CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0"); } else if (Triple.isAndroid()) { // Enabled A53 errata (835769) workaround by default on android - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); } // Forward the -mglobal-merge option for explicit control over the pass. if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, options::OPT_mno_global_merge)) { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); if (A->getOption().matches(options::OPT_mno_global_merge)) CmdArgs.push_back("-aarch64-enable-global-merge=false"); else @@ -1668,6 +1656,25 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, } } +void Clang::AddRISCVTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // FIXME: currently defaults to the soft-float ABIs. Will need to be + // expanded to select ilp32f, ilp32d, lp64f, lp64d when appropriate. + const char *ABIName = nullptr; + const llvm::Triple &Triple = getToolChain().getTriple(); + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) + ABIName = A->getValue(); + else if (Triple.getArch() == llvm::Triple::riscv32) + ABIName = "ilp32"; + else if (Triple.getArch() == llvm::Triple::riscv64) + ABIName = "lp64"; + else + llvm_unreachable("Unexpected triple!"); + + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(ABIName); +} + void Clang::AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { sparc::FloatABI FloatABI = @@ -1722,6 +1729,9 @@ void Clang::AddX86TargetArgs(const ArgList &Args, getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } + } else if (getToolChain().getDriver().IsCLMode()) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-x86-asm-syntax=intel"); } // Set flags to support MCU ABI. @@ -2043,7 +2053,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // Handle various floating point optimization flags, mapping them to the // appropriate LLVM code generation flags. This is complicated by several // "umbrella" flags, so we do this by stepping through the flags incrementally - // adjusting what we think is enabled/disabled, then at the end settting the + // adjusting what we think is enabled/disabled, then at the end setting the // LLVM flags based on the final state. bool HonorINFs = true; bool HonorNaNs = true; @@ -2202,6 +2212,11 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-mfpmath"); CmdArgs.push_back(A->getValue()); } + + // Disable a codegen optimization for floating-point casts. + if (Args.hasFlag(options::OPT_fno_strict_float_cast_overflow, + options::OPT_fstrict_float_cast_overflow, false)) + CmdArgs.push_back("-fno-strict-float-cast-overflow"); } static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, @@ -2337,6 +2352,7 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) { options::OPT_cl_no_signed_zeros, options::OPT_cl_denorms_are_zero, options::OPT_cl_fp32_correctly_rounded_divide_sqrt, + options::OPT_cl_uniform_work_group_size }; if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { @@ -2458,6 +2474,13 @@ static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, CmdArgs.push_back("-fno-math-builtin"); } +void Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) { + llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Result); + llvm::sys::path::append(Result, "org.llvm.clang."); + appendUserToPath(Result); + llvm::sys::path::append(Result, "ModuleCache"); +} + static void RenderModulesOptions(Compilation &C, const Driver &D, const ArgList &Args, const InputInfo &Input, const InputInfo &Output, @@ -2499,11 +2522,13 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, CmdArgs.push_back("-fmodules-strict-decluse"); // -fno-implicit-modules turns off implicitly compiling modules on demand. + bool ImplicitModules = false; if (!Args.hasFlag(options::OPT_fimplicit_modules, options::OPT_fno_implicit_modules, HaveClangModules)) { if (HaveModules) CmdArgs.push_back("-fno-implicit-modules"); } else if (HaveModules) { + ImplicitModules = true; // -fmodule-cache-path specifies where our implicitly-built module files // should be written. SmallString<128> Path; @@ -2518,10 +2543,7 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, llvm::sys::path::append(Path, "modules"); } else if (Path.empty()) { // No module path was provided: use the default. - llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Path); - llvm::sys::path::append(Path, "org.llvm.clang."); - appendUserToPath(Path); - llvm::sys::path::append(Path, "ModuleCache"); + Driver::getDefaultModuleCachePath(Path); } const char Arg[] = "-fmodules-cache-path="; @@ -2613,7 +2635,11 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, options::OPT_fmodules_validate_once_per_build_session); } - Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers); + if (Args.hasFlag(options::OPT_fmodules_validate_system_headers, + options::OPT_fno_modules_validate_system_headers, + ImplicitModules)) + CmdArgs.push_back("-fmodules-validate-system-headers"); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); } @@ -2632,6 +2658,9 @@ static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T, CmdArgs.push_back("-fno-signed-char"); } + if (Args.hasFlag(options::OPT_fchar8__t, options::OPT_fno_char8__t, false)) + CmdArgs.push_back("-fchar8_t"); + if (const Arg *A = Args.getLastArg(options::OPT_fshort_wchar, options::OPT_fno_short_wchar)) { if (A->getOption().matches(options::OPT_fshort_wchar)) { @@ -2850,7 +2879,9 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, codegenoptions::DebugInfoKind &DebugInfoKind, const Arg *&SplitDWARFArg) { if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, - options::OPT_fno_debug_info_for_profiling, false)) + options::OPT_fno_debug_info_for_profiling, false) && + checkDebugInfoOption( + Args.getLastArg(options::OPT_fdebug_info_for_profiling), Args, D, TC)) CmdArgs.push_back("-fdebug-info-for-profiling"); // The 'g' groups options involve a somewhat intricate sequence of decisions @@ -2873,29 +2904,38 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, SplitDWARFArg = Args.getLastArg(options::OPT_gsplit_dwarf); + if (SplitDWARFArg && !checkDebugInfoOption(SplitDWARFArg, Args, D, TC)) { + SplitDWARFArg = nullptr; + SplitDWARFInlining = false; + } + if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) { - // If the last option explicitly specified a debug-info level, use it. - if (A->getOption().matches(options::OPT_gN_Group)) { - DebugInfoKind = DebugLevelToInfoKind(*A); - // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. - // But -gsplit-dwarf is not a g_group option, hence we have to check the - // order explicitly. If -gsplit-dwarf wins, we fix DebugInfoKind later. - // This gets a bit more complicated if you've disabled inline info in the - // skeleton CUs (SplitDWARFInlining) - then there's value in composing - // split-dwarf and line-tables-only, so let those compose naturally in - // that case. - // And if you just turned off debug info, (-gsplit-dwarf -g0) - do that. - if (SplitDWARFArg) { - if (A->getIndex() > SplitDWARFArg->getIndex()) { - if (DebugInfoKind == codegenoptions::NoDebugInfo || - (DebugInfoKind == codegenoptions::DebugLineTablesOnly && - SplitDWARFInlining)) - SplitDWARFArg = nullptr; - } else if (SplitDWARFInlining) - DebugInfoKind = codegenoptions::NoDebugInfo; + if (checkDebugInfoOption(A, Args, D, TC)) { + // If the last option explicitly specified a debug-info level, use it. + if (A->getOption().matches(options::OPT_gN_Group)) { + DebugInfoKind = DebugLevelToInfoKind(*A); + // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. + // But -gsplit-dwarf is not a g_group option, hence we have to check the + // order explicitly. If -gsplit-dwarf wins, we fix DebugInfoKind later. + // This gets a bit more complicated if you've disabled inline info in + // the skeleton CUs (SplitDWARFInlining) - then there's value in + // composing split-dwarf and line-tables-only, so let those compose + // naturally in that case. And if you just turned off debug info, + // (-gsplit-dwarf -g0) - do that. + if (SplitDWARFArg) { + if (A->getIndex() > SplitDWARFArg->getIndex()) { + if (DebugInfoKind == codegenoptions::NoDebugInfo || + (DebugInfoKind == codegenoptions::DebugLineTablesOnly && + SplitDWARFInlining)) + SplitDWARFArg = nullptr; + } else if (SplitDWARFInlining) + DebugInfoKind = codegenoptions::NoDebugInfo; + } + } else { + // For any other 'g' option, use Limited. + DebugInfoKind = codegenoptions::LimitedDebugInfo; } } else { - // For any other 'g' option, use Limited. DebugInfoKind = codegenoptions::LimitedDebugInfo; } } @@ -2903,52 +2943,65 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, // If a debugger tuning argument appeared, remember it. if (const Arg *A = Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { - if (A->getOption().matches(options::OPT_glldb)) - DebuggerTuning = llvm::DebuggerKind::LLDB; - else if (A->getOption().matches(options::OPT_gsce)) - DebuggerTuning = llvm::DebuggerKind::SCE; - else - DebuggerTuning = llvm::DebuggerKind::GDB; + if (checkDebugInfoOption(A, Args, D, TC)) { + if (A->getOption().matches(options::OPT_glldb)) + DebuggerTuning = llvm::DebuggerKind::LLDB; + else if (A->getOption().matches(options::OPT_gsce)) + DebuggerTuning = llvm::DebuggerKind::SCE; + else + DebuggerTuning = llvm::DebuggerKind::GDB; + } } // If a -gdwarf argument appeared, remember it. if (const Arg *A = Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, options::OPT_gdwarf_4, options::OPT_gdwarf_5)) - DWARFVersion = DwarfVersionNum(A->getSpelling()); + if (checkDebugInfoOption(A, Args, D, TC)) + DWARFVersion = DwarfVersionNum(A->getSpelling()); // Forward -gcodeview. EmitCodeView might have been set by CL-compatibility // argument parsing. - if (Args.hasArg(options::OPT_gcodeview) || EmitCodeView) { - // DWARFVersion remains at 0 if no explicit choice was made. - CmdArgs.push_back("-gcodeview"); - } else if (DWARFVersion == 0 && - DebugInfoKind != codegenoptions::NoDebugInfo) { - DWARFVersion = TC.GetDefaultDwarfVersion(); + if (EmitCodeView) { + if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) { + EmitCodeView = checkDebugInfoOption(A, Args, D, TC); + if (EmitCodeView) { + // DWARFVersion remains at 0 if no explicit choice was made. + CmdArgs.push_back("-gcodeview"); + } + } } + if (!EmitCodeView && DWARFVersion == 0 && + DebugInfoKind != codegenoptions::NoDebugInfo) + DWARFVersion = TC.GetDefaultDwarfVersion(); + // We ignore flag -gstrict-dwarf for now. // And we handle flag -grecord-gcc-switches later with DWARFDebugFlags. Args.ClaimAllArgs(options::OPT_g_flags_Group); - // Column info is included by default for everything except SCE and CodeView. - // Clang doesn't track end columns, just starting columns, which, in theory, - // is fine for CodeView (and PDB). In practice, however, the Microsoft - // debuggers don't handle missing end columns well, so it's better not to - // include any column info. + // Column info is included by default for everything except SCE and + // CodeView. Clang doesn't track end columns, just starting columns, which, + // in theory, is fine for CodeView (and PDB). In practice, however, the + // Microsoft debuggers don't handle missing end columns well, so it's better + // not to include any column info. + if (const Arg *A = Args.getLastArg(options::OPT_gcolumn_info)) + (void)checkDebugInfoOption(A, Args, D, TC); if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, - /*Default=*/!(IsWindowsMSVC && EmitCodeView) && + /*Default=*/!EmitCodeView && DebuggerTuning != llvm::DebuggerKind::SCE)) CmdArgs.push_back("-dwarf-column-info"); // FIXME: Move backend command line options to the module. // If -gline-tables-only is the last option it wins. - if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && - Args.hasArg(options::OPT_gmodules)) { - DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-dwarf-ext-refs"); - CmdArgs.push_back("-fmodule-format=obj"); - } + if (const Arg *A = Args.getLastArg(options::OPT_gmodules)) + if (checkDebugInfoOption(A, Args, D, TC)) { + if (DebugInfoKind != codegenoptions::DebugLineTablesOnly) { + DebugInfoKind = codegenoptions::LimitedDebugInfo; + CmdArgs.push_back("-dwarf-ext-refs"); + CmdArgs.push_back("-fmodule-format=obj"); + } + } // -gsplit-dwarf should turn on -g and enable the backend dwarf // splitting and extraction. @@ -2972,34 +3025,66 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, options::OPT_fno_standalone_debug, TC.GetDefaultStandaloneDebug()); + if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug)) + (void)checkDebugInfoOption(A, Args, D, TC); if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug) DebugInfoKind = codegenoptions::FullDebugInfo; + if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source, + false)) { + // Source embedding is a vendor extension to DWARF v5. By now we have + // checked if a DWARF version was stated explicitly, and have otherwise + // fallen back to the target default, so if this is still not at least 5 + // we emit an error. + const Arg *A = Args.getLastArg(options::OPT_gembed_source); + if (DWARFVersion < 5) + D.Diag(diag::err_drv_argument_only_allowed_with) + << A->getAsString(Args) << "-gdwarf-5"; + else if (checkDebugInfoOption(A, Args, D, TC)) + CmdArgs.push_back("-gembed-source"); + } + RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion, DebuggerTuning); // -fdebug-macro turns on macro debug info generation. if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, false)) - CmdArgs.push_back("-debug-info-macro"); + if (checkDebugInfoOption(Args.getLastArg(options::OPT_fdebug_macro), Args, + D, TC)) + CmdArgs.push_back("-debug-info-macro"); // -ggnu-pubnames turns on gnu style pubnames in the backend. - if (Args.hasArg(options::OPT_ggnu_pubnames)) - CmdArgs.push_back("-ggnu-pubnames"); + if (Args.hasFlag(options::OPT_ggnu_pubnames, options::OPT_gno_gnu_pubnames, + false)) + if (checkDebugInfoOption(Args.getLastArg(options::OPT_ggnu_pubnames), Args, + D, TC)) + CmdArgs.push_back("-ggnu-pubnames"); // -gdwarf-aranges turns on the emission of the aranges section in the // backend. // Always enabled for SCE tuning. - if (Args.hasArg(options::OPT_gdwarf_aranges) || - DebuggerTuning == llvm::DebuggerKind::SCE) { - CmdArgs.push_back("-backend-option"); + bool NeedAranges = DebuggerTuning == llvm::DebuggerKind::SCE; + if (const Arg *A = Args.getLastArg(options::OPT_gdwarf_aranges)) + NeedAranges = checkDebugInfoOption(A, Args, D, TC) || NeedAranges; + if (NeedAranges) { + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-generate-arange-section"); } if (Args.hasFlag(options::OPT_fdebug_types_section, options::OPT_fno_debug_types_section, false)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-generate-type-units"); + if (!T.isOSBinFormatELF()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Args.getLastArg(options::OPT_fdebug_types_section) + ->getAsString(Args) + << T.getTriple(); + } else if (checkDebugInfoOption( + Args.getLastArg(options::OPT_fdebug_types_section), Args, D, + TC)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-generate-type-units"); + } } // Decide how to render forward declarations of template instantiations. @@ -3007,11 +3092,12 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, if (DebuggerTuning == llvm::DebuggerKind::SCE) CmdArgs.push_back("-debug-forward-template-params"); - // Do we need to explicitly import anonymous namespaces into the parent scope? + // Do we need to explicitly import anonymous namespaces into the parent + // scope? if (DebuggerTuning == llvm::DebuggerKind::SCE) CmdArgs.push_back("-dwarf-explicit-import"); - RenderDebugInfoCompressionArgs(Args, CmdArgs, D); + RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); } void Clang::ConstructJob(Compilation &C, const JobAction &JA, @@ -3029,13 +3115,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Check number of inputs for sanity. We need at least one input. assert(Inputs.size() >= 1 && "Must have at least one input."); const InputInfo &Input = Inputs[0]; - // CUDA compilation may have multiple inputs (source file + results of + // CUDA/HIP compilation may have multiple inputs (source file + results of // device-side compilations). OpenMP device jobs also take the host IR as a // second input. All other jobs are expected to have exactly one // input. bool IsCuda = JA.isOffloading(Action::OFK_Cuda); + bool IsHIP = JA.isOffloading(Action::OFK_HIP); bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); - assert((IsCuda || (IsOpenMPDevice && Inputs.size() == 2) || + assert((IsCuda || IsHIP || (IsOpenMPDevice && Inputs.size() == 2) || Inputs.size() == 1) && "Unable to handle multiple inputs."); @@ -3047,10 +3134,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment(); bool IsIAMCU = RawTriple.isOSIAMCU(); - // Adjust IsWindowsXYZ for CUDA compilations. Even when compiling in device - // mode (i.e., getToolchain().getTriple() is NVPTX, not Windows), we need to - // pass Windows-specific flags to cc1. - if (IsCuda) { + // Adjust IsWindowsXYZ for CUDA/HIP compilations. Even when compiling in + // device mode (i.e., getToolchain().getTriple() is NVPTX/AMDGCN, not + // Windows), we need to pass Windows-specific flags to cc1. + if (IsCuda || IsHIP) { IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment(); IsWindowsGNU |= AuxTriple && AuxTriple->isWindowsGNUEnvironment(); IsWindowsCygnus |= AuxTriple && AuxTriple->isWindowsCygwinEnvironment(); @@ -3074,18 +3161,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_MJ); } - if (IsCuda) { - // We have to pass the triple of the host if compiling for a CUDA device and - // vice-versa. + if (IsCuda || IsHIP) { + // We have to pass the triple of the host if compiling for a CUDA/HIP device + // and vice-versa. std::string NormalizedTriple; - if (JA.isDeviceOffloading(Action::OFK_Cuda)) + if (JA.isDeviceOffloading(Action::OFK_Cuda) || + JA.isDeviceOffloading(Action::OFK_HIP)) NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>() ->getTriple() .normalize(); else - NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Cuda>() - ->getTriple() - .normalize(); + NormalizedTriple = + (IsCuda ? C.getSingleOffloadToolChain<Action::OFK_Cuda>() + : C.getSingleOffloadToolChain<Action::OFK_HIP>()) + ->getTriple() + .normalize(); CmdArgs.push_back("-aux-triple"); CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); @@ -3188,7 +3278,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (JA.getType() == types::TY_LLVM_BC) CmdArgs.push_back("-emit-llvm-uselists"); - if (D.isUsingLTO()) { + // Device-side jobs do not support LTO. + bool isDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) || + JA.isDeviceOffloading(Action::OFK_Host)); + + if (D.isUsingLTO() && !isDeviceOffloadAction) { Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ); // The Darwin and PS4 linkers currently use the legacy LTO API, which @@ -3207,6 +3301,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); } + if (Args.getLastArg(options::OPT_save_temps_EQ)) + Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); + // Embed-bitcode option. if (C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO() && (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) { @@ -3224,13 +3321,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!C.isForDiagnostics()) CmdArgs.push_back("-disable-free"); -// Disable the verification pass in -asserts builds. #ifdef NDEBUG - CmdArgs.push_back("-disable-llvm-verifier"); - // Discard LLVM value names in -asserts builds. - CmdArgs.push_back("-discard-value-names"); + const bool IsAssertBuild = false; +#else + const bool IsAssertBuild = true; #endif + // Disable the verification pass in -asserts builds. + if (!IsAssertBuild) + CmdArgs.push_back("-disable-llvm-verifier"); + + // Discard value names in assert builds unless otherwise specified. + if (Args.hasFlag(options::OPT_fdiscard_value_names, + options::OPT_fno_discard_value_names, !IsAssertBuild)) + CmdArgs.push_back("-discard-value-names"); + // Set the main file name, so that debug info works even with // -save-temps. CmdArgs.push_back("-main-file-name"); @@ -3246,6 +3351,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CheckCodeGenerationOptions(D, Args); + unsigned FunctionAlignment = ParseFunctionAlignment(getToolChain(), Args); + assert(FunctionAlignment <= 31 && "function alignment will be truncated!"); + if (FunctionAlignment) { + CmdArgs.push_back("-function-alignment"); + CmdArgs.push_back(Args.MakeArgString(std::to_string(FunctionAlignment))); + } + llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; @@ -3288,9 +3400,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fveclib); - if (!Args.hasFlag(options::OPT_fmerge_all_constants, - options::OPT_fno_merge_all_constants)) - CmdArgs.push_back("-fno-merge-all-constants"); + if (Args.hasFlag(options::OPT_fmerge_all_constants, + options::OPT_fno_merge_all_constants, false)) + CmdArgs.push_back("-fmerge-all-constants"); + + if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks, + options::OPT_fdelete_null_pointer_checks, false)) + CmdArgs.push_back("-fno-delete-null-pointer-checks"); // LLVM Code Generator Options. @@ -3385,9 +3501,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_strict_vtable_pointers, false)) CmdArgs.push_back("-fstrict-vtable-pointers"); + if (Args.hasFlag(options::OPT_fforce_emit_vtables, + options::OPT_fno_force_emit_vtables, + false)) + CmdArgs.push_back("-fforce-emit-vtables"); if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); + if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls, + options::OPT_fescaping_block_tail_calls, false)) + CmdArgs.push_back("-fno-escaping-block-tail-calls"); Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses, options::OPT_fno_fine_grained_bitfield_accesses); @@ -3407,8 +3530,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.hasArg(options::OPT_dA)) CmdArgs.push_back("-masm-verbose"); - if (!Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as, - IsIntegratedAssemblerDefault)) + if (!getToolChain().useIntegratedAs()) CmdArgs.push_back("-no-integrated-as"); if (Args.hasArg(options::OPT_fdebug_pass_structure)) { @@ -3501,6 +3623,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, types::ID InputType = Input.getType(); if (D.IsCLMode()) AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); + else + EmitCodeView = Args.hasArg(options::OPT_gcodeview); const Arg *SplitDWARFArg = nullptr; RenderDebugOptions(getToolChain(), D, RawTriple, Args, EmitCodeView, @@ -3586,14 +3710,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_finstrument_function_entry_bare)) A->render(Args, CmdArgs); - addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); + // NVPTX doesn't support PGO or coverage. There's no runtime support for + // sampling, overhead of call arc collection is way too high and there's no + // way to collect the output. + if (!Triple.isNVPTX()) + addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); if (auto *ABICompatArg = Args.getLastArg(options::OPT_fclang_abi_compat_EQ)) ABICompatArg->render(Args, CmdArgs); - // Add runtime flag for PS4 when PGO or Coverage are enabled. - if (RawTriple.isPS4CPU()) + // Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled. + if (RawTriple.isPS4CPU()) { PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs); + PS4cpu::addSanitizerArgs(getToolChain(), CmdArgs); + } // Pass options for controlling the default header search paths. if (Args.hasArg(options::OPT_nostdinc)) { @@ -3660,6 +3790,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); Args.AddLastArg(CmdArgs, options::OPT_w); + // Fixed point flags + if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point, + /*Default=*/false)) + Args.AddLastArg(CmdArgs, options::OPT_ffixed_point); + // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} // (-ansi is equivalent to -std=c89 or -std=c++98). // @@ -3744,14 +3879,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add in -fdebug-compilation-dir if necessary. addDebugCompDirArg(Args, CmdArgs); - for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { - StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) - D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; - else - CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); - A->claim(); - } + addDebugPrefixMapArg(D, Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, options::OPT_ftemplate_depth_EQ)) { @@ -3801,6 +3929,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Args.hasFlag(options::OPT_fstack_size_section, + options::OPT_fno_stack_size_section, RawTriple.isPS4())) + CmdArgs.push_back("-fstack-size-section"); + CmdArgs.push_back("-ferror-limit"); if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) CmdArgs.push_back(A->getValue()); @@ -3860,14 +3992,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); + Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs); Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); - // Emulated TLS is enabled by default on Android and OpenBSD, and can be enabled - // manually with -femulated-tls. - bool EmulatedTLSDefault = Triple.isAndroid() || Triple.isOSOpenBSD() || - Triple.isWindowsCygwinEnvironment(); - if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, - EmulatedTLSDefault)) - CmdArgs.push_back("-femulated-tls"); + Args.AddLastArg(CmdArgs, options::OPT_femulated_tls, + options::OPT_fno_emulated_tls); + // AltiVec-like language extensions aren't relevant for assembling. if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) Args.AddLastArg(CmdArgs, options::OPT_fzvector); @@ -3893,7 +4022,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fopenmp_use_tls, options::OPT_fnoopenmp_use_tls, /*Default=*/true)) CmdArgs.push_back("-fnoopenmp-use-tls"); + Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd, + options::OPT_fno_openmp_simd); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); + + // When in OpenMP offloading mode with NVPTX target, forward + // cuda-mode flag + Args.AddLastArg(CmdArgs, options::OPT_fopenmp_cuda_mode, + options::OPT_fno_openmp_cuda_mode); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -4006,26 +4142,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mstack-probe-size=0"); } + if (!Args.hasFlag(options::OPT_mstack_arg_probe, + options::OPT_mno_stack_arg_probe, true)) + CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe")); + if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, options::OPT_mno_restrict_it)) { if (A->getOption().matches(options::OPT_mrestrict_it)) { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-arm-restrict-it"); } else { - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-arm-no-restrict-it"); } } else if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb)) { // Windows on ARM expects restricted IT blocks - CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-arm-restrict-it"); } // Forward -cl options to -cc1 RenderOpenCLOptions(Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) { + CmdArgs.push_back( + Args.MakeArgString(Twine("-fcf-protection=") + A->getValue())); + } + // Forward -f options with positive and negative forms; we translate // these by hand. if (Arg *A = getLastProfileSampleUseArg(Args)) { @@ -4084,8 +4229,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, ToolChain::RTTIMode RTTIMode = getToolChain().getRTTIMode(); if (KernelOrKext || (types::isCXX(InputType) && - (RTTIMode == ToolChain::RM_DisabledExplicitly || - RTTIMode == ToolChain::RM_DisabledImplicitly))) + (RTTIMode == ToolChain::RM_Disabled))) CmdArgs.push_back("-fno-rtti"); // -fshort-enums=0 is default for all architectures except Hexagon. @@ -4107,6 +4251,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, KernelOrKext) CmdArgs.push_back("-fno-use-cxa-atexit"); + if (Args.hasFlag(options::OPT_fregister_global_dtors_with_atexit, + options::OPT_fno_register_global_dtors_with_atexit, + RawTriple.isOSDarwin() && !KernelOrKext)) + CmdArgs.push_back("-fregister-global-dtors-with-atexit"); + // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) @@ -4173,7 +4322,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, !IsWindowsMSVC || IsMSVC2015Compatible)) CmdArgs.push_back("-fno-threadsafe-statics"); - // -fno-delayed-template-parsing is default, except when targetting MSVC. + // -fno-delayed-template-parsing is default, except when targeting MSVC. // Many old Windows SDK versions require this to parse. // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their // compiler. We should be able to disable this by default at some point. @@ -4318,6 +4467,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (!Args.hasFlag(options::OPT_Qy, options::OPT_Qn, true)) + CmdArgs.push_back("-Qn"); + // -fcommon is the default unless compiling kernel code or the target says so bool NoCommonDefault = KernelOrKext || isNoCommonDefault(RawTriple); if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, @@ -4511,31 +4663,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Setup statistics file output. - if (const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ)) { - StringRef SaveStats = A->getValue(); - - SmallString<128> StatsFile; - bool DoSaveStats = false; - if (SaveStats == "obj") { - if (Output.isFilename()) { - StatsFile.assign(Output.getFilename()); - llvm::sys::path::remove_filename(StatsFile); - } - DoSaveStats = true; - } else if (SaveStats == "cwd") { - DoSaveStats = true; - } else { - D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; - } - - if (DoSaveStats) { - StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); - llvm::sys::path::append(StatsFile, BaseName); - llvm::sys::path::replace_extension(StatsFile, "stats"); - CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + - StatsFile)); - } - } + SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); + if (!StatsFile.empty()) + CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile)); // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. @@ -4622,14 +4752,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Flags)); } - // Host-side cuda compilation receives device-side outputs as Inputs[1...]. - // Include them with -fcuda-include-gpubinary. - if (IsCuda && Inputs.size() > 1) - for (auto I = std::next(Inputs.begin()), E = Inputs.end(); I != E; ++I) { + if (IsCuda) { + // Host-side cuda compilation receives all device-side outputs in a single + // fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary. + if (Inputs.size() > 1) { + assert(Inputs.size() == 2 && "More than one GPU binary!"); CmdArgs.push_back("-fcuda-include-gpubinary"); - CmdArgs.push_back(I->getFilename()); + CmdArgs.push_back(Inputs[1].getFilename()); } + if (Args.hasFlag(options::OPT_fcuda_rdc, options::OPT_fno_cuda_rdc, false)) + CmdArgs.push_back("-fcuda-rdc"); + if (Args.hasFlag(options::OPT_fcuda_short_ptr, + options::OPT_fno_cuda_short_ptr, false)) + CmdArgs.push_back("-fcuda-short-ptr"); + } + // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path // to specify the result of the compile phase on the host, so the meaningful // device declarations can be identified. Also, -fopenmp-is-device is passed @@ -4645,7 +4783,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // For all the host OpenMP offloading compile jobs we need to pass the targets // information using -fopenmp-targets= option. - if (isa<CompileJobAction>(JA) && JA.isHostOffloading(Action::OFK_OpenMP)) { + if (JA.isHostOffloading(Action::OFK_OpenMP)) { SmallString<128> TargetInfo("-fopenmp-targets="); Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ); @@ -4704,6 +4842,40 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (Arg *A = Args.getLastArg(options::OPT_fforce_enable_int128, + options::OPT_fno_force_enable_int128)) { + if (A->getOption().matches(options::OPT_fforce_enable_int128)) + CmdArgs.push_back("-fforce-enable-int128"); + } + + if (Args.hasFlag(options::OPT_fcomplete_member_pointers, + options::OPT_fno_complete_member_pointers, false)) + CmdArgs.push_back("-fcomplete-member-pointers"); + + if (Arg *A = Args.getLastArg(options::OPT_moutline, + options::OPT_mno_outline)) { + if (A->getOption().matches(options::OPT_moutline)) { + // We only support -moutline in AArch64 right now. If we're not compiling + // for AArch64, emit a warning and ignore the flag. Otherwise, add the + // proper mllvm flags. + if (Triple.getArch() != llvm::Triple::aarch64) { + D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName(); + } else { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-machine-outliner"); + } + } else { + // Disable all outlining behaviour. + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-machine-outliner=never"); + } + } + + if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig, + getToolChain().getTriple().isOSBinFormatELF() && + getToolChain().useIntegratedAs())) + CmdArgs.push_back("-faddrsig"); + // Finally add the compile command to the compilation. if (Args.hasArg(options::OPT__SLASH_fallback) && Output.getType() == types::TY_Object && @@ -4722,12 +4894,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } - // Handle the debug info splitting at object creation time if we're - // creating an object. - // TODO: Currently only works on linux with newer objcopy. - if (SplitDWARF && Output.getType() == types::TY_Object) - SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDWARFOut); - if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" @@ -4778,6 +4944,13 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime) << value; } + if ((runtime.getKind() == ObjCRuntime::GNUstep) && + (runtime.getVersion() >= VersionTuple(2, 0))) + if (!getToolChain().getTriple().isOSBinFormatELF()) { + getToolChain().getDriver().Diag( + diag::err_drv_gnustep_objc_runtime_incompatible_binary) + << runtime.getVersion().getMajor(); + } runtimeArg->render(args, cmdArgs); return runtime; @@ -4871,7 +5044,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, // Legacy behaviour is to target the gnustep runtime if we are in // non-fragile mode or the GCC runtime in fragile mode. if (isNonFragile) - runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1, 6)); + runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(2, 0)); else runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple()); } @@ -4999,13 +5172,8 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("--dependent-lib=oldnames"); } - // Both /showIncludes and /E (and /EP) write to stdout. Allowing both - // would produce interleaved output, so ignore /showIncludes in such cases. - if ((!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) || - (Args.hasArg(options::OPT__SLASH_P) && - Args.hasArg(options::OPT__SLASH_EP) && !Args.hasArg(options::OPT_E))) - if (Arg *A = Args.getLastArg(options::OPT_show_includes)) - A->render(Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_show_includes)) + A->render(Args, CmdArgs); // This controls whether or not we emit RTTI data for polymorphic types. if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, @@ -5135,6 +5303,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, else CmdArgs.push_back("msvc"); } + + if (Args.hasArg(options::OPT__SLASH_Guard) && + Args.getLastArgValue(options::OPT__SLASH_Guard).equals_lower("cf")) + CmdArgs.push_back("-cfguard"); } visualstudio::Compiler *Clang::getCLFallback() const { @@ -5289,6 +5461,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // Add the -fdebug-compilation-dir flag if needed. addDebugCompDirArg(Args, CmdArgs); + addDebugPrefixMapArg(getToolChain().getDriver(), Args, CmdArgs); + // Set the AT_producer to the clang version when using the integrated // assembler on assembly source files. CmdArgs.push_back("-dwarf-debug-producer"); @@ -5299,7 +5473,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, } RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, llvm::DebuggerKind::Default); - RenderDebugInfoCompressionArgs(Args, CmdArgs, D); + RenderDebugInfoCompressionArgs(Args, CmdArgs, D, getToolChain()); // Handle -fPIC et al -- the relocation-model affects the assembler @@ -5385,19 +5559,17 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); + if (Args.hasArg(options::OPT_gsplit_dwarf) && + getToolChain().getTriple().isOSLinux()) { + CmdArgs.push_back("-split-dwarf-file"); + CmdArgs.push_back(SplitDebugName(Args, Input)); + } + assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); const char *Exec = getToolChain().getDriver().getClangProgramPath(); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); - - // Handle the debug info splitting at object creation time if we're - // creating an object. - // TODO: Currently only works on linux with newer objcopy. - if (Args.hasArg(options::OPT_gsplit_dwarf) && - getToolChain().getTriple().isOSLinux()) - SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, - SplitDebugName(Args, Input)); } // Begin OffloadBundler @@ -5448,6 +5620,10 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, Triples += Action::GetOffloadKindName(CurKind); Triples += '-'; Triples += CurTC->getTriple().normalize(); + if (CurKind == Action::OFK_HIP && CurDep->getOffloadingArch()) { + Triples += '-'; + Triples += CurDep->getOffloadingArch(); + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); @@ -5517,6 +5693,11 @@ void OffloadBundler::ConstructJobMultipleOutputs( Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); Triples += '-'; Triples += Dep.DependentToolChain->getTriple().normalize(); + if (Dep.DependentOffloadKind == Action::OFK_HIP && + !Dep.DependentBoundArch.empty()) { + Triples += '-'; + Triples += Dep.DependentBoundArch; + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp index 49dfeca1b23..66fa21402d7 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp @@ -8,13 +8,14 @@ //===----------------------------------------------------------------------===// #include "Gnu.h" -#include "Linux.h" #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" +#include "Arch/RISCV.h" #include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "CommonArgs.h" +#include "Linux.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" @@ -84,6 +85,13 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().matches(options::OPT_W_Group)) continue; + // Don't forward -mno-unaligned-access since GCC doesn't understand + // it and because it doesn't affect the assembly or link steps. + if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) && + (A->getOption().matches(options::OPT_munaligned_access) || + A->getOption().matches(options::OPT_mno_unaligned_access))) + continue; + A->render(Args, CmdArgs); } } @@ -220,35 +228,6 @@ void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, // The types are (hopefully) good enough. } -static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - // Do not add the XRay runtime to shared libraries. - if (Args.hasArg(options::OPT_shared)) - return false; - - if (Args.hasFlag(options::OPT_fxray_instrument, - options::OPT_fnoxray_instrument, false)) { - CmdArgs.push_back("-whole-archive"); - CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false)); - CmdArgs.push_back("-no-whole-archive"); - return true; - } - - return false; -} - -static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - CmdArgs.push_back("--no-as-needed"); - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lrt"); - CmdArgs.push_back("-lm"); - - if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && - TC.getTriple().getOS() != llvm::Triple::NetBSD) - CmdArgs.push_back("-ldl"); -} - static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { switch (T.getArch()) { case llvm::Triple::x86: @@ -258,7 +237,7 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { case llvm::Triple::aarch64: return "aarch64linux"; case llvm::Triple::aarch64_be: - return "aarch64_be_linux"; + return "aarch64linuxb"; case llvm::Triple::arm: case llvm::Triple::thumb: return "armelf_linux_eabi"; @@ -271,6 +250,10 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { return "elf64ppc"; case llvm::Triple::ppc64le: return "elf64lppc"; + case llvm::Triple::riscv32: + return "elf32lriscv"; + case llvm::Triple::riscv64: + return "elf64lriscv"; case llvm::Triple::sparc: case llvm::Triple::sparcel: return "elf32_sparc"; @@ -300,7 +283,8 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { } static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static)) + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_r)) return false; Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, @@ -373,9 +357,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &Opt : ToolChain.ExtraOpts) CmdArgs.push_back(Opt.c_str()); - if (!Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("--eh-frame-hdr"); - } + CmdArgs.push_back("--eh-frame-hdr"); if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) { CmdArgs.push_back("-m"); @@ -453,8 +435,11 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.AddFilePathLibArgs(Args, CmdArgs); - if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); @@ -490,7 +475,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, linkSanitizerRuntimeDeps(ToolChain, CmdArgs); if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); + linkXRayRuntimeDeps(ToolChain, CmdArgs); bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); @@ -550,6 +535,10 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Add OpenMP offloading linker script args if required. AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); + // Add HIP offloading linker script args if required. + AddHIPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA, + *this); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -624,6 +613,18 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; } + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: { + StringRef ABIName = riscv::getRISCVABI(Args, getToolChain().getTriple()); + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(ABIName.data()); + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + StringRef MArch = A->getValue(); + CmdArgs.push_back("-march"); + CmdArgs.push_back(MArch.data()); + } + break; + } case llvm::Triple::sparc: case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); @@ -706,11 +707,10 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, if (ABIName != "64" && !Args.hasArg(options::OPT_mno_abicalls)) CmdArgs.push_back("-call_nonpic"); - if (getToolChain().getArch() == llvm::Triple::mips || - getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("-EB"); - else + if (getToolChain().getTriple().isLittleEndian()) CmdArgs.push_back("-EL"); + else + CmdArgs.push_back("-EB"); if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { if (StringRef(A->getValue()) == "2008") @@ -834,14 +834,6 @@ static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb; } -static bool isMips32(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel; -} - -static bool isMips64(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; -} - static bool isMipsEL(llvm::Triple::ArchType Arch) { return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el; } @@ -856,6 +848,10 @@ static bool isMicroMips(const ArgList &Args) { return A && A->getOption().matches(options::OPT_mmicromips); } +static bool isRISCV(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::riscv32 || Arch == llvm::Triple::riscv64; +} + static Multilib makeMultilib(StringRef commonSuffix) { return Multilib(commonSuffix, commonSuffix, commonSuffix); } @@ -1300,8 +1296,8 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); Multilib::flags_list Flags; - addMultilibFlag(isMips32(TargetArch), "m32", Flags); - addMultilibFlag(isMips64(TargetArch), "m64", Flags); + addMultilibFlag(TargetTriple.isMIPS32(), "m32", Flags); + addMultilibFlag(TargetTriple.isMIPS64(), "m64", Flags); addMultilibFlag(isMips16(Args), "mips16", Flags); addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || @@ -1401,11 +1397,48 @@ static void findAndroidArmMultilibs(const Driver &D, Result.Multilibs = AndroidArmMultilibs; } +static void findRISCVMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, StringRef Path, + const ArgList &Args, DetectedMultilibs &Result) { + + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32"); + Multilib Ilp32f = + makeMultilib("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f"); + Multilib Ilp32d = + makeMultilib("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d"); + Multilib Lp64 = makeMultilib("lib64/lp64").flag("+m64").flag("+mabi=lp64"); + Multilib Lp64f = makeMultilib("lib64/lp64f").flag("+m64").flag("+mabi=lp64f"); + Multilib Lp64d = makeMultilib("lib64/lp64d").flag("+m64").flag("+mabi=lp64d"); + MultilibSet RISCVMultilibs = + MultilibSet() + .Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d}) + .FilterOut(NonExistent); + + Multilib::flags_list Flags; + bool IsRV64 = TargetTriple.getArch() == llvm::Triple::riscv64; + StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); + + addMultilibFlag(!IsRV64, "m32", Flags); + addMultilibFlag(IsRV64, "m64", Flags); + addMultilibFlag(ABIName == "ilp32", "mabi=ilp32", Flags); + addMultilibFlag(ABIName == "ilp32f", "mabi=ilp32f", Flags); + addMultilibFlag(ABIName == "ilp32d", "mabi=ilp32d", Flags); + addMultilibFlag(ABIName == "lp64", "mabi=lp64", Flags); + addMultilibFlag(ABIName == "lp64f", "mabi=lp64f", Flags); + addMultilibFlag(ABIName == "lp64d", "mabi=lp64d", Flags); + + if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = RISCVMultilibs; +} + static bool findBiarchMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, bool NeedsBiarchSuffix, DetectedMultilibs &Result) { + Multilib Default; + // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit // libs in a subdirectory named 64. The simple logic we follow is that @@ -1413,10 +1446,26 @@ static bool findBiarchMultilibs(const Driver &D, // we use that. If not, and if not a biarch triple alias, we look for // crtbegin.o without the subdirectory. - Multilib Default; + StringRef Suff64 = "/64"; + // Solaris uses platform-specific suffixes instead of /64. + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + switch (TargetTriple.getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + Suff64 = "/amd64"; + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + Suff64 = "/sparcv9"; + break; + default: + break; + } + } + Multilib Alt64 = Multilib() - .gccSuffix("/64") - .includeSuffix("/64") + .gccSuffix(Suff64) + .includeSuffix(Suff64) .flag("-m32") .flag("+m64") .flag("-mx32"); @@ -1491,7 +1540,7 @@ static bool findBiarchMultilibs(const Driver &D, /// all subcommands; this relies on gcc translating the majority of /// command line options. -/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. +/// Less-than for GCCVersion, implementing a Strict Weak Ordering. bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, StringRef RHSPatchSuffix) const { @@ -1525,7 +1574,7 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, return false; } -/// \brief Parse a GCCVersion object out of a string of text. +/// Parse a GCCVersion object out of a string of text. /// /// This is the primary means of forming GCCVersion objects. /*static*/ @@ -1540,21 +1589,29 @@ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { GoodVersion.MajorStr = First.first.str(); if (First.second.empty()) return GoodVersion; - if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) + StringRef MinorStr = Second.first; + if (Second.second.empty()) { + if (size_t EndNumber = MinorStr.find_first_not_of("0123456789")) { + GoodVersion.PatchSuffix = MinorStr.substr(EndNumber); + MinorStr = MinorStr.slice(0, EndNumber); + } + } + if (MinorStr.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) return BadVersion; - GoodVersion.MinorStr = Second.first.str(); + GoodVersion.MinorStr = MinorStr.str(); // First look for a number prefix and parse that if present. Otherwise just // stash the entire patch string in the suffix, and leave the number // unspecified. This covers versions strings such as: // 5 (handled above) // 4.4 + // 4.4-patched // 4.4.0 // 4.4.x // 4.4.2-rc4 // 4.4.x-patched // And retains any patch number it finds. - StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); + StringRef PatchText = Second.second; if (!PatchText.empty()) { if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { // Try to parse the number and any suffix. @@ -1575,7 +1632,7 @@ static llvm::StringRef getGCCToolchainDir(const ArgList &Args) { return GCC_INSTALL_PREFIX; } -/// \brief Initialize a GCCInstallationDetector from the driver. +/// Initialize a GCCInstallationDetector from the driver. /// /// This performs all of the autodetection and sets up the various paths. /// Once constructed, a GCCInstallationDetector is essentially immutable. @@ -1613,21 +1670,17 @@ void Generic_GCC::GCCInstallationDetector::init( // If we have a SysRoot, try that first. if (!D.SysRoot.empty()) { Prefixes.push_back(D.SysRoot); - Prefixes.push_back(D.SysRoot + "/usr"); + AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot); } // Then look for gcc installed alongside clang. Prefixes.push_back(D.InstalledDir + "/.."); - // Then look for distribution supplied gcc installations. + // Next, look for prefix(es) that correspond to distribution-supplied gcc + // installations. if (D.SysRoot.empty()) { - // Look for RHEL devtoolsets. - Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); - // And finally in /usr. - Prefixes.push_back("/usr"); + // Typically /usr. + AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot); } } @@ -1636,18 +1689,21 @@ void Generic_GCC::GCCInstallationDetector::init( // in /usr. This avoids accidentally enforcing the system GCC version // when using a custom toolchain. if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") { - for (StringRef CandidateTriple : ExtraTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) - return; - } - for (StringRef CandidateTriple : CandidateTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) - return; - } - for (StringRef CandidateTriple : CandidateBiarchTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) - return; - } + SmallVector<StringRef, 16> GentooTestTriples; + // Try to match an exact triple as target triple first. + // e.g. crossdev -S x86_64-gentoo-linux-gnu will install gcc libs for + // x86_64-gentoo-linux-gnu. But "clang -target x86_64-gentoo-linux-gnu" + // may pick the libraries for x86_64-pc-linux-gnu even when exact matching + // triple x86_64-gentoo-linux-gnu is present. + GentooTestTriples.push_back(TargetTriple.str()); + // Check rest of triples. + GentooTestTriples.append(ExtraTripleAliases.begin(), + ExtraTripleAliases.end()); + GentooTestTriples.append(CandidateTripleAliases.begin(), + CandidateTripleAliases.end()); + if (ScanGentooConfigs(TargetTriple, Args, GentooTestTriples, + CandidateBiarchTripleAliases)) + return; } // Loop over the various components which exist and select the best GCC @@ -1660,6 +1716,9 @@ void Generic_GCC::GCCInstallationDetector::init( const std::string LibDir = Prefix + Suffix.str(); if (!D.getVFS().exists(LibDir)) continue; + // Try to match the exact target triple first. + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, TargetTriple.str()); + // Try rest of possible triples. for (StringRef Candidate : ExtraTripleAliases) // Try these first. ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); for (StringRef Candidate : CandidateTripleAliases) @@ -1698,6 +1757,49 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { return false; } +void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( + const llvm::Triple &TargetTriple, SmallVectorImpl<std::string> &Prefixes, + StringRef SysRoot) { + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + // Solaris is a special case. + // The GCC installation is under + // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/ + // so we need to find those /usr/gcc/*/lib/gcc libdirs and go with + // /usr/gcc/<version> as a prefix. + + std::string PrefixDir = SysRoot.str() + "/usr/gcc"; + std::error_code EC; + for (vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->getName()); + GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + + // Filter out obviously bad entries. + if (CandidateVersion.Major == -1 || CandidateVersion.isOlderThan(4, 1, 1)) + continue; + + std::string CandidatePrefix = PrefixDir + "/" + VersionText.str(); + std::string CandidateLibPath = CandidatePrefix + "/lib/gcc"; + if (!D.getVFS().exists(CandidateLibPath)) + continue; + + Prefixes.push_back(CandidatePrefix); + } + return; + } + + // Non-Solaris is much simpler - most systems just go with "/usr". + if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux) { + // Yet, still look for RHEL devtoolsets. + Prefixes.push_back("/opt/rh/devtoolset-7/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); + } + Prefixes.push_back(SysRoot.str() + "/usr"); +} + /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, SmallVectorImpl<StringRef> &LibDirs, @@ -1709,22 +1811,20 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { // lifetime or initialization issues. static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; static const char *const AArch64Triples[] = { - "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android", - "aarch64-redhat-linux", "aarch64-suse-linux"}; + "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux", + "aarch64-suse-linux"}; static const char *const AArch64beLibDirs[] = {"/lib"}; static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", "aarch64_be-linux-gnu"}; static const char *const ARMLibDirs[] = {"/lib"}; - static const char *const ARMTriples[] = {"arm-linux-gnueabi", - "arm-linux-androideabi"}; + static const char *const ARMTriples[] = {"arm-linux-gnueabi"}; static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", "armv7hl-redhat-linux-gnueabi", "armv6hl-suse-linux-gnueabi", "armv7hl-suse-linux-gnueabi"}; static const char *const ARMebLibDirs[] = {"/lib"}; - static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", - "armeb-linux-androideabi"}; + static const char *const ARMebTriples[] = {"armeb-linux-gnueabi"}; static const char *const ARMebHFTriples[] = { "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; @@ -1734,16 +1834,15 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", - "x86_64-slackware-linux", "x86_64-linux-android", - "x86_64-unknown-linux"}; + "x86_64-slackware-linux", "x86_64-unknown-linux", + "x86_64-amazon-linux"}; static const char *const X32LibDirs[] = {"/libx32"}; static const char *const X86LibDirs[] = {"/lib32", "/lib"}; static const char *const X86Triples[] = { "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", - "i486-slackware-linux", "i686-montavista-linux", "i686-linux-android", - "i586-linux-gnu"}; + "i486-slackware-linux", "i686-montavista-linux", "i586-linux-gnu"}; static const char *const MIPSLibDirs[] = {"/lib"}; static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux", @@ -1762,13 +1861,6 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64el-linux-gnuabi64"}; - static const char *const MIPSELAndroidLibDirs[] = {"/lib", "/libr2", - "/libr6"}; - static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; - static const char *const MIPS64ELAndroidLibDirs[] = {"/lib64", "/lib", - "/libr2", "/libr6"}; - static const char *const MIPS64ELAndroidTriples[] = { - "mips64el-linux-android"}; static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; static const char *const PPCTriples[] = { @@ -1783,6 +1875,11 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; + static const char *const RISCV32LibDirs[] = {"/lib", "/lib32"}; + static const char *const RISCVTriples[] = {"riscv32-unknown-linux-gnu", + "riscv64-unknown-linux-gnu", + "riscv32-unknown-elf"}; + static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", "sparcv8-linux-gnu"}; @@ -1795,17 +1892,109 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", "s390x-suse-linux", "s390x-redhat-linux"}; - // Solaris. - static const char *const SolarisSPARCLibDirs[] = {"/gcc"}; - static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11", - "i386-pc-solaris2.11"}; using std::begin; using std::end; if (TargetTriple.getOS() == llvm::Triple::Solaris) { - LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs)); - TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples)); + static const char *const SolarisLibDirs[] = {"/lib"}; + static const char *const SolarisSparcV8Triples[] = { + "sparc-sun-solaris2.11", "sparc-sun-solaris2.12"}; + static const char *const SolarisSparcV9Triples[] = { + "sparcv9-sun-solaris2.11", "sparcv9-sun-solaris2.12"}; + static const char *const SolarisX86Triples[] = {"i386-pc-solaris2.11", + "i386-pc-solaris2.12"}; + static const char *const SolarisX86_64Triples[] = {"x86_64-pc-solaris2.11", + "x86_64-pc-solaris2.12"}; + LibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); + BiarchLibDirs.append(begin(SolarisLibDirs), end(SolarisLibDirs)); + switch (TargetTriple.getArch()) { + case llvm::Triple::x86: + TripleAliases.append(begin(SolarisX86Triples), end(SolarisX86Triples)); + BiarchTripleAliases.append(begin(SolarisX86_64Triples), + end(SolarisX86_64Triples)); + break; + case llvm::Triple::x86_64: + TripleAliases.append(begin(SolarisX86_64Triples), + end(SolarisX86_64Triples)); + BiarchTripleAliases.append(begin(SolarisX86Triples), + end(SolarisX86Triples)); + break; + case llvm::Triple::sparc: + TripleAliases.append(begin(SolarisSparcV8Triples), + end(SolarisSparcV8Triples)); + BiarchTripleAliases.append(begin(SolarisSparcV9Triples), + end(SolarisSparcV9Triples)); + break; + case llvm::Triple::sparcv9: + TripleAliases.append(begin(SolarisSparcV9Triples), + end(SolarisSparcV9Triples)); + BiarchTripleAliases.append(begin(SolarisSparcV8Triples), + end(SolarisSparcV8Triples)); + break; + default: + break; + } + return; + } + + // Android targets should not use GNU/Linux tools or libraries. + if (TargetTriple.isAndroid()) { + static const char *const AArch64AndroidTriples[] = { + "aarch64-linux-android"}; + static const char *const ARMAndroidTriples[] = {"arm-linux-androideabi"}; + static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; + static const char *const MIPS64ELAndroidTriples[] = { + "mips64el-linux-android"}; + static const char *const X86AndroidTriples[] = {"i686-linux-android"}; + static const char *const X86_64AndroidTriples[] = {"x86_64-linux-android"}; + + switch (TargetTriple.getArch()) { + case llvm::Triple::aarch64: + LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); + TripleAliases.append(begin(AArch64AndroidTriples), + end(AArch64AndroidTriples)); + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); + TripleAliases.append(begin(ARMAndroidTriples), end(ARMAndroidTriples)); + break; + case llvm::Triple::mipsel: + LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + TripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + break; + case llvm::Triple::mips64el: + LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + TripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + BiarchTripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + break; + case llvm::Triple::x86_64: + LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + TripleAliases.append(begin(X86_64AndroidTriples), + end(X86_64AndroidTriples)); + BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + BiarchTripleAliases.append(begin(X86AndroidTriples), + end(X86AndroidTriples)); + break; + case llvm::Triple::x86: + LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + TripleAliases.append(begin(X86AndroidTriples), end(X86AndroidTriples)); + BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + BiarchTripleAliases.append(begin(X86_64AndroidTriples), + end(X86_64AndroidTriples)); + break; + default: + break; + } + return; } @@ -1870,22 +2059,11 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); break; case llvm::Triple::mipsel: - if (TargetTriple.isAndroid()) { - LibDirs.append(begin(MIPSELAndroidLibDirs), end(MIPSELAndroidLibDirs)); - TripleAliases.append(begin(MIPSELAndroidTriples), - end(MIPSELAndroidTriples)); - BiarchLibDirs.append(begin(MIPS64ELAndroidLibDirs), - end(MIPS64ELAndroidLibDirs)); - BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), - end(MIPS64ELAndroidTriples)); - - } else { - LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); - TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); - BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); - } + LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); break; case llvm::Triple::mips64: LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); @@ -1894,23 +2072,11 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); break; case llvm::Triple::mips64el: - if (TargetTriple.isAndroid()) { - LibDirs.append(begin(MIPS64ELAndroidLibDirs), - end(MIPS64ELAndroidLibDirs)); - TripleAliases.append(begin(MIPS64ELAndroidTriples), - end(MIPS64ELAndroidTriples)); - BiarchLibDirs.append(begin(MIPSELAndroidLibDirs), - end(MIPSELAndroidLibDirs)); - BiarchTripleAliases.append(begin(MIPSELAndroidTriples), - end(MIPSELAndroidTriples)); - - } else { - LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); - BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); - BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); - } + LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); + BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); break; case llvm::Triple::ppc: LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); @@ -1928,6 +2094,12 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs)); TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); break; + case llvm::Triple::riscv32: + LibDirs.append(begin(RISCV32LibDirs), end(RISCV32LibDirs)); + BiarchLibDirs.append(begin(RISCV32LibDirs), end(RISCV32LibDirs)); + TripleAliases.append(begin(RISCVTriples), end(RISCVTriples)); + BiarchTripleAliases.append(begin(RISCVTriples), end(RISCVTriples)); + break; case llvm::Triple::sparc: case llvm::Triple::sparcel: LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); @@ -1960,56 +2132,6 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { BiarchTripleAliases.push_back(BiarchTriple.str()); } -void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( - const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, - const std::string &LibDir, StringRef CandidateTriple, - bool NeedsBiarchSuffix) { - // Solaris is a special case. The GCC installation is under - // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/, so we - // need to iterate twice. - std::error_code EC; - for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->getName()); - GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); - - if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(LI->getName()).second) - continue; // Saw this path before; no need to look at it again. - if (CandidateVersion.isOlderThan(4, 1, 1)) - continue; - if (CandidateVersion <= Version) - continue; - - GCCInstallPath = - LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str(); - if (!D.getVFS().exists(GCCInstallPath)) - continue; - - // If we make it here there has to be at least one GCC version, let's just - // use the latest one. - std::error_code EEC; - for (vfs::directory_iterator - LLI = D.getVFS().dir_begin(GCCInstallPath, EEC), - LLE; - !EEC && LLI != LLE; LLI = LLI.increment(EEC)) { - - StringRef SubVersionText = llvm::sys::path::filename(LLI->getName()); - GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText); - - if (CandidateSubVersion > Version) - Version = CandidateSubVersion; - } - - GCCTriple.setTriple(CandidateTriple); - - GCCInstallPath += "/" + Version.Text; - GCCParentLibPath = GCCInstallPath + "/../../../../"; - - IsValid = true; - } -} - bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( const llvm::Triple &TargetTriple, const ArgList &Args, StringRef Path, bool NeedsBiarchSuffix) { @@ -2022,9 +2144,11 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { // It should also work without multilibs in a simplified toolchain. findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); - } else if (tools::isMipsArch(TargetArch)) { + } else if (TargetTriple.isMIPS()) { if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) return false; + } else if (isRISCV(TargetArch)) { + findRISCVMultilibs(D, TargetTriple, Path, Args, Detected); } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, NeedsBiarchSuffix, Detected)) { return false; @@ -2041,12 +2165,6 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( const llvm::Triple &TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsBiarchSuffix) { - if (TargetTriple.getOS() == llvm::Triple::Solaris) { - scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple, - NeedsBiarchSuffix); - return; - } - llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); // Locations relative to the system lib directory where GCC's triple-specific // directories might reside. @@ -2059,31 +2177,34 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // Whether this library suffix is relevant for the triple. bool Active; } Suffixes[] = { - // This is the normal place. - {"gcc/" + CandidateTriple.str(), "../..", true}, - - // Debian puts cross-compilers in gcc-cross. - {"gcc-cross/" + CandidateTriple.str(), "../..", true}, - - // The Freescale PPC SDK has the gcc libraries in - // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do - // this on Freescale triples, though, since some systems put a *lot* of - // files in that location, not just GCC installation data. - {CandidateTriple.str(), "..", - TargetTriple.getVendor() == llvm::Triple::Freescale}, - - // Natively multiarch systems sometimes put the GCC triple-specific - // directory within their multiarch lib directory, resulting in the - // triple appearing twice. - {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", true}, - - // Deal with cases (on Ubuntu) where the system architecture could be i386 - // but the GCC target architecture could be (say) i686. - // FIXME: It may be worthwhile to generalize this and look for a second - // triple. - {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", - TargetArch == llvm::Triple::x86} - }; + // This is the normal place. + {"gcc/" + CandidateTriple.str(), "../..", true}, + + // Debian puts cross-compilers in gcc-cross. + {"gcc-cross/" + CandidateTriple.str(), "../..", + TargetTriple.getOS() != llvm::Triple::Solaris}, + + // The Freescale PPC SDK has the gcc libraries in + // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do + // this on Freescale triples, though, since some systems put a *lot* of + // files in that location, not just GCC installation data. + {CandidateTriple.str(), "..", + TargetTriple.getVendor() == llvm::Triple::Freescale || + TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}, + + // Natively multiarch systems sometimes put the GCC triple-specific + // directory within their multiarch lib directory, resulting in the + // triple appearing twice. + {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", + TargetTriple.getOS() != llvm::Triple::Solaris}, + + // Deal with cases (on Ubuntu) where the system architecture could be i386 + // but the GCC target architecture could be (say) i686. + // FIXME: It may be worthwhile to generalize this and look for a second + // triple. + {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", + (TargetArch == llvm::Triple::x86 && + TargetTriple.getOS() != llvm::Triple::Solaris)}}; for (auto &Suffix : Suffixes) { if (!Suffix.Active) @@ -2121,6 +2242,22 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( } } +bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( + const llvm::Triple &TargetTriple, const ArgList &Args, + const SmallVectorImpl<StringRef> &CandidateTriples, + const SmallVectorImpl<StringRef> &CandidateBiarchTriples) { + for (StringRef CandidateTriple : CandidateTriples) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) + return true; + } + + for (StringRef CandidateTriple : CandidateBiarchTriples) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) + return true; + } + return false; +} + bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( const llvm::Triple &TargetTriple, const ArgList &Args, StringRef CandidateTriple, bool NeedsBiarchSuffix) { @@ -2133,23 +2270,53 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( for (StringRef Line : Lines) { Line = Line.trim(); // CURRENT=triple-version - if (Line.consume_front("CURRENT=")) { - const std::pair<StringRef, StringRef> ActiveVersion = - Line.rsplit('-'); - // Note: Strictly speaking, we should be reading - // /etc/env.d/gcc/${CURRENT} now. However, the file doesn't - // contain anything new or especially useful to us. - const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" + - ActiveVersion.first.str() + "/" + - ActiveVersion.second.str(); + if (!Line.consume_front("CURRENT=")) + continue; + // Process the config file pointed to by CURRENT. + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ConfigFile = + D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/" + + Line.str()); + std::pair<StringRef, StringRef> ActiveVersion = Line.rsplit('-'); + // List of paths to scan for libraries. + SmallVector<StringRef, 4> GentooScanPaths; + // Scan the Config file to find installed GCC libraries path. + // Typical content of the GCC config file: + // LDPATH="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x:/usr/lib/gcc/ + // (continued from previous line) x86_64-pc-linux-gnu/4.9.x/32" + // MANPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/man" + // INFOPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/info" + // STDCXX_INCDIR="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x/include/g++-v4" + // We are looking for the paths listed in LDPATH=... . + if (ConfigFile) { + SmallVector<StringRef, 2> ConfigLines; + ConfigFile.get()->getBuffer().split(ConfigLines, "\n"); + for (StringRef ConfLine : ConfigLines) { + ConfLine = ConfLine.trim(); + if (ConfLine.consume_front("LDPATH=")) { + // Drop '"' from front and back if present. + ConfLine.consume_back("\""); + ConfLine.consume_front("\""); + // Get all paths sperated by ':' + ConfLine.split(GentooScanPaths, ':', -1, /*AllowEmpty*/ false); + } + } + } + // Test the path based on the version in /etc/env.d/gcc/config-{tuple}. + std::string basePath = "/usr/lib/gcc/" + ActiveVersion.first.str() + "/" + + ActiveVersion.second.str(); + GentooScanPaths.push_back(StringRef(basePath)); + + // Scan all paths for GCC libraries. + for (const auto &GentooScanPath : GentooScanPaths) { + std::string GentooPath = D.SysRoot + std::string(GentooScanPath); if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, NeedsBiarchSuffix)) - return false; + continue; Version = GCCVersion::Parse(ActiveVersion.second); GCCInstallPath = GentooPath; - GCCParentLibPath = GentooPath + "/../../.."; + GCCParentLibPath = GentooPath + std::string("/../../.."); GCCTriple.setTriple(ActiveVersion.first); IsValid = true; return true; @@ -2240,6 +2407,8 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: case llvm::Triple::systemz: case llvm::Triple::mips: case llvm::Triple::mipsel: @@ -2267,12 +2436,9 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, return; switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: { - std::string Path = findLibCxxIncludePath(); - if (!Path.empty()) - addSystemInclude(DriverArgs, CC1Args, Path); + case ToolChain::CST_Libcxx: + addLibCxxIncludePaths(DriverArgs, CC1Args); break; - } case ToolChain::CST_Libstdcxx: addLibStdCxxIncludePaths(DriverArgs, CC1Args); @@ -2280,9 +2446,12 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } -std::string Generic_GCC::findLibCxxIncludePath() const { +void +Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { // FIXME: The Linux behavior would probaby be a better approach here. - return getDriver().SysRoot + "/usr/include/c++/v1"; + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/v1"); } void @@ -2292,7 +2461,7 @@ Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, // FIXME: If we have a valid GCCInstallation, use it. } -/// \brief Helper to add the variant paths of a libstdc++ installation. +/// Helper to add the variant paths of a libstdc++ installation. bool Generic_GCC::addLibStdCXXIncludePaths( Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, Twine IncludeSuffix, @@ -2377,6 +2546,8 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, bool UseInitArrayDefault = getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::aarch64_be || + (getTriple().getOS() == llvm::Triple::FreeBSD && + getTriple().getOSMajorVersion() >= 12) || (getTriple().getOS() == llvm::Triple::Linux && ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) || getTriple().isAndroid())) || diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp index ca8321c2474..e199c38966b 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -15,6 +15,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" using namespace clang::driver; @@ -69,10 +70,10 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mabi"); CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - if (getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("-EB"); - else + if (getToolChain().getTriple().isLittleEndian()) CmdArgs.push_back("-EL"); + else + CmdArgs.push_back("-EB"); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); break; @@ -99,6 +100,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const toolchains::OpenBSD &ToolChain = + static_cast<const toolchains::OpenBSD &>(getToolChain()); const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; @@ -137,7 +140,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_pie)) CmdArgs.push_back("-pie"); - if (Args.hasArg(options::OPT_nopie)) + if (Args.hasArg(options::OPT_nopie) || Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-nopie"); if (Output.isFilename()) { @@ -174,6 +177,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -185,7 +190,14 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-lm"); } - + if (NeedsSanitizerDeps) { + CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins", false)); + linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + } + if (NeedsXRayDeps) { + CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins", false)); + linkXRayRuntimeDeps(ToolChain, CmdArgs); + } // FIXME: For some reason GCC passes -lgcc before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lcompiler_rt"); @@ -216,10 +228,28 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); } - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + const char *Exec = Args.MakeArgString( + !NeedsSanitizerDeps ? getToolChain().GetLinkerPath() + : getToolChain().GetProgramPath("ld.lld")); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } +SanitizerMask OpenBSD::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + + // For future use, only UBsan at the moment + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + + if (IsX86 || IsX86_64) { + Res |= SanitizerKind::Vptr; + Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + } + + return Res; +} + /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, @@ -276,14 +306,16 @@ void OpenBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - switch (GetCXXStdlibType(Args)) { + bool Profiling = Args.hasArg(options::OPT_pg); + + switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lpthread"); + CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi"); + CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread"); break; case ToolChain::CST_Libstdcxx: - CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); break; } } diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h b/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h index 750c87b58d8..1aba4de44c5 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h @@ -58,19 +58,21 @@ public: bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } bool isPIEDefault() const override { return true; } + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return 2; } unsigned GetDefaultDwarfVersion() const override { return 2; } + SanitizerMask getSupportedSanitizers() const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/gnu/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/gnu/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index a637af723ab..de089ad0c17 100644 --- a/gnu/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/gnu/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -1,4 +1,4 @@ -//===--- CompilerInvocation.cpp -------------------------------------------===// +//===- CompilerInvocation.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,54 +10,99 @@ #include "clang/Frontend/CompilerInvocation.h" #include "TestModuleFileExtension.h" #include "clang/Basic/Builtins.h" -#include "clang/Basic/FileManager.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/CommentOptions.h" +#include "clang/Basic/DebugInfoOptions.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/Sanitizers.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Basic/Visibility.h" +#include "clang/Basic/XRayInstr.h" #include "clang/Config/config.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" -#include "clang/Driver/Util.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "clang/Frontend/CommandLineSourceLoc.h" +#include "clang/Frontend/DependencyOutputOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/LangStandard.h" +#include "clang/Frontend/MigratorOptions.h" +#include "clang/Frontend/PreprocessorOutputOptions.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/PreprocessorOptions.h" -#include "clang/Serialization/ASTReader.h" +#include "clang/Sema/CodeCompleteOptions.h" #include "clang/Serialization/ModuleFileExtension.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/Hashing.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" #include "llvm/Linker/Linker.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" +#include "llvm/Option/OptSpecifier.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/Support/ScopedPrinter.h" +#include <algorithm> #include <atomic> +#include <cassert> +#include <cstddef> +#include <cstring> #include <memory> -#include <sys/stat.h> -#include <system_error> +#include <string> +#include <tuple> +#include <utility> +#include <vector> + using namespace clang; +using namespace driver; +using namespace options; +using namespace llvm::opt; //===----------------------------------------------------------------------===// // Initialization. //===----------------------------------------------------------------------===// CompilerInvocationBase::CompilerInvocationBase() - : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()), - DiagnosticOpts(new DiagnosticOptions()), - HeaderSearchOpts(new HeaderSearchOptions()), - PreprocessorOpts(new PreprocessorOptions()) {} + : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()), + DiagnosticOpts(new DiagnosticOptions()), + HeaderSearchOpts(new HeaderSearchOptions()), + PreprocessorOpts(new PreprocessorOptions()) {} CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X) : LangOpts(new LangOptions(*X.getLangOpts())), @@ -66,18 +111,12 @@ CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X) HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())), PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())) {} -CompilerInvocationBase::~CompilerInvocationBase() {} +CompilerInvocationBase::~CompilerInvocationBase() = default; //===----------------------------------------------------------------------===// // Deserialization (from args) //===----------------------------------------------------------------------===// -using namespace clang::driver; -using namespace clang::driver::options; -using namespace llvm::opt; - -// - static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { unsigned DefaultOpt = 0; @@ -91,7 +130,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, if (A->getOption().matches(options::OPT_Ofast)) return 3; - assert (A->getOption().matches(options::OPT_O)); + assert(A->getOption().matches(options::OPT_O)); StringRef S(A->getValue()); if (S == "s" || S == "z" || S.empty()) @@ -125,7 +164,7 @@ static unsigned getOptimizationLevelSize(ArgList &Args) { static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group, OptSpecifier GroupWithValue, std::vector<std::string> &Diagnostics) { - for (Arg *A : Args.filtered(Group)) { + for (auto *A : Args.filtered(Group)) { if (A->getOption().getKind() == Option::FlagClass) { // The argument is a pure flag (such as OPT_Wall or OPT_Wdeprecated). Add // its name (minus the "W" or "R" at the beginning) to the warning list. @@ -135,7 +174,7 @@ static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group, Diagnostics.push_back(A->getOption().getName().drop_front(1).rtrim("=-")); } else { // Otherwise, add its value (for OPT_W_Joined and similar). - for (const char *Arg : A->getValues()) + for (const auto *Arg : A->getValues()) Diagnostics.emplace_back(Arg); } } @@ -157,7 +196,6 @@ static void getAllNoBuiltinFuncValues(ArgList &Args, static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { - using namespace options; bool Success = true; if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { StringRef Name = A->getValue(); @@ -273,31 +311,31 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, StringRef checkerList = A->getValue(); SmallVector<StringRef, 4> checkers; checkerList.split(checkers, ","); - for (StringRef checker : checkers) + for (auto checker : checkers) Opts.CheckersControlList.emplace_back(checker, enable); } // Go through the analyzer configuration options. - for (const Arg *A : Args.filtered(OPT_analyzer_config)) { + for (const auto *A : Args.filtered(OPT_analyzer_config)) { A->claim(); // We can have a list of comma separated config names, e.g: // '-analyzer-config key1=val1,key2=val2' StringRef configList = A->getValue(); SmallVector<StringRef, 4> configVals; configList.split(configVals, ","); - for (unsigned i = 0, e = configVals.size(); i != e; ++i) { + for (const auto &configVal : configVals) { StringRef key, val; - std::tie(key, val) = configVals[i].split("="); + std::tie(key, val) = configVal.split("="); if (val.empty()) { Diags.Report(SourceLocation(), - diag::err_analyzer_config_no_value) << configVals[i]; + diag::err_analyzer_config_no_value) << configVal; Success = false; break; } if (val.find('=') != StringRef::npos) { Diags.Report(SourceLocation(), diag::err_analyzer_config_multiple_values) - << configVals[i]; + << configVal; Success = false; break; } @@ -305,6 +343,14 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } } + llvm::raw_string_ostream os(Opts.FullCompilerInvocation); + for (unsigned i = 0; i < Args.getNumInputArgStrings(); ++i) { + if (i != 0) + os << " "; + os << Args.getArgString(i); + } + os.flush(); + return Success; } @@ -330,18 +376,26 @@ static StringRef getCodeModel(ArgList &Args, DiagnosticsEngine &Diags) { return "default"; } -static StringRef getRelocModel(ArgList &Args, DiagnosticsEngine &Diags) { +static llvm::Reloc::Model getRelocModel(ArgList &Args, + DiagnosticsEngine &Diags) { if (Arg *A = Args.getLastArg(OPT_mrelocation_model)) { StringRef Value = A->getValue(); - if (Value == "static" || Value == "pic" || Value == "ropi" || - Value == "rwpi" || Value == "ropi-rwpi" || Value == "dynamic-no-pic") - return Value; + auto RM = llvm::StringSwitch<llvm::Optional<llvm::Reloc::Model>>(Value) + .Case("static", llvm::Reloc::Static) + .Case("pic", llvm::Reloc::PIC_) + .Case("ropi", llvm::Reloc::ROPI) + .Case("rwpi", llvm::Reloc::RWPI) + .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI) + .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC) + .Default(None); + if (RM.hasValue()) + return *RM; Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Value; } - return "pic"; + return llvm::Reloc::PIC_; } -/// \brief Create a new Regex instance out of the string value in \p RpassArg. +/// Create a new Regex instance out of the string value in \p RpassArg. /// It returns a pointer to the newly generated Regex instance. static std::shared_ptr<llvm::Regex> GenerateOptimizationRemarkRegex(DiagnosticsEngine &Diags, ArgList &Args, @@ -392,6 +446,25 @@ static void parseSanitizerKinds(StringRef FlagName, } } +static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle, + ArgList &Args, DiagnosticsEngine &D, + XRayInstrSet &S) { + llvm::SmallVector<StringRef, 2> BundleParts; + llvm::SplitString(Bundle, BundleParts, ","); + for (const auto B : BundleParts) { + auto Mask = parseXRayInstrValue(B); + if (Mask == XRayInstrKind::None) + if (B != "none") + D.Report(diag::err_drv_invalid_value) << FlagName << Bundle; + else + S.Mask = Mask; + else if (Mask == XRayInstrKind::All) + S.Mask = Mask; + else + S.set(Mask, true); + } +} + // Set the profile kind for fprofile-instrument. static void setPGOInstrumentor(CodeGenOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { @@ -409,8 +482,7 @@ static void setPGOInstrumentor(CodeGenOptions &Opts, ArgList &Args, << S; return; } - CodeGenOptions::ProfileInstrKind Instrumentor = - static_cast<CodeGenOptions::ProfileInstrKind>(I); + auto Instrumentor = static_cast<CodeGenOptions::ProfileInstrKind>(I); Opts.setProfileInstr(Instrumentor); } @@ -434,8 +506,8 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts, static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags, - const TargetOptions &TargetOpts) { - using namespace options; + const TargetOptions &TargetOpts, + const FrontendOptions &FrontendOpts) { bool Success = true; llvm::Triple Triple = llvm::Triple(TargetOpts.Triple); @@ -474,7 +546,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.ExperimentalNewPassManager = Args.hasFlag( OPT_fexperimental_new_pass_manager, OPT_fno_experimental_new_pass_manager, - /* Default */ false); + /* Default */ ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER); Opts.DebugPassManager = Args.hasFlag(OPT_fdebug_pass_manager, OPT_fno_debug_pass_manager, @@ -529,6 +601,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs); Opts.DebugExplicitImport = Args.hasArg(OPT_dwarf_explicit_import); Opts.DebugFwdTemplateParams = Args.hasArg(OPT_debug_forward_template_params); + Opts.EmbedSource = Args.hasArg(OPT_gembed_source); for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) Opts.DebugPrefixMap.insert(StringRef(Arg).split('=')); @@ -552,7 +625,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasFlag(OPT_ffine_grained_bitfield_accesses, OPT_fno_fine_grained_bitfield_accesses, false); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); - Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); + Opts.MergeAllConstants = Args.hasArg(OPT_fmerge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); Opts.OptimizeSize = getOptimizationLevelSize(Args); @@ -580,33 +653,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, if (!Opts.ProfileInstrumentUsePath.empty()) setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath); - if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) { - Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest); - - StringRef Ver = A->getValue(); - std::pair<StringRef, StringRef> VerParts = Ver.split('.'); - unsigned Major, Minor = 0; - - // Check the version number is valid: either 3.x (0 <= x <= 9) or - // y or y.0 (4 <= y <= current version). - if (!VerParts.first.startswith("0") && - !VerParts.first.getAsInteger(10, Major) && - 3 <= Major && Major <= CLANG_VERSION_MAJOR && - (Major == 3 ? VerParts.second.size() == 1 && - !VerParts.second.getAsInteger(10, Minor) - : VerParts.first.size() == Ver.size() || - VerParts.second == "0")) { - // Got a valid version number. - if (Major == 3 && Minor <= 8) - Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver3_8); - else if (Major <= 4) - Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4); - } else if (Ver != "latest") { - Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(); - } - } - Opts.CoverageMapping = Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false); Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); @@ -615,6 +661,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); + Opts.RegisterGlobalDtorsWithAtExit = + Args.hasArg(OPT_fregister_global_dtors_with_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = getCodeModel(Args, Diags); Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass); @@ -623,6 +671,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DisableFree = Args.hasArg(OPT_disable_free); Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names); Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls); + Opts.NoEscapingBlockTailCalls = + Args.hasArg(OPT_fno_escaping_block_tail_calls); Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi); Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable) || Args.hasArg(OPT_cl_unsafe_math_optimizations) || @@ -640,14 +690,20 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math)); Opts.Reassociate = Args.hasArg(OPT_mreassociate); - Opts.FlushDenorm = Args.hasArg(OPT_cl_denorms_are_zero); + Opts.FlushDenorm = Args.hasArg(OPT_cl_denorms_are_zero) || + (Args.hasArg(OPT_fcuda_is_device) && + Args.hasArg(OPT_fcuda_flush_denormals_to_zero)); Opts.CorrectlyRoundedDivSqrt = Args.hasArg(OPT_cl_fp32_correctly_rounded_divide_sqrt); + Opts.UniformWGSize = + Args.hasArg(OPT_cl_uniform_work_group_size); Opts.Reciprocals = Args.getAllArgValues(OPT_mrecip_EQ); Opts.ReciprocalMath = Args.hasArg(OPT_freciprocal_math); Opts.NoTrappingMath = Args.hasArg(OPT_fno_trapping_math); + Opts.StrictFloatCastOverflow = + !Args.hasArg(OPT_fno_strict_float_cast_overflow); + Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); - Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option); Opts.NumRegisterParameters = getLastArgIntValue(Args, OPT_mregparm, 0, Diags); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); @@ -665,6 +721,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.StrictEnums = Args.hasArg(OPT_fstrict_enums); Opts.StrictReturn = !Args.hasArg(OPT_fno_strict_return); Opts.StrictVTablePointers = Args.hasArg(OPT_fstrict_vtable_pointers); + Opts.ForceEmitVTables = Args.hasArg(OPT_fforce_emit_vtables); Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) || Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); @@ -682,6 +739,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, OPT_fno_function_sections, false); Opts.DataSections = Args.hasFlag(OPT_fdata_sections, OPT_fno_data_sections, false); + Opts.StackSizeSection = + Args.hasFlag(OPT_fstack_size_section, OPT_fno_stack_size_section, false); Opts.UniqueSectionNames = Args.hasFlag(OPT_funique_section_names, OPT_fno_unique_section_names, true); @@ -689,14 +748,16 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables); + Opts.NullPointerIsValid = Args.hasArg(OPT_fno_delete_null_pointer_checks); + Opts.ProfileSampleAccurate = Args.hasArg(OPT_fprofile_sample_accurate); Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ); - Opts.EmitSummaryIndex = false; + Opts.PrepareForThinLTO = false; if (Arg *A = Args.getLastArg(OPT_flto_EQ)) { StringRef S = A->getValue(); if (S == "thin") - Opts.EmitSummaryIndex = true; + Opts.PrepareForThinLTO = true; else if (S != "full") Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S; } @@ -707,6 +768,12 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, << A->getAsString(Args) << "-x ir"; Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ); } + if (Arg *A = Args.getLastArg(OPT_save_temps_EQ)) + Opts.SaveTempsFilePrefix = + llvm::StringSwitch<std::string>(A->getValue()) + .Case("obj", FrontendOpts.OutputFile) + .Default(llvm::sys::path::filename(FrontendOpts.OutputFile).str()); + Opts.ThinLinkBitcodeFile = Args.getLastArgValue(OPT_fthin_link_bitcode_EQ); Opts.MSVolatile = Args.hasArg(OPT_fms_volatile); @@ -719,6 +786,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); + Opts.ControlFlowGuard = Args.hasArg(OPT_cfguard); + Opts.DisableGCov = Args.hasArg(OPT_test_coverage); Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); @@ -741,7 +810,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } } - // Handle -fembed-bitcode option. + // Handle -fembed-bitcode option. if (Arg *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) { StringRef Name = A->getValue(); unsigned Model = llvm::StringSwitch<unsigned>(Name) @@ -787,15 +856,44 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.hasArg(OPT_finstrument_functions_after_inlining); Opts.InstrumentFunctionEntryBare = Args.hasArg(OPT_finstrument_function_entry_bare); - Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument); + + Opts.XRayInstrumentFunctions = + Args.hasArg(OPT_fxray_instrument); Opts.XRayAlwaysEmitCustomEvents = Args.hasArg(OPT_fxray_always_emit_customevents); + Opts.XRayAlwaysEmitTypedEvents = + Args.hasArg(OPT_fxray_always_emit_typedevents); Opts.XRayInstructionThreshold = getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags); + + auto XRayInstrBundles = + Args.getAllArgValues(OPT_fxray_instrumentation_bundle); + if (XRayInstrBundles.empty()) + Opts.XRayInstrumentationBundle.Mask = XRayInstrKind::All; + else + for (const auto &A : XRayInstrBundles) + parseXRayInstrumentationBundle("-fxray-instrumentation-bundle=", A, Args, + Diags, Opts.XRayInstrumentationBundle); + Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.CallFEntry = Args.hasArg(OPT_mfentry); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { + StringRef Name = A->getValue(); + if (Name == "full") { + Opts.CFProtectionReturn = 1; + Opts.CFProtectionBranch = 1; + } else if (Name == "return") + Opts.CFProtectionReturn = 1; + else if (Name == "branch") + Opts.CFProtectionBranch = 1; + else if (Name != "none") { + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; + Success = false; + } + } + if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections, OPT_compress_debug_sections_EQ)) { if (A->getOption().getID() == OPT_compress_debug_sections) { @@ -813,7 +911,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); - for (auto A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) { + for (auto *A : + Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) { CodeGenOptions::BitcodeFileToLink F; F.Filename = A->getValue(); if (A->getOption().matches(OPT_mlink_cuda_bitcode)) { @@ -855,6 +954,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.SanitizeCfiICallGeneralizePointers = Args.hasArg(OPT_fsanitize_cfi_icall_generalize_pointers); Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats); + if (Arg *A = Args.getLastArg( + OPT_fsanitize_address_poison_class_member_array_new_cookie, + OPT_fno_sanitize_address_poison_class_member_array_new_cookie)) { + Opts.SanitizeAddressPoisonClassMemberArrayNewCookie = + A->getOption().getID() == + OPT_fsanitize_address_poison_class_member_array_new_cookie; + } if (Arg *A = Args.getLastArg(OPT_fsanitize_address_use_after_scope, OPT_fno_sanitize_address_use_after_scope)) { Opts.SanitizeAddressUseAfterScope = @@ -881,6 +987,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.StackProbeSize = StackProbeSize; } + Opts.NoStackArgProbe = Args.hasArg(OPT_mno_stack_arg_probe); + if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { StringRef Name = A->getValue(); unsigned Method = llvm::StringSwitch<unsigned>(Name) @@ -897,8 +1005,12 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } - Opts.EmulatedTLS = - Args.hasFlag(OPT_femulated_tls, OPT_fno_emulated_tls, false); + if (Args.getLastArg(OPT_femulated_tls) || + Args.getLastArg(OPT_fno_emulated_tls)) { + Opts.ExplicitEmulatedTLS = true; + Opts.EmulatedTLS = + Args.hasFlag(OPT_femulated_tls, OPT_fno_emulated_tls, false); + } if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) { StringRef Name = A->getValue(); @@ -969,7 +1081,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, bool UsingProfile = UsingSampleProfile || (Opts.getProfileUse() != CodeGenOptions::ProfileNone); - if (Opts.DiagnosticsWithHotness && !UsingProfile) + if (Opts.DiagnosticsWithHotness && !UsingProfile && + // An IR file will contain PGO as metadata + IK.getLanguage() != InputKind::LLVM_IR) Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo) << "-fdiagnostics-show-hotness"; @@ -1001,20 +1115,23 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Args.getAllArgValues(OPT_fsanitize_trap_EQ), Diags, Opts.SanitizeTrap); - Opts.CudaGpuBinaryFileNames = - Args.getAllArgValues(OPT_fcuda_include_gpubinary); + Opts.CudaGpuBinaryFileName = + Args.getLastArgValue(OPT_fcuda_include_gpubinary); Opts.Backchain = Args.hasArg(OPT_mbackchain); Opts.EmitCheckPathComponentsToStrip = getLastArgIntValue( Args, OPT_fsanitize_undefined_strip_path_components_EQ, 0, Diags); + Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); + + Opts.Addrsig = Args.hasArg(OPT_faddrsig); + return Success; } static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, ArgList &Args) { - using namespace options; Opts.OutputFile = Args.getLastArgValue(OPT_dependency_file); Opts.Targets = Args.getAllArgValues(OPT_MT); Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps); @@ -1023,7 +1140,17 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, Opts.ShowHeaderIncludes = Args.hasArg(OPT_H); Opts.HeaderIncludeOutputFile = Args.getLastArgValue(OPT_header_include_file); Opts.AddMissingHeaderDeps = Args.hasArg(OPT_MG); - Opts.PrintShowIncludes = Args.hasArg(OPT_show_includes); + if (Args.hasArg(OPT_show_includes)) { + // Writing both /showIncludes and preprocessor output to stdout + // would produce interleaved output, so use stderr for /showIncludes. + // This behaves the same as cl.exe, when /E, /EP or /P are passed. + if (Args.hasArg(options::OPT_E) || Args.hasArg(options::OPT_P)) + Opts.ShowIncludesDest = ShowIncludesDestination::Stderr; + else + Opts.ShowIncludesDest = ShowIncludesDestination::Stdout; + } else { + Opts.ShowIncludesDest = ShowIncludesDestination::None; + } Opts.DOTOutputFile = Args.getLastArgValue(OPT_dependency_dot); Opts.ModuleDependencyOutputDir = Args.getLastArgValue(OPT_module_dependency_dir); @@ -1034,7 +1161,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, // we let make / ninja to know about this implicit dependency. Opts.ExtraDeps = Args.getAllArgValues(OPT_fdepfile_entry); // Only the -fmodule-file=<file> form. - for (const Arg *A : Args.filtered(OPT_fmodule_file)) { + for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); if (Val.find('=') == StringRef::npos) Opts.ExtraDeps.push_back(Val); @@ -1051,7 +1178,7 @@ static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) { Colors_Off, Colors_Auto } ShowColors = DefaultColor ? Colors_Auto : Colors_Off; - for (Arg *A : Args) { + for (auto *A : Args) { const Option &O = A->getOption(); if (O.matches(options::OPT_fcolor_diagnostics) || O.matches(options::OPT_fdiagnostics_color)) { @@ -1097,7 +1224,6 @@ static bool checkVerifyPrefixes(const std::vector<std::string> &VerifyPrefixes, bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine *Diags, bool DefaultDiagColor, bool DefaultShowOpt) { - using namespace options; bool Success = true; Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); @@ -1192,7 +1318,7 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Success = false; } else - std::sort(Opts.VerifyPrefixes.begin(), Opts.VerifyPrefixes.end()); + llvm::sort(Opts.VerifyPrefixes.begin(), Opts.VerifyPrefixes.end()); DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None; Success &= parseDiagnosticLevelMask("-verify-ignore-unexpected=", Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ), @@ -1264,7 +1390,6 @@ static bool parseTestModuleFileExtensionArg(StringRef Arg, static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags, bool &IsHeaderFile) { - using namespace options; Opts.ProgramAction = frontend::ParseSyntaxOnly; if (const Arg *A = Args.getLastArg(OPT_Action_Group)) { switch (A->getOption().getID()) { @@ -1280,6 +1405,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::ASTPrint; break; case OPT_ast_view: Opts.ProgramAction = frontend::ASTView; break; + case OPT_compiler_options_dump: + Opts.ProgramAction = frontend::DumpCompilerOptions; break; case OPT_dump_raw_tokens: Opts.ProgramAction = frontend::DumpRawTokens; break; case OPT_dump_tokens: @@ -1325,6 +1452,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::PrintPreamble; break; case OPT_E: Opts.ProgramAction = frontend::PrintPreprocessedInput; break; + case OPT_templight_dump: + Opts.ProgramAction = frontend::TemplightDump; break; case OPT_rewrite_macros: Opts.ProgramAction = frontend::RewriteMacros; break; case OPT_rewrite_objc: @@ -1346,7 +1475,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ActionName = A->getValue(); } Opts.AddPluginActions = Args.getAllArgValues(OPT_add_plugin); - for (const Arg *AA : Args.filtered(OPT_plugin_arg)) + for (const auto *AA : Args.filtered(OPT_plugin_arg)) Opts.PluginArgs[AA->getValue(0)].emplace_back(AA->getValue(1)); for (const std::string &Arg : @@ -1399,7 +1528,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex; Opts.ModuleMapFiles = Args.getAllArgValues(OPT_fmodule_map_file); // Only the -fmodule-file=<file> form. - for (const Arg *A : Args.filtered(OPT_fmodule_file)) { + for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); if (Val.find('=') == StringRef::npos) Opts.ModuleFiles.push_back(Val); @@ -1418,12 +1547,13 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, = !Args.hasArg(OPT_no_code_completion_ns_level_decls); Opts.CodeCompleteOpts.IncludeBriefComments = Args.hasArg(OPT_code_completion_brief_comments); + Opts.CodeCompleteOpts.IncludeFixIts + = Args.hasArg(OPT_code_completion_with_fixits); Opts.OverrideRecordLayoutsFile = Args.getLastArgValue(OPT_foverride_record_layout_EQ); Opts.AuxTriple = llvm::Triple::normalize(Args.getLastArgValue(OPT_aux_triple)); - Opts.FindPchSource = Args.getLastArgValue(OPT_find_pch_source_EQ); Opts.StatsFile = Args.getLastArgValue(OPT_stats_file); if (const Arg *A = Args.getLastArg(OPT_arcmt_check, @@ -1504,6 +1634,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("c", InputKind::C) .Case("cl", InputKind::OpenCL) .Case("cuda", InputKind::CUDA) + .Case("hip", InputKind::HIP) .Case("c++", InputKind::CXX) .Case("objective-c", InputKind::ObjC) .Case("objective-c++", InputKind::ObjCXX) @@ -1587,7 +1718,6 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0, static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, const std::string &WorkingDir) { - using namespace options; Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); @@ -1610,12 +1740,12 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, Opts.ModuleUserBuildPath = Args.getLastArgValue(OPT_fmodules_user_build_path); // Only the -fmodule-file=<name>=<file> form. - for (const Arg *A : Args.filtered(OPT_fmodule_file)) { + for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); if (Val.find('=') != StringRef::npos) Opts.PrebuiltModuleFiles.insert(Val.split('=')); } - for (const Arg *A : Args.filtered(OPT_fprebuilt_module_path)) + for (const auto *A : Args.filtered(OPT_fprebuilt_module_path)) Opts.AddPrebuiltModulePath(A->getValue()); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); Opts.ModulesHashContent = Args.hasArg(OPT_fmodules_hash_content); @@ -1636,7 +1766,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, if (const Arg *A = Args.getLastArg(OPT_fmodule_format_EQ)) Opts.ModuleFormat = A->getValue(); - for (const Arg *A : Args.filtered(OPT_fmodules_ignore_macro)) { + for (const auto *A : Args.filtered(OPT_fmodules_ignore_macro)) { StringRef MacroDef = A->getValue(); Opts.ModulesIgnoreMacros.insert( llvm::CachedHashString(MacroDef.split('=').first)); @@ -1646,7 +1776,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, bool IsIndexHeaderMap = false; bool IsSysrootSpecified = Args.hasArg(OPT__sysroot_EQ) || Args.hasArg(OPT_isysroot); - for (const Arg *A : Args.filtered(OPT_I, OPT_F, OPT_index_header_map)) { + for (const auto *A : Args.filtered(OPT_I, OPT_F, OPT_index_header_map)) { if (A->getOption().matches(OPT_index_header_map)) { // -index-header-map applies to the next -I or -F. IsIndexHeaderMap = true; @@ -1673,7 +1803,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, // Add -iprefix/-iwithprefix/-iwithprefixbefore options. StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. - for (const Arg *A : + for (const auto *A : Args.filtered(OPT_iprefix, OPT_iwithprefix, OPT_iwithprefixbefore)) { if (A->getOption().matches(OPT_iprefix)) Prefix = A->getValue(); @@ -1683,31 +1813,31 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, Opts.AddPath(Prefix.str() + A->getValue(), frontend::Angled, false, true); } - for (const Arg *A : Args.filtered(OPT_idirafter)) + for (const auto *A : Args.filtered(OPT_idirafter)) Opts.AddPath(A->getValue(), frontend::After, false, true); - for (const Arg *A : Args.filtered(OPT_iquote)) + for (const auto *A : Args.filtered(OPT_iquote)) Opts.AddPath(A->getValue(), frontend::Quoted, false, true); - for (const Arg *A : Args.filtered(OPT_isystem, OPT_iwithsysroot)) + for (const auto *A : Args.filtered(OPT_isystem, OPT_iwithsysroot)) Opts.AddPath(A->getValue(), frontend::System, false, !A->getOption().matches(OPT_iwithsysroot)); - for (const Arg *A : Args.filtered(OPT_iframework)) + for (const auto *A : Args.filtered(OPT_iframework)) Opts.AddPath(A->getValue(), frontend::System, true, true); - for (const Arg *A : Args.filtered(OPT_iframeworkwithsysroot)) + for (const auto *A : Args.filtered(OPT_iframeworkwithsysroot)) Opts.AddPath(A->getValue(), frontend::System, /*IsFramework=*/true, /*IgnoreSysRoot=*/false); // Add the paths for the various language specific isystem flags. - for (const Arg *A : Args.filtered(OPT_c_isystem)) + for (const auto *A : Args.filtered(OPT_c_isystem)) Opts.AddPath(A->getValue(), frontend::CSystem, false, true); - for (const Arg *A : Args.filtered(OPT_cxx_isystem)) + for (const auto *A : Args.filtered(OPT_cxx_isystem)) Opts.AddPath(A->getValue(), frontend::CXXSystem, false, true); - for (const Arg *A : Args.filtered(OPT_objc_isystem)) + for (const auto *A : Args.filtered(OPT_objc_isystem)) Opts.AddPath(A->getValue(), frontend::ObjCSystem, false,true); - for (const Arg *A : Args.filtered(OPT_objcxx_isystem)) + for (const auto *A : Args.filtered(OPT_objcxx_isystem)) Opts.AddPath(A->getValue(), frontend::ObjCXXSystem, false, true); // Add the internal paths from a driver that detects standard include paths. - for (const Arg *A : + for (const auto *A : Args.filtered(OPT_internal_isystem, OPT_internal_externc_isystem)) { frontend::IncludeDirGroup Group = frontend::System; if (A->getOption().matches(OPT_internal_externc_isystem)) @@ -1716,12 +1846,12 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, } // Add the path prefixes which are implicitly treated as being system headers. - for (const Arg *A : + for (const auto *A : Args.filtered(OPT_system_header_prefix, OPT_no_system_header_prefix)) Opts.AddSystemHeaderPrefix( A->getValue(), A->getOption().matches(OPT_system_header_prefix)); - for (const Arg *A : Args.filtered(OPT_ivfsoverlay)) + for (const auto *A : Args.filtered(OPT_ivfsoverlay)) Opts.AddVFSOverlayFile(A->getValue()); } @@ -1756,22 +1886,37 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, break; case InputKind::Asm: case InputKind::C: +#if defined(CLANG_DEFAULT_STD_C) + LangStd = CLANG_DEFAULT_STD_C; +#else // The PS4 uses C99 as the default C standard. if (T.isPS4()) LangStd = LangStandard::lang_gnu99; else LangStd = LangStandard::lang_gnu11; +#endif break; case InputKind::ObjC: +#if defined(CLANG_DEFAULT_STD_C) + LangStd = CLANG_DEFAULT_STD_C; +#else LangStd = LangStandard::lang_gnu11; +#endif break; case InputKind::CXX: case InputKind::ObjCXX: +#if defined(CLANG_DEFAULT_STD_CXX) + LangStd = CLANG_DEFAULT_STD_CXX; +#else LangStd = LangStandard::lang_gnucxx14; +#endif break; case InputKind::RenderScript: LangStd = LangStandard::lang_c99; break; + case InputKind::HIP: + LangStd = LangStandard::lang_hip; + break; } } @@ -1801,6 +1946,8 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.OpenCLVersion = 120; else if (LangStd == LangStandard::lang_opencl20) Opts.OpenCLVersion = 200; + else if (LangStd == LangStandard::lang_openclcpp) + Opts.OpenCLCPlusPlusVersion = 100; // OpenCL has some additional defaults. if (Opts.OpenCL) { @@ -1810,13 +1957,15 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.setDefaultFPContractMode(LangOptions::FPC_On); Opts.NativeHalfType = 1; Opts.NativeHalfArgsAndReturns = 1; + Opts.OpenCLCPlusPlus = Opts.CPlusPlus; // Include default header file for OpenCL. if (Opts.IncludeDefaultHeader) { PPOpts.Includes.push_back("opencl-c.h"); } } - Opts.CUDA = IK.getLanguage() == InputKind::CUDA; + Opts.HIP = IK.getLanguage() == InputKind::HIP; + Opts.CUDA = IK.getLanguage() == InputKind::CUDA || Opts.HIP; if (Opts.CUDA) // Set default FP_CONTRACT to FAST. Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); @@ -1887,6 +2036,10 @@ static bool IsInputCompatibleWithStandard(InputKind IK, return S.getLanguage() == InputKind::CUDA || S.getLanguage() == InputKind::CXX; + case InputKind::HIP: + return S.getLanguage() == InputKind::CXX || + S.getLanguage() == InputKind::HIP; + case InputKind::Asm: // Accept (and ignore) all -std= values. // FIXME: The -std= value is not ignored; it affects the tokenization @@ -1914,6 +2067,8 @@ static const StringRef GetInputKindName(InputKind IK) { return "CUDA"; case InputKind::RenderScript: return "RenderScript"; + case InputKind::HIP: + return "HIP"; case InputKind::Asm: return "Asm"; @@ -1977,6 +2132,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, } } + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { + StringRef Name = A->getValue(); + if (Name == "full" || Name == "branch") { + Opts.CFProtectionBranch = 1; + } + } // -cl-std only applies for OpenCL language standards. // Override the -std option in this case. if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { @@ -1986,6 +2147,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11) .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12) .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20) + .Case("c++", LangStandard::lang_openclcpp) .Default(LangStandard::lang_unspecified); if (OpenCLLangStd == LangStandard::lang_unspecified) { @@ -2006,11 +2168,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // this option was added for compatibility with OpenCL 1.0. if (Args.getLastArg(OPT_cl_strict_aliasing) && Opts.OpenCLVersion > 100) { - std::string VerSpec = llvm::to_string(Opts.OpenCLVersion / 100) + - std::string(".") + - llvm::to_string((Opts.OpenCLVersion % 100) / 10); Diags.Report(diag::warn_option_invalid_ocl_version) - << VerSpec << Args.getLastArg(OPT_cl_strict_aliasing)->getAsString(Args); + << Opts.getOpenCLVersionTuple().getAsString() + << Args.getLastArg(OPT_cl_strict_aliasing)->getAsString(Args); } // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension @@ -2021,6 +2181,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords, Opts.GNUKeywords); + Opts.Digraphs = Args.hasFlag(OPT_fdigraphs, OPT_fno_digraphs, Opts.Digraphs); + if (Args.hasArg(OPT_fno_operator_names)) Opts.CXXOperatorNames = 0; @@ -2033,12 +2195,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fno_cuda_host_device_constexpr)) Opts.CUDAHostDeviceConstexpr = 0; - if (Opts.CUDAIsDevice && Args.hasArg(OPT_fcuda_flush_denormals_to_zero)) - Opts.CUDADeviceFlushDenormalsToZero = 1; - if (Opts.CUDAIsDevice && Args.hasArg(OPT_fcuda_approx_transcendentals)) Opts.CUDADeviceApproxTranscendentals = 1; + Opts.CUDARelocatableDeviceCode = Args.hasArg(OPT_fcuda_rdc); + if (Opts.ObjC1) { if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) { StringRef value = arg->getValue(); @@ -2179,12 +2340,27 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions); Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions); + // -ffixed-point + Opts.FixedPoint = + Args.hasFlag(OPT_ffixed_point, OPT_fno_fixed_point, /*Default=*/false) && + !Opts.CPlusPlus; + Opts.PaddingOnUnsignedFixedPoint = + Args.hasFlag(OPT_fpadding_on_unsigned_fixed_point, + OPT_fno_padding_on_unsigned_fixed_point, + /*Default=*/false) && + Opts.FixedPoint; + // Handle exception personalities Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions, options::OPT_fdwarf_exceptions); if (A) { const Option &Opt = A->getOption(); + llvm::Triple T(TargetOpts.Triple); + if (T.isWindowsMSVCEnvironment()) + Diags.Report(diag::err_fe_invalid_exception_model) + << Opt.getName() << T.str(); + Opts.SjLjExceptions = Opt.matches(options::OPT_fsjlj_exceptions); Opts.SEHExceptions = Opt.matches(options::OPT_fseh_exceptions); Opts.DWARFExceptions = Opt.matches(options::OPT_fdwarf_exceptions); @@ -2196,7 +2372,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.RTTI = Opts.CPlusPlus && !Args.hasArg(OPT_fno_rtti); Opts.RTTIData = Opts.RTTI && !Args.hasArg(OPT_fno_rtti_data); Opts.Blocks = Args.hasArg(OPT_fblocks) || (Opts.OpenCL - && Opts.OpenCLVersion >= 200); + && Opts.OpenCLVersion == 200); Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.CoroutinesTS = Args.hasArg(OPT_fcoroutines_ts); @@ -2221,6 +2397,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ImplicitModules = !Args.hasArg(OPT_fno_implicit_modules); Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char); Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar); + Opts.Char8 = Args.hasArg(OPT_fchar8__t); if (const Arg *A = Args.getLastArg(OPT_fwchar_type_EQ)) { Opts.WCharSize = llvm::StringSwitch<unsigned>(A->getValue()) .Case("char", 1) @@ -2299,10 +2476,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id); Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal); Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack); - Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name_EQ); + Opts.ModuleName = Args.getLastArgValue(OPT_fmodule_name_EQ); + Opts.CurrentModule = Opts.ModuleName; Opts.AppExt = Args.hasArg(OPT_fapplication_extension); Opts.ModuleFeatures = Args.getAllArgValues(OPT_fmodule_feature); - std::sort(Opts.ModuleFeatures.begin(), Opts.ModuleFeatures.end()); + llvm::sort(Opts.ModuleFeatures.begin(), Opts.ModuleFeatures.end()); Opts.NativeHalfType |= Args.hasArg(OPT_fnative_half_type); Opts.NativeHalfArgsAndReturns |= Args.hasArg(OPT_fnative_half_arguments_and_returns); // Enable HalfArgsAndReturns if present in Args or if NativeHalfArgsAndReturns @@ -2410,20 +2588,23 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Check if -fopenmp is specified. Opts.OpenMP = Args.hasArg(options::OPT_fopenmp) ? 1 : 0; // Check if -fopenmp-simd is specified. - Opts.OpenMPSimd = !Opts.OpenMP && Args.hasFlag(options::OPT_fopenmp_simd, - options::OPT_fno_openmp_simd, - /*Default=*/false); + bool IsSimdSpecified = + Args.hasFlag(options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd, + /*Default=*/false); + Opts.OpenMPSimd = !Opts.OpenMP && IsSimdSpecified; Opts.OpenMPUseTLS = Opts.OpenMP && !Args.hasArg(options::OPT_fnoopenmp_use_tls); Opts.OpenMPIsDevice = Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_is_device); + bool IsTargetSpecified = + Opts.OpenMPIsDevice || Args.hasArg(options::OPT_fopenmp_targets_EQ); if (Opts.OpenMP || Opts.OpenMPSimd) { - if (int Version = - getLastArgIntValue(Args, OPT_fopenmp_version_EQ, - Opts.OpenMPSimd ? 45 : Opts.OpenMP, Diags)) + if (int Version = getLastArgIntValue( + Args, OPT_fopenmp_version_EQ, + (IsSimdSpecified || IsTargetSpecified) ? 45 : Opts.OpenMP, Diags)) Opts.OpenMP = Version; - else if (Opts.OpenMPSimd) + else if (IsSimdSpecified || IsTargetSpecified) Opts.OpenMP = 45; // Provide diagnostic when a given target is not expected to be an OpenMP // device or host. @@ -2434,7 +2615,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Add unsupported host targets here: case llvm::Triple::nvptx: case llvm::Triple::nvptx64: - Diags.Report(clang::diag::err_drv_omp_host_target_not_supported) + Diags.Report(diag::err_drv_omp_host_target_not_supported) << TargetOpts.Triple; break; } @@ -2443,7 +2624,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Set the flag to prevent the implementation from emitting device exception // handling code for those requiring so. - if (Opts.OpenMPIsDevice && T.isNVPTX()) { + Opts.OpenMPHostCXXExceptions = Opts.Exceptions && Opts.CXXExceptions; + if ((Opts.OpenMPIsDevice && T.isNVPTX()) || Opts.OpenCLCPlusPlus) { Opts.Exceptions = 0; Opts.CXXExceptions = 0; } @@ -2462,7 +2644,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, TT.getArch() == llvm::Triple::nvptx64 || TT.getArch() == llvm::Triple::x86 || TT.getArch() == llvm::Triple::x86_64)) - Diags.Report(clang::diag::err_drv_invalid_omp_target) << A->getValue(i); + Diags.Report(diag::err_drv_invalid_omp_target) << A->getValue(i); else Opts.OMPTargetTriples.push_back(TT); } @@ -2473,10 +2655,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Arg *A = Args.getLastArg(options::OPT_fopenmp_host_ir_file_path)) { Opts.OMPHostIRFile = A->getValue(); if (!llvm::sys::fs::exists(Opts.OMPHostIRFile)) - Diags.Report(clang::diag::err_drv_omp_host_ir_file_not_found) + Diags.Report(diag::err_drv_omp_host_ir_file_not_found) << Opts.OMPHostIRFile; } + // set CUDA mode for OpenMP target NVPTX if specified in options + Opts.OpenMPCUDAMode = Opts.OpenMPIsDevice && T.isNVPTX() && + Args.hasArg(options::OPT_fopenmp_cuda_mode); + // Record whether the __DEPRECATED define was requested. Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro, OPT_fno_deprecated_macro, @@ -2551,14 +2737,55 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Args.hasFlag(OPT_fxray_always_emit_customevents, OPT_fnoxray_always_emit_customevents, false); + // -fxray-always-emit-typedevents + Opts.XRayAlwaysEmitTypedEvents = + Args.hasFlag(OPT_fxray_always_emit_typedevents, + OPT_fnoxray_always_emit_customevents, false); + // -fxray-{always,never}-instrument= filenames. Opts.XRayAlwaysInstrumentFiles = Args.getAllArgValues(OPT_fxray_always_instrument); Opts.XRayNeverInstrumentFiles = Args.getAllArgValues(OPT_fxray_never_instrument); + Opts.XRayAttrListFiles = Args.getAllArgValues(OPT_fxray_attr_list); + + // -fforce-emit-vtables + Opts.ForceEmitVTables = Args.hasArg(OPT_fforce_emit_vtables); // -fallow-editor-placeholders Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders); + + if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) { + Opts.setClangABICompat(LangOptions::ClangABI::Latest); + + StringRef Ver = A->getValue(); + std::pair<StringRef, StringRef> VerParts = Ver.split('.'); + unsigned Major, Minor = 0; + + // Check the version number is valid: either 3.x (0 <= x <= 9) or + // y or y.0 (4 <= y <= current version). + if (!VerParts.first.startswith("0") && + !VerParts.first.getAsInteger(10, Major) && + 3 <= Major && Major <= CLANG_VERSION_MAJOR && + (Major == 3 ? VerParts.second.size() == 1 && + !VerParts.second.getAsInteger(10, Minor) + : VerParts.first.size() == Ver.size() || + VerParts.second == "0")) { + // Got a valid version number. + if (Major == 3 && Minor <= 8) + Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8); + else if (Major <= 4) + Opts.setClangABICompat(LangOptions::ClangABI::Ver4); + else if (Major <= 6) + Opts.setClangABICompat(LangOptions::ClangABI::Ver6); + } else if (Ver != "latest") { + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + } + } + + Opts.CompleteMemberPointers = Args.hasArg(OPT_fcomplete_member_pointers); + Opts.BuildingPCHWithObjectFile = Args.hasArg(OPT_building_pch_with_obj); } static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { @@ -2587,9 +2814,11 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { case frontend::RewriteObjC: case frontend::RewriteTest: case frontend::RunAnalysis: + case frontend::TemplightDump: case frontend::MigrateSource: return false; + case frontend::DumpCompilerOptions: case frontend::DumpRawTokens: case frontend::DumpTokens: case frontend::InitOnly: @@ -2603,12 +2832,11 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, - FileManager &FileMgr, DiagnosticsEngine &Diags, frontend::ActionKind Action) { - using namespace options; Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); + Opts.PCHThroughHeader = Args.getLastArgValue(OPT_pch_through_header_EQ); if (const Arg *A = Args.getLastArg(OPT_token_cache)) Opts.TokenCache = A->getValue(); else @@ -2619,7 +2847,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.AllowPCHWithCompilerErrors = Args.hasArg(OPT_fallow_pch_with_errors); Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls); - for (const Arg *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) + for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue()); if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { @@ -2638,8 +2866,19 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, } } + // Add the __CET__ macro if a CFProtection option is set. + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { + StringRef Name = A->getValue(); + if (Name == "branch") + Opts.addMacroDef("__CET__=1"); + else if (Name == "return") + Opts.addMacroDef("__CET__=2"); + else if (Name == "full") + Opts.addMacroDef("__CET__=3"); + } + // Add macros from the command line. - for (const Arg *A : Args.filtered(OPT_D, OPT_U)) { + for (const auto *A : Args.filtered(OPT_D, OPT_U)) { if (A->getOption().matches(OPT_D)) Opts.addMacroDef(A->getValue()); else @@ -2649,13 +2888,13 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros); // Add the ordered list of -includes. - for (const Arg *A : Args.filtered(OPT_include)) + for (const auto *A : Args.filtered(OPT_include)) Opts.Includes.emplace_back(A->getValue()); - for (const Arg *A : Args.filtered(OPT_chain_include)) + for (const auto *A : Args.filtered(OPT_chain_include)) Opts.ChainedIncludes.emplace_back(A->getValue()); - for (const Arg *A : Args.filtered(OPT_remap_file)) { + for (const auto *A : Args.filtered(OPT_remap_file)) { std::pair<StringRef, StringRef> Split = StringRef(A->getValue()).split(';'); if (Split.second.empty()) { @@ -2689,8 +2928,6 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, ArgList &Args, frontend::ActionKind Action) { - using namespace options; - if (isStrictlyPreprocessorAction(Action)) Opts.ShowCPP = !Args.hasArg(OPT_dM); else @@ -2708,7 +2945,6 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { - using namespace options; Opts.ABI = Args.getLastArgValue(OPT_target_abi); if (Arg *A = Args.getLastArg(OPT_meabi)) { StringRef Value = A->getValue(); @@ -2728,11 +2964,15 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args, Opts.FPMath = Args.getLastArgValue(OPT_mfpmath); Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature); Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version); - Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); + Opts.Triple = Args.getLastArgValue(OPT_triple); // Use the default target triple if unspecified. if (Opts.Triple.empty()) Opts.Triple = llvm::sys::getDefaultTargetTriple(); + Opts.Triple = llvm::Triple::normalize(Opts.Triple); Opts.OpenCLExtensionsAsWritten = Args.getAllArgValues(OPT_cl_ext_EQ); + Opts.ForceEnableInt128 = Args.hasArg(OPT_fforce_enable_int128); + Opts.NVPTXUseShortPointers = Args.hasFlag( + options::OPT_fcuda_short_ptr, options::OPT_fno_cuda_short_ptr, false); } bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, @@ -2758,8 +2998,14 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, } // Issue errors on unknown arguments. - for (const Arg *A : Args.filtered(OPT_UNKNOWN)) { - Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args); + for (const auto *A : Args.filtered(OPT_UNKNOWN)) { + auto ArgString = A->getAsString(Args); + std::string Nearest; + if (Opts->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1) + Diags.Report(diag::err_drv_unknown_argument) << ArgString; + else + Diags.Report(diag::err_drv_unknown_argument_with_suggestion) + << ArgString << Nearest; Success = false; } @@ -2776,7 +3022,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, LangOpts.IsHeaderFile); ParseTargetArgs(Res.getTargetOpts(), Args, Diags); Success &= ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags, - Res.getTargetOpts()); + Res.getTargetOpts(), Res.getFrontendOpts()); ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Res.getFileSystemOpts().WorkingDir); if (DashX.getFormat() == InputKind::Precompiled || @@ -2801,6 +3047,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, LangOpts.ObjCExceptions = 1; } + LangOpts.FunctionAlignment = + getLastArgIntValue(Args, OPT_function_alignment, 0, Diags); + if (LangOpts.CUDA) { // During CUDA device-side compilation, the aux triple is the // triple used for host compilation. @@ -2819,12 +3068,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, !LangOpts.Sanitize.has(SanitizerKind::Address) && !LangOpts.Sanitize.has(SanitizerKind::Memory); - // FIXME: ParsePreprocessorArgs uses the FileManager to read the contents of - // PCH file and find the original header name. Remove the need to do that in - // ParsePreprocessorArgs and remove the FileManager - // parameters from the function and the "FileManager.h" #include. - FileManager FileMgr(Res.getFileSystemOpts()); - ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags, + ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, Diags, Res.getFrontendOpts().ProgramAction); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args, Res.getFrontendOpts().ProgramAction); @@ -2872,29 +3116,26 @@ std::string CompilerInvocation::getModuleHash() const { // Extend the signature with the target options. code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU, TargetOpts->ABI); - for (unsigned i = 0, n = TargetOpts->FeaturesAsWritten.size(); i != n; ++i) - code = hash_combine(code, TargetOpts->FeaturesAsWritten[i]); + for (const auto &FeatureAsWritten : TargetOpts->FeaturesAsWritten) + code = hash_combine(code, FeatureAsWritten); // Extend the signature with preprocessor options. const PreprocessorOptions &ppOpts = getPreprocessorOpts(); const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord); - for (std::vector<std::pair<std::string, bool/*isUndef*/>>::const_iterator - I = getPreprocessorOpts().Macros.begin(), - IEnd = getPreprocessorOpts().Macros.end(); - I != IEnd; ++I) { + for (const auto &I : getPreprocessorOpts().Macros) { // If we're supposed to ignore this macro for the purposes of modules, // don't put it into the hash. if (!hsOpts.ModulesIgnoreMacros.empty()) { // Check whether we're ignoring this macro. - StringRef MacroDef = I->first; + StringRef MacroDef = I.first; if (hsOpts.ModulesIgnoreMacros.count( llvm::CachedHashString(MacroDef.split('=').first))) continue; } - code = hash_combine(code, I->first, I->second); + code = hash_combine(code, I.first, I.second); } // Extend the signature with the sysroot and other header search options. @@ -2927,8 +3168,6 @@ std::string CompilerInvocation::getModuleHash() const { return llvm::APInt(64, code).toString(36, /*Signed=*/false); } -namespace clang { - template<typename IntTy> static IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, IntTy Default, @@ -2944,6 +3183,7 @@ static IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, return Res; } +namespace clang { // Declared in clang/Frontend/Utils.h. int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, @@ -2988,22 +3228,22 @@ createVFSFromCompilerInvocation(const CompilerInvocation &CI, IntrusiveRefCntPtr<vfs::OverlayFileSystem> Overlay( new vfs::OverlayFileSystem(BaseFS)); // earlier vfs files are on the bottom - for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) { + for (const auto &File : CI.getHeaderSearchOpts().VFSOverlayFiles) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer = BaseFS->getBufferForFile(File); if (!Buffer) { Diags.Report(diag::err_missing_vfs_overlay_file) << File; - return IntrusiveRefCntPtr<vfs::FileSystem>(); + continue; } IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getVFSFromYAML( std::move(Buffer.get()), /*DiagHandler*/ nullptr, File); - if (!FS.get()) { + if (FS) + Overlay->pushOverlay(FS); + else Diags.Report(diag::err_invalid_vfs_overlay) << File; - return IntrusiveRefCntPtr<vfs::FileSystem>(); - } - Overlay->pushOverlay(FS); } return Overlay; } -} // end namespace clang + +} // namespace clang diff --git a/gnu/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/gnu/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp index 2efbfaae92b..a3901e5fb91 100644 --- a/gnu/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/gnu/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp @@ -14,6 +14,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" #include "clang/Config/config.h" // C_INCLUDE_DIRS +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderMap.h" #include "clang/Lex/HeaderSearch.h" @@ -55,11 +56,13 @@ public: /// AddPath - Add the specified path to the specified group list, prefixing /// the sysroot if used. - void AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework); + /// Returns true if the path exists, false if it was ignored. + bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework); /// AddUnmappedPath - Add the specified path to the specified group list, /// without performing any sysroot remapping. - void AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, + /// Returns true if the path exists, false if it was ignored. + bool AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, bool isFramework); /// AddSystemHeaderPrefix - Add the specified prefix to the system header @@ -70,10 +73,9 @@ public: /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu /// libstdc++. - void AddGnuCPlusPlusIncludePaths(StringRef Base, - StringRef ArchDir, - StringRef Dir32, - StringRef Dir64, + /// Returns true if the \p Base path was found, false if it does not exist. + bool AddGnuCPlusPlusIncludePaths(StringRef Base, StringRef ArchDir, + StringRef Dir32, StringRef Dir64, const llvm::Triple &triple); /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW @@ -88,7 +90,8 @@ public: // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when // compiling c++. - void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, + void AddDefaultCPlusPlusIncludePaths(const LangOptions &LangOpts, + const llvm::Triple &triple, const HeaderSearchOptions &HSOpts); /// AddDefaultSystemIncludePaths - Adds the default system include paths so @@ -105,14 +108,14 @@ public: } // end anonymous namespace. static bool CanPrefixSysroot(StringRef Path) { -#if defined(LLVM_ON_WIN32) +#if defined(_WIN32) return !Path.empty() && llvm::sys::path::is_separator(Path[0]); #else return llvm::sys::path::is_absolute(Path); #endif } -void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, +bool InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework) { // Add the path with sysroot prepended, if desired and this is a system header // group. @@ -120,15 +123,14 @@ void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, SmallString<256> MappedPathStorage; StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); if (CanPrefixSysroot(MappedPathStr)) { - AddUnmappedPath(IncludeSysroot + Path, Group, isFramework); - return; + return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework); } } - AddUnmappedPath(Path, Group, isFramework); + return AddUnmappedPath(Path, Group, isFramework); } -void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, +bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, bool isFramework) { assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); @@ -150,7 +152,7 @@ void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) { IncludePath.push_back( std::make_pair(Group, DirectoryLookup(DE, Type, isFramework))); - return; + return true; } // Check to see if this is an apple-style headermap (which are not allowed to @@ -162,7 +164,7 @@ void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, IncludePath.push_back( std::make_pair(Group, DirectoryLookup(HM, Type, Group == IndexHeaderMap))); - return; + return true; } } } @@ -170,15 +172,16 @@ void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, if (Verbose) llvm::errs() << "ignoring nonexistent directory \"" << MappedPathStr << "\"\n"; + return false; } -void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, +bool InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, StringRef ArchDir, StringRef Dir32, StringRef Dir64, const llvm::Triple &triple) { // Add the base dir - AddPath(Base, CXXSystem, false); + bool IsBaseFound = AddPath(Base, CXXSystem, false); // Add the multilib dirs llvm::Triple::ArchType arch = triple.getArch(); @@ -190,6 +193,7 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base, // Add the backward dir AddPath(Base + "/backward", CXXSystem, false); + return IsBaseFound; } void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base, @@ -216,6 +220,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, case llvm::Triple::NaCl: case llvm::Triple::PS4: case llvm::Triple::ELFIAMCU: + case llvm::Triple::Fuchsia: break; case llvm::Triple::Win32: if (triple.getEnvironment() != llvm::Triple::Cygnus) @@ -255,6 +260,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, switch (os) { case llvm::Triple::Linux: + case llvm::Triple::Solaris: llvm_unreachable("Include management is handled in the driver."); case llvm::Triple::CloudABI: { @@ -321,6 +327,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, case llvm::Triple::RTEMS: case llvm::Triple::NaCl: case llvm::Triple::ELFIAMCU: + case llvm::Triple::Fuchsia: break; case llvm::Triple::PS4: { // <isysroot> gets prepended later in AddPath(). @@ -351,51 +358,61 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, } } -void InitHeaderSearch:: -AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOptions &HSOpts) { +void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths( + const LangOptions &LangOpts, const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts) { llvm::Triple::OSType os = triple.getOS(); // FIXME: temporary hack: hard-coded paths. if (triple.isOSDarwin()) { + bool IsBaseFound = true; switch (triple.getArch()) { default: break; case llvm::Triple::ppc: case llvm::Triple::ppc64: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "powerpc-apple-darwin10", "", "ppc64", - triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", - "powerpc-apple-darwin10", "", "ppc64", - triple); + IsBaseFound = AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", + "powerpc-apple-darwin10", "", + "ppc64", triple); + IsBaseFound |= AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", + "powerpc-apple-darwin10", "", + "ppc64", triple); break; case llvm::Triple::x86: case llvm::Triple::x86_64: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "i686-apple-darwin10", "", "x86_64", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", - "i686-apple-darwin8", "", "", triple); + IsBaseFound = AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", + "i686-apple-darwin10", "", + "x86_64", triple); + IsBaseFound |= AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.0.0", "i686-apple-darwin8", "", "", triple); break; case llvm::Triple::arm: case llvm::Triple::thumb: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "arm-apple-darwin10", "v7", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "arm-apple-darwin10", "v6", "", triple); + IsBaseFound = AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.2.1", "arm-apple-darwin10", "v7", "", triple); + IsBaseFound |= AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.2.1", "arm-apple-darwin10", "v6", "", triple); break; case llvm::Triple::aarch64: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "arm64-apple-darwin10", "", "", triple); + IsBaseFound = AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.2.1", "arm64-apple-darwin10", "", "", triple); break; } + // Warn when compiling pure C++ / Objective-C++ only. + if (!IsBaseFound && + !(LangOpts.CUDA || LangOpts.OpenCL || LangOpts.RenderScript)) { + Headers.getDiags().Report(SourceLocation(), + diag::warn_stdlibcxx_not_found); + } return; } switch (os) { case llvm::Triple::Linux: + case llvm::Triple::Solaris: llvm_unreachable("Include management is handled in the driver."); break; case llvm::Triple::Win32: @@ -435,6 +452,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, break; // Everything else continues to use this routine's logic. case llvm::Triple::Linux: + case llvm::Triple::Solaris: return; case llvm::Triple::Win32: @@ -444,8 +462,8 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, break; } - if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes && - HSOpts.UseStandardSystemIncludes) { + if (Lang.CPlusPlus && !Lang.AsmPreprocessor && + HSOpts.UseStandardCXXIncludes && HSOpts.UseStandardSystemIncludes) { if (HSOpts.UseLibcxx) { if (triple.isOSDarwin()) { // On Darwin, libc++ may be installed alongside the compiler in @@ -465,7 +483,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, } AddPath("/usr/include/c++/v1", CXXSystem, false); } else { - AddDefaultCPlusPlusIncludePaths(triple, HSOpts); + AddDefaultCPlusPlusIncludePaths(Lang, triple, HSOpts); } } diff --git a/gnu/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/gnu/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 30e693b558d..03057defd95 100644 --- a/gnu/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/gnu/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -28,6 +28,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/NSAPI.h" +#include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" @@ -118,7 +119,7 @@ static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) { // Highlight all the excess arguments. SourceRange range(call->getArg(desiredArgCount)->getLocStart(), call->getArg(argCount - 1)->getLocEnd()); - + return S.Diag(range.getBegin(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ << desiredArgCount << argCount << call->getArg(1)->getSourceRange(); @@ -196,35 +197,47 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { // First two arguments should be integers. for (unsigned I = 0; I < 2; ++I) { - Expr *Arg = TheCall->getArg(I); - QualType Ty = Arg->getType(); + ExprResult Arg = TheCall->getArg(I); + QualType Ty = Arg.get()->getType(); if (!Ty->isIntegerType()) { - S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_int) - << Ty << Arg->getSourceRange(); + S.Diag(Arg.get()->getLocStart(), diag::err_overflow_builtin_must_be_int) + << Ty << Arg.get()->getSourceRange(); return true; } + InitializedEntity Entity = InitializedEntity::InitializeParameter( + S.getASTContext(), Ty, /*consume*/ false); + Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(I, Arg.get()); } // Third argument should be a pointer to a non-const integer. // IRGen correctly handles volatile, restrict, and address spaces, and // the other qualifiers aren't possible. { - Expr *Arg = TheCall->getArg(2); - QualType Ty = Arg->getType(); + ExprResult Arg = TheCall->getArg(2); + QualType Ty = Arg.get()->getType(); const auto *PtrTy = Ty->getAs<PointerType>(); if (!(PtrTy && PtrTy->getPointeeType()->isIntegerType() && !PtrTy->getPointeeType().isConstQualified())) { - S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_ptr_int) - << Ty << Arg->getSourceRange(); + S.Diag(Arg.get()->getLocStart(), + diag::err_overflow_builtin_must_be_ptr_int) + << Ty << Arg.get()->getSourceRange(); return true; } + InitializedEntity Entity = InitializedEntity::InitializeParameter( + S.getASTContext(), Ty, /*consume*/ false); + Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(2, Arg.get()); } - return false; } static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, - CallExpr *TheCall, unsigned SizeIdx, + CallExpr *TheCall, unsigned SizeIdx, unsigned DstSizeIdx) { if (TheCall->getNumArgs() <= SizeIdx || TheCall->getNumArgs() <= DstSizeIdx) @@ -683,7 +696,7 @@ static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { return false; } -// \brief Performs semantic analysis for the read/write_pipe call. +// Performs semantic analysis for the read/write_pipe call. // \param S Reference to the semantic analyzer. // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. @@ -737,7 +750,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { return false; } -// \brief Performs a semantic analysis on the {work_group_/sub_group_ +// Performs a semantic analysis on the {work_group_/sub_group_ // /_}reserve_{read/write}_pipe // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. @@ -766,7 +779,7 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { return false; } -// \brief Performs a semantic analysis on {work_group_/sub_group_ +// Performs a semantic analysis on {work_group_/sub_group_ // /_}commit_{read/write}_pipe // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. @@ -789,7 +802,7 @@ static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { return false; } -// \brief Performs a semantic analysis on the call to built-in Pipe +// Performs a semantic analysis on the call to built-in Pipe // Query Functions. // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. @@ -807,8 +820,8 @@ static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { return false; } -// \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions. -// \brief Performs semantic analysis for the to_global/local/private call. +// OpenCL v2.0 s6.13.9 - Address space qualifier functions. +// Performs semantic analysis for the to_global/local/private call. // \param S Reference to the semantic analyzer. // \param BuiltinID ID of the builtin function. // \param Call A pointer to the builtin call. @@ -850,6 +863,20 @@ static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, return false; } +// Emit an error and return true if the current architecture is not in the list +// of supported architectures. +static bool +CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall, + ArrayRef<llvm::Triple::ArchType> SupportedArchs) { + llvm::Triple::ArchType CurArch = + S.getASTContext().getTargetInfo().getTriple().getArch(); + if (llvm::is_contained(SupportedArchs, CurArch)) + return false; + S.Diag(TheCall->getLocStart(), diag::err_builtin_target_unsupported) + << TheCall->getSourceRange(); + return true; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -861,18 +888,18 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, Context.GetBuiltinType(BuiltinID, Error, &ICEArguments); if (Error != ASTContext::GE_None) ICEArguments = 0; // Don't diagnose previously diagnosed errors. - + // If any arguments are required to be ICE's, check and diagnose. for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) { // Skip arguments not required to be ICE's. if ((ICEArguments & (1 << ArgNo)) == 0) continue; - + llvm::APSInt Result; if (SemaBuiltinConstantArg(TheCall, ArgNo, Result)) return true; ICEArguments &= ~(1 << ArgNo); } - + switch (BuiltinID) { case Builtin::BI__builtin___CFStringMakeConstantString: assert(TheCall->getNumArgs() == 1 && @@ -900,6 +927,33 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } break; } + + // The acquire, release, and no fence variants are ARM and AArch64 only. + case Builtin::BI_interlockedbittestandset_acq: + case Builtin::BI_interlockedbittestandset_rel: + case Builtin::BI_interlockedbittestandset_nf: + case Builtin::BI_interlockedbittestandreset_acq: + case Builtin::BI_interlockedbittestandreset_rel: + case Builtin::BI_interlockedbittestandreset_nf: + if (CheckBuiltinTargetSupport( + *this, BuiltinID, TheCall, + {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; + + // The 64-bit bittest variants are x64, ARM, and AArch64 only. + case Builtin::BI_bittest64: + case Builtin::BI_bittestandcomplement64: + case Builtin::BI_bittestandreset64: + case Builtin::BI_bittestandset64: + case Builtin::BI_interlockedbittestandreset64: + case Builtin::BI_interlockedbittestandset64: + if (CheckBuiltinTargetSupport(*this, BuiltinID, TheCall, + {llvm::Triple::x86_64, llvm::Triple::arm, + llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; + case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: @@ -918,6 +972,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_isinf_sign: case Builtin::BI__builtin_isnan: case Builtin::BI__builtin_isnormal: + case Builtin::BI__builtin_signbit: + case Builtin::BI__builtin_signbitf: + case Builtin::BI__builtin_signbitl: if (SemaBuiltinFPClassification(TheCall, 1)) return ExprError(); break; @@ -1097,19 +1154,70 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case Builtin::BI__builtin_operator_new: - case Builtin::BI__builtin_operator_delete: - if (!getLangOpts().CPlusPlus) { - Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) - << (BuiltinID == Builtin::BI__builtin_operator_new - ? "__builtin_operator_new" - : "__builtin_operator_delete") - << "C++"; + case Builtin::BI__builtin_operator_delete: { + bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; + ExprResult Res = + SemaBuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); + if (Res.isInvalid()) + CorrectDelayedTyposInExpr(TheCallResult.get()); + return Res; + } + case Builtin::BI__builtin_dump_struct: { + // We first want to ensure we are called with 2 arguments + if (checkArgCount(*this, TheCall, 2)) + return ExprError(); + // Ensure that the first argument is of type 'struct XX *' + const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts(); + const QualType PtrArgType = PtrArg->getType(); + if (!PtrArgType->isPointerType() || + !PtrArgType->getPointeeType()->isRecordType()) { + Diag(PtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << PtrArgType + << "structure pointer"; + return ExprError(); + } + + // Ensure that the second argument is of type 'FunctionType' + const Expr *FnPtrArg = TheCall->getArg(1)->IgnoreImpCasts(); + const QualType FnPtrArgType = FnPtrArg->getType(); + if (!FnPtrArgType->isPointerType()) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; return ExprError(); } - // CodeGen assumes it can find the global new and delete to call, - // so ensure that they are declared. - DeclareGlobalNewDelete(); + + const auto *FuncType = + FnPtrArgType->getPointeeType()->getAs<FunctionType>(); + + if (!FuncType) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; + return ExprError(); + } + + if (const auto *FT = dyn_cast<FunctionProtoType>(FuncType)) { + if (!FT->getNumParams()) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; + return ExprError(); + } + QualType PT = FT->getParamType(0); + if (!FT->isVariadic() || FT->getReturnType() != Context.IntTy || + !PT->isPointerType() || !PT->getPointeeType()->isCharType() || + !PT->getPointeeType().isConstQualified()) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; + return ExprError(); + } + } + + TheCall->setType(Context.IntTy); break; + } // check secure string manipulation functions where overflows // are detectable at compile time @@ -1215,7 +1323,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); break; - break; case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: case Builtin::BIget_kernel_sub_group_count_for_ndrange: if (SemaOpenCLBuiltinNDRangeAndBlock(*this, TheCall)) @@ -1244,6 +1351,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::hexagon: + if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -1353,6 +1464,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { #define GET_NEON_OVERLOAD_CHECK #include "clang/Basic/arm_neon.inc" +#include "clang/Basic/arm_fp16.inc" #undef GET_NEON_OVERLOAD_CHECK } @@ -1402,9 +1514,10 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { default: return false; -#define GET_NEON_IMMEDIATE_CHECK -#include "clang/Basic/arm_neon.inc" -#undef GET_NEON_IMMEDIATE_CHECK + #define GET_NEON_IMMEDIATE_CHECK + #include "clang/Basic/arm_neon.inc" + #include "clang/Basic/arm_fp16.inc" + #undef GET_NEON_IMMEDIATE_CHECK } return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); @@ -1618,6 +1731,1015 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { + static const std::map<unsigned, std::vector<StringRef>> ValidCPU = { + { Hexagon::BI__builtin_HEXAGON_A6_vcmpbeq_notany, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_A6_vminub_RdP, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffub, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_vsplatrbp, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_vtrunehb_ppp, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_vtrunohb_ppp, {"v62", "v65"} }, + }; + + static const std::map<unsigned, std::vector<StringRef>> ValidHVX = { + { Hexagon::BI__builtin_HEXAGON_V6_extractw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_extractw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_hi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_hi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lo, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lo_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplath, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplath_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_not, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_not_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vand, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vand_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvqv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvqv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslwv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslwv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassign, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassign_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassignp, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassignp_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguw, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguw_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0h, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0h_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0w, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0w_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcombine, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcombine_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vd0, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vd0_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdd0, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdd0_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdelta, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdelta_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlut4, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlut4_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmux, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmux_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamth, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamth_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnot, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnot_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackob, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackob_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrdelta, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrdelta_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vror, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vror_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsathub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsathub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufeh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufeh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffob, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffob_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vswap, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vswap_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackob, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackob_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vxor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vxor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzh_128B, {"v60", "v62", "v65"} }, + }; + + const TargetInfo &TI = Context.getTargetInfo(); + + auto FC = ValidCPU.find(BuiltinID); + if (FC != ValidCPU.end()) { + const TargetOptions &Opts = TI.getTargetOpts(); + StringRef CPU = Opts.CPU; + if (!CPU.empty()) { + assert(CPU.startswith("hexagon") && "Unexpected CPU name"); + CPU.consume_front("hexagon"); + if (llvm::none_of(FC->second, [CPU](StringRef S) { return S == CPU; })) + return Diag(TheCall->getLocStart(), + diag::err_hexagon_builtin_unsupported_cpu); + } + } + + auto FH = ValidHVX.find(BuiltinID); + if (FH != ValidHVX.end()) { + if (!TI.hasFeature("hvx")) + return Diag(TheCall->getLocStart(), + diag::err_hexagon_builtin_requires_hvx); + + bool IsValid = llvm::any_of(FH->second, + [&TI] (StringRef V) { + std::string F = "hvx" + V.str(); + return TI.hasFeature(F); + }); + if (!IsValid) + return Diag(TheCall->getLocStart(), + diag::err_hexagon_builtin_unsupported_hvx); + } + + return false; +} + +bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { + struct ArgInfo { + ArgInfo(unsigned O, bool S, unsigned W, unsigned A) + : OpNum(O), IsSigned(S), BitWidth(W), Align(A) {} + unsigned OpNum = 0; + bool IsSigned = false; + unsigned BitWidth = 0; + unsigned Align = 0; + }; + + static const std::map<unsigned, std::vector<ArgInfo>> Infos = { + { Hexagon::BI__builtin_circ_ldd, {{ 3, true, 4, 3 }} }, + { Hexagon::BI__builtin_circ_ldw, {{ 3, true, 4, 2 }} }, + { Hexagon::BI__builtin_circ_ldh, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_ldb, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_ldub, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_std, {{ 3, true, 4, 3 }} }, + { Hexagon::BI__builtin_circ_stw, {{ 3, true, 4, 2 }} }, + { Hexagon::BI__builtin_circ_sth, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_sthhi, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_stb, {{ 3, true, 4, 0 }} }, + + { Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadri_pci, {{ 1, true, 4, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci, {{ 1, true, 4, 3 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerb_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerf_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storeri_pci, {{ 1, true, 4, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerd_pci, {{ 1, true, 4, 3 }} }, + + { Hexagon::BI__builtin_HEXAGON_A2_combineii, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfrih, {{ 1, false, 16, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfril, {{ 1, false, 16, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfrpi, {{ 0, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_bitspliti, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cmpbeqi, {{ 1, false, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cmpbgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cround_ri, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_round_ri, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_round_ri_sat, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbeqi, {{ 1, false, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpheqi, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmphgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmphgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpweqi, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C2_bitsclri, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C2_muxii, {{ 2, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C4_nbitsclri, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfclass, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfimm_n, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfimm_p, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfclass, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfimm_n, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfimm_p, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addi, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addr_u2, {{ 1, false, 6, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_addasl_rrri, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_sat, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd_goodsyntax, + {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax, + {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_svw_trun, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_clrbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_extractu, {{ 1, false, 5, 0 }, + { 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_extractup, {{ 1, false, 6, 0 }, + { 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_insert, {{ 2, false, 5, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_insertp, {{ 2, false, 6, 0 }, + { 3, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_setbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxb_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxd_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxh_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxw_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_togglebit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tstbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_valignib, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_vspliceib, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_addi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_addi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_andi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_andi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_clbaddi, {{ 1, true , 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_clbpaddi, {{ 1, true, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_extract, {{ 1, false, 5, 0 }, + { 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_extractp, {{ 1, false, 6, 0 }, + { 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_lsli, {{ 0, true, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ntstbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ori_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ori_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_subi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_subi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate_acc, {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate, {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_asrhub_rnd_sat_goodsyntax, + {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_asrhub_sat, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_vasrhrnd_goodsyntax, + {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, + {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, + {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, + {{ 3, false, 1, 0 }} }, + }; + + auto F = Infos.find(BuiltinID); + if (F == Infos.end()) + return false; + + bool Error = false; + + for (const ArgInfo &A : F->second) { + int32_t Min = A.IsSigned ? -(1 << (A.BitWidth-1)) : 0; + int32_t Max = (1 << (A.IsSigned ? A.BitWidth-1 : A.BitWidth)) - 1; + if (!A.Align) { + Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + } else { + unsigned M = 1 << A.Align; + Min *= M; + Max *= M; + Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max) | + SemaBuiltinConstantArgMultiple(TheCall, A.OpNum, M); + } + } + return Error; +} + +bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + return CheckHexagonBuiltinCpu(BuiltinID, TheCall) || + CheckHexagonBuiltinArgument(BuiltinID, TheCall); +} + + // CheckMipsBuiltinFunctionCall - Checks the constant value passed to the // intrinsic is correct. The switch statement is ordered by DSP, MSA. The // ordering for DSP is unspecified. MSA is ordered by the data format used @@ -1666,7 +2788,7 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Mips::BI__builtin_msa_srlri_h: i = 1; l = 0; u = 15; break; case Mips::BI__builtin_msa_binsli_h: case Mips::BI__builtin_msa_binsri_h: i = 2; l = 0; u = 15; break; - // These intrinsics take an unsigned 5 bit immedate. + // These intrinsics take an unsigned 5 bit immediate. // The first block of intrinsics actually have an unsigned 5 bit field, // not a df/n field. case Mips::BI__builtin_msa_clei_u_b: @@ -1966,6 +3088,12 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vcvttss2usi64: ArgNum = 1; break; + case X86::BI__builtin_ia32_maxpd512: + case X86::BI__builtin_ia32_maxps512: + case X86::BI__builtin_ia32_minpd512: + case X86::BI__builtin_ia32_minps512: + ArgNum = 2; + break; case X86::BI__builtin_ia32_cvtps2pd512_mask: case X86::BI__builtin_ia32_cvttpd2dq512_mask: case X86::BI__builtin_ia32_cvttpd2qq512_mask: @@ -1995,12 +3123,8 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtss2sd_round_mask: case X86::BI__builtin_ia32_getexpsd128_round_mask: case X86::BI__builtin_ia32_getexpss128_round_mask: - case X86::BI__builtin_ia32_maxpd512_mask: - case X86::BI__builtin_ia32_maxps512_mask: case X86::BI__builtin_ia32_maxsd_round_mask: case X86::BI__builtin_ia32_maxss_round_mask: - case X86::BI__builtin_ia32_minpd512_mask: - case X86::BI__builtin_ia32_minps512_mask: case X86::BI__builtin_ia32_minsd_round_mask: case X86::BI__builtin_ia32_minss_round_mask: case X86::BI__builtin_ia32_rcp28sd_round_mask: @@ -2039,9 +3163,19 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vcvtss2si64: case X86::BI__builtin_ia32_vcvtss2usi32: case X86::BI__builtin_ia32_vcvtss2usi64: + case X86::BI__builtin_ia32_sqrtpd512: + case X86::BI__builtin_ia32_sqrtps512: ArgNum = 1; HasRC = true; break; + case X86::BI__builtin_ia32_addpd512: + case X86::BI__builtin_ia32_addps512: + case X86::BI__builtin_ia32_divpd512: + case X86::BI__builtin_ia32_divps512: + case X86::BI__builtin_ia32_mulpd512: + case X86::BI__builtin_ia32_mulps512: + case X86::BI__builtin_ia32_subpd512: + case X86::BI__builtin_ia32_subps512: case X86::BI__builtin_ia32_cvtsi2sd64: case X86::BI__builtin_ia32_cvtsi2ss32: case X86::BI__builtin_ia32_cvtsi2ss64: @@ -2062,19 +3196,9 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtqq2ps512_mask: case X86::BI__builtin_ia32_cvtuqq2pd512_mask: case X86::BI__builtin_ia32_cvtuqq2ps512_mask: - case X86::BI__builtin_ia32_sqrtpd512_mask: - case X86::BI__builtin_ia32_sqrtps512_mask: ArgNum = 3; HasRC = true; break; - case X86::BI__builtin_ia32_addpd512_mask: - case X86::BI__builtin_ia32_addps512_mask: - case X86::BI__builtin_ia32_divpd512_mask: - case X86::BI__builtin_ia32_divps512_mask: - case X86::BI__builtin_ia32_mulpd512_mask: - case X86::BI__builtin_ia32_mulps512_mask: - case X86::BI__builtin_ia32_subpd512_mask: - case X86::BI__builtin_ia32_subps512_mask: case X86::BI__builtin_ia32_addss_round_mask: case X86::BI__builtin_ia32_addsd_round_mask: case X86::BI__builtin_ia32_divss_round_mask: @@ -2092,34 +3216,28 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtsd2ss_round_mask: case X86::BI__builtin_ia32_sqrtsd_round_mask: case X86::BI__builtin_ia32_sqrtss_round_mask: + case X86::BI__builtin_ia32_vfmaddsd3_mask: + case X86::BI__builtin_ia32_vfmaddsd3_maskz: + case X86::BI__builtin_ia32_vfmaddsd3_mask3: + case X86::BI__builtin_ia32_vfmaddss3_mask: + case X86::BI__builtin_ia32_vfmaddss3_maskz: + case X86::BI__builtin_ia32_vfmaddss3_mask3: case X86::BI__builtin_ia32_vfmaddpd512_mask: - case X86::BI__builtin_ia32_vfmaddpd512_mask3: case X86::BI__builtin_ia32_vfmaddpd512_maskz: + case X86::BI__builtin_ia32_vfmaddpd512_mask3: + case X86::BI__builtin_ia32_vfmsubpd512_mask3: case X86::BI__builtin_ia32_vfmaddps512_mask: - case X86::BI__builtin_ia32_vfmaddps512_mask3: case X86::BI__builtin_ia32_vfmaddps512_maskz: + case X86::BI__builtin_ia32_vfmaddps512_mask3: + case X86::BI__builtin_ia32_vfmsubps512_mask3: case X86::BI__builtin_ia32_vfmaddsubpd512_mask: - case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: case X86::BI__builtin_ia32_vfmaddsubpd512_maskz: + case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: + case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: case X86::BI__builtin_ia32_vfmaddsubps512_mask: - case X86::BI__builtin_ia32_vfmaddsubps512_mask3: case X86::BI__builtin_ia32_vfmaddsubps512_maskz: - case X86::BI__builtin_ia32_vfmsubpd512_mask3: - case X86::BI__builtin_ia32_vfmsubps512_mask3: - case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: + case X86::BI__builtin_ia32_vfmaddsubps512_mask3: case X86::BI__builtin_ia32_vfmsubaddps512_mask3: - case X86::BI__builtin_ia32_vfnmaddpd512_mask: - case X86::BI__builtin_ia32_vfnmaddps512_mask: - case X86::BI__builtin_ia32_vfnmsubpd512_mask: - case X86::BI__builtin_ia32_vfnmsubpd512_mask3: - case X86::BI__builtin_ia32_vfnmsubps512_mask: - case X86::BI__builtin_ia32_vfnmsubps512_mask3: - case X86::BI__builtin_ia32_vfmaddsd3_mask: - case X86::BI__builtin_ia32_vfmaddsd3_maskz: - case X86::BI__builtin_ia32_vfmaddsd3_mask3: - case X86::BI__builtin_ia32_vfmaddss3_mask: - case X86::BI__builtin_ia32_vfmaddss3_maskz: - case X86::BI__builtin_ia32_vfmaddss3_mask3: ArgNum = 4; HasRC = true; break; @@ -2256,6 +3374,17 @@ bool Sema::CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, << Arg->getSourceRange(); } +static bool isX86_32Builtin(unsigned BuiltinID) { + // These builtins only work on x86-32 targets. + switch (BuiltinID) { + case X86::BI__builtin_ia32_readeflags_u32: + case X86::BI__builtin_ia32_writeeflags_u32: + return true; + } + + return false; +} + bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_supports) return SemaBuiltinCpuSupports(*this, TheCall); @@ -2263,6 +3392,12 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_is) return SemaBuiltinCpuIs(*this, TheCall); + // Check for 32-bit only builtins on a 64-bit target. + const llvm::Triple &TT = Context.getTargetInfo().getTriple(); + if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID)) + return Diag(TheCall->getCallee()->getLocStart(), + diag::err_32_bit_builtin_64_bit_tgt); + // If the intrinsic has rounding or SAE make sure its valid. if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) return true; @@ -2277,14 +3412,67 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { default: return false; + case X86::BI__builtin_ia32_vec_ext_v2si: + case X86::BI__builtin_ia32_vec_ext_v2di: + case X86::BI__builtin_ia32_vextractf128_pd256: + case X86::BI__builtin_ia32_vextractf128_ps256: + case X86::BI__builtin_ia32_vextractf128_si256: + case X86::BI__builtin_ia32_extract128i256: + case X86::BI__builtin_ia32_extractf64x4_mask: + case X86::BI__builtin_ia32_extracti64x4_mask: + case X86::BI__builtin_ia32_extractf32x8_mask: + case X86::BI__builtin_ia32_extracti32x8_mask: + case X86::BI__builtin_ia32_extractf64x2_256_mask: + case X86::BI__builtin_ia32_extracti64x2_256_mask: + case X86::BI__builtin_ia32_extractf32x4_256_mask: + case X86::BI__builtin_ia32_extracti32x4_256_mask: + i = 1; l = 0; u = 1; + break; + case X86::BI__builtin_ia32_vec_set_v2di: + case X86::BI__builtin_ia32_vinsertf128_pd256: + case X86::BI__builtin_ia32_vinsertf128_ps256: + case X86::BI__builtin_ia32_vinsertf128_si256: + case X86::BI__builtin_ia32_insert128i256: + case X86::BI__builtin_ia32_insertf32x8: + case X86::BI__builtin_ia32_inserti32x8: + case X86::BI__builtin_ia32_insertf64x4: + case X86::BI__builtin_ia32_inserti64x4: + case X86::BI__builtin_ia32_insertf64x2_256: + case X86::BI__builtin_ia32_inserti64x2_256: + case X86::BI__builtin_ia32_insertf32x4_256: + case X86::BI__builtin_ia32_inserti32x4_256: + i = 2; l = 0; u = 1; + break; + case X86::BI__builtin_ia32_vpermilpd: + case X86::BI__builtin_ia32_vec_ext_v4hi: + case X86::BI__builtin_ia32_vec_ext_v4si: + case X86::BI__builtin_ia32_vec_ext_v4sf: + case X86::BI__builtin_ia32_vec_ext_v4di: + case X86::BI__builtin_ia32_extractf32x4_mask: + case X86::BI__builtin_ia32_extracti32x4_mask: + case X86::BI__builtin_ia32_extractf64x2_512_mask: + case X86::BI__builtin_ia32_extracti64x2_512_mask: + i = 1; l = 0; u = 3; + break; case X86::BI_mm_prefetch: + case X86::BI__builtin_ia32_vec_ext_v8hi: + case X86::BI__builtin_ia32_vec_ext_v8si: i = 1; l = 0; u = 7; break; case X86::BI__builtin_ia32_sha1rnds4: - case X86::BI__builtin_ia32_shuf_f32x4_256_mask: - case X86::BI__builtin_ia32_shuf_f64x2_256_mask: - case X86::BI__builtin_ia32_shuf_i32x4_256_mask: - case X86::BI__builtin_ia32_shuf_i64x2_256_mask: + case X86::BI__builtin_ia32_blendpd: + case X86::BI__builtin_ia32_shufpd: + case X86::BI__builtin_ia32_vec_set_v4hi: + case X86::BI__builtin_ia32_vec_set_v4si: + case X86::BI__builtin_ia32_vec_set_v4di: + case X86::BI__builtin_ia32_shuf_f32x4_256: + case X86::BI__builtin_ia32_shuf_f64x2_256: + case X86::BI__builtin_ia32_shuf_i32x4_256: + case X86::BI__builtin_ia32_shuf_i64x2_256: + case X86::BI__builtin_ia32_insertf64x2_512: + case X86::BI__builtin_ia32_inserti64x2_512: + case X86::BI__builtin_ia32_insertf32x4: + case X86::BI__builtin_ia32_inserti32x4: i = 2; l = 0; u = 3; break; case X86::BI__builtin_ia32_vpermil2pd: @@ -2325,14 +3513,29 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vpcomw: case X86::BI__builtin_ia32_vpcomd: case X86::BI__builtin_ia32_vpcomq: + case X86::BI__builtin_ia32_vec_set_v8hi: + case X86::BI__builtin_ia32_vec_set_v8si: i = 2; l = 0; u = 7; break; + case X86::BI__builtin_ia32_vpermilpd256: case X86::BI__builtin_ia32_roundps: case X86::BI__builtin_ia32_roundpd: case X86::BI__builtin_ia32_roundps256: case X86::BI__builtin_ia32_roundpd256: + case X86::BI__builtin_ia32_getmantpd128_mask: + case X86::BI__builtin_ia32_getmantpd256_mask: + case X86::BI__builtin_ia32_getmantps128_mask: + case X86::BI__builtin_ia32_getmantps256_mask: + case X86::BI__builtin_ia32_getmantpd512_mask: + case X86::BI__builtin_ia32_getmantps512_mask: + case X86::BI__builtin_ia32_vec_ext_v16qi: + case X86::BI__builtin_ia32_vec_ext_v16hi: i = 1; l = 0; u = 15; break; + case X86::BI__builtin_ia32_pblendd128: + case X86::BI__builtin_ia32_blendps: + case X86::BI__builtin_ia32_blendpd256: + case X86::BI__builtin_ia32_shufpd256: case X86::BI__builtin_ia32_roundss: case X86::BI__builtin_ia32_roundsd: case X86::BI__builtin_ia32_rangepd128_mask: @@ -2343,8 +3546,13 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_rangeps512_mask: case X86::BI__builtin_ia32_getmantsd_round_mask: case X86::BI__builtin_ia32_getmantss_round_mask: + case X86::BI__builtin_ia32_vec_set_v16qi: + case X86::BI__builtin_ia32_vec_set_v16hi: i = 2; l = 0; u = 15; break; + case X86::BI__builtin_ia32_vec_ext_v32qi: + i = 1; l = 0; u = 31; + break; case X86::BI__builtin_ia32_cmpps: case X86::BI__builtin_ia32_cmpss: case X86::BI__builtin_ia32_cmppd: @@ -2359,15 +3567,26 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cmppd512_mask: case X86::BI__builtin_ia32_cmpsd_mask: case X86::BI__builtin_ia32_cmpss_mask: + case X86::BI__builtin_ia32_vec_set_v32qi: i = 2; l = 0; u = 31; break; - case X86::BI__builtin_ia32_xabort: - i = 0; l = -128; u = 255; - break; - case X86::BI__builtin_ia32_pshufw: - case X86::BI__builtin_ia32_aeskeygenassist128: - i = 1; l = -128; u = 255; - break; + case X86::BI__builtin_ia32_permdf256: + case X86::BI__builtin_ia32_permdi256: + case X86::BI__builtin_ia32_permdf512: + case X86::BI__builtin_ia32_permdi512: + case X86::BI__builtin_ia32_vpermilps: + case X86::BI__builtin_ia32_vpermilps256: + case X86::BI__builtin_ia32_vpermilpd512: + case X86::BI__builtin_ia32_vpermilps512: + case X86::BI__builtin_ia32_pshufd: + case X86::BI__builtin_ia32_pshufd256: + case X86::BI__builtin_ia32_pshufd512: + case X86::BI__builtin_ia32_pshufhw: + case X86::BI__builtin_ia32_pshufhw256: + case X86::BI__builtin_ia32_pshufhw512: + case X86::BI__builtin_ia32_pshuflw: + case X86::BI__builtin_ia32_pshuflw256: + case X86::BI__builtin_ia32_pshuflw512: case X86::BI__builtin_ia32_vcvtps2ph: case X86::BI__builtin_ia32_vcvtps2ph_mask: case X86::BI__builtin_ia32_vcvtps2ph256: @@ -2385,16 +3604,18 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_reduceps128_mask: case X86::BI__builtin_ia32_reduceps256_mask: case X86::BI__builtin_ia32_reduceps512_mask: - case X86::BI__builtin_ia32_prold512_mask: - case X86::BI__builtin_ia32_prolq512_mask: - case X86::BI__builtin_ia32_prold128_mask: - case X86::BI__builtin_ia32_prold256_mask: - case X86::BI__builtin_ia32_prolq128_mask: - case X86::BI__builtin_ia32_prolq256_mask: - case X86::BI__builtin_ia32_prord128_mask: - case X86::BI__builtin_ia32_prord256_mask: - case X86::BI__builtin_ia32_prorq128_mask: - case X86::BI__builtin_ia32_prorq256_mask: + case X86::BI__builtin_ia32_prold512: + case X86::BI__builtin_ia32_prolq512: + case X86::BI__builtin_ia32_prold128: + case X86::BI__builtin_ia32_prold256: + case X86::BI__builtin_ia32_prolq128: + case X86::BI__builtin_ia32_prolq256: + case X86::BI__builtin_ia32_prord512: + case X86::BI__builtin_ia32_prorq512: + case X86::BI__builtin_ia32_prord128: + case X86::BI__builtin_ia32_prord256: + case X86::BI__builtin_ia32_prorq128: + case X86::BI__builtin_ia32_prorq256: case X86::BI__builtin_ia32_fpclasspd128_mask: case X86::BI__builtin_ia32_fpclasspd256_mask: case X86::BI__builtin_ia32_fpclassps128_mask: @@ -2403,41 +3624,62 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_fpclasspd512_mask: case X86::BI__builtin_ia32_fpclasssd_mask: case X86::BI__builtin_ia32_fpclassss_mask: + case X86::BI__builtin_ia32_pslldqi128_byteshift: + case X86::BI__builtin_ia32_pslldqi256_byteshift: + case X86::BI__builtin_ia32_pslldqi512_byteshift: + case X86::BI__builtin_ia32_psrldqi128_byteshift: + case X86::BI__builtin_ia32_psrldqi256_byteshift: + case X86::BI__builtin_ia32_psrldqi512_byteshift: i = 1; l = 0; u = 255; break; - case X86::BI__builtin_ia32_palignr: - case X86::BI__builtin_ia32_insertps128: - case X86::BI__builtin_ia32_dpps: - case X86::BI__builtin_ia32_dppd: - case X86::BI__builtin_ia32_dpps256: - case X86::BI__builtin_ia32_mpsadbw128: - case X86::BI__builtin_ia32_mpsadbw256: - case X86::BI__builtin_ia32_pcmpistrm128: - case X86::BI__builtin_ia32_pcmpistri128: - case X86::BI__builtin_ia32_pcmpistria128: - case X86::BI__builtin_ia32_pcmpistric128: - case X86::BI__builtin_ia32_pcmpistrio128: - case X86::BI__builtin_ia32_pcmpistris128: - case X86::BI__builtin_ia32_pcmpistriz128: - case X86::BI__builtin_ia32_pclmulqdq128: case X86::BI__builtin_ia32_vperm2f128_pd256: case X86::BI__builtin_ia32_vperm2f128_ps256: case X86::BI__builtin_ia32_vperm2f128_si256: case X86::BI__builtin_ia32_permti256: - i = 2; l = -128; u = 255; - break; + case X86::BI__builtin_ia32_pblendw128: + case X86::BI__builtin_ia32_pblendw256: + case X86::BI__builtin_ia32_blendps256: + case X86::BI__builtin_ia32_pblendd256: case X86::BI__builtin_ia32_palignr128: case X86::BI__builtin_ia32_palignr256: - case X86::BI__builtin_ia32_palignr512_mask: + case X86::BI__builtin_ia32_palignr512: + case X86::BI__builtin_ia32_alignq512: + case X86::BI__builtin_ia32_alignd512: + case X86::BI__builtin_ia32_alignd128: + case X86::BI__builtin_ia32_alignd256: + case X86::BI__builtin_ia32_alignq128: + case X86::BI__builtin_ia32_alignq256: case X86::BI__builtin_ia32_vcomisd: case X86::BI__builtin_ia32_vcomiss: - case X86::BI__builtin_ia32_shuf_f32x4_mask: - case X86::BI__builtin_ia32_shuf_f64x2_mask: - case X86::BI__builtin_ia32_shuf_i32x4_mask: - case X86::BI__builtin_ia32_shuf_i64x2_mask: - case X86::BI__builtin_ia32_dbpsadbw128_mask: - case X86::BI__builtin_ia32_dbpsadbw256_mask: - case X86::BI__builtin_ia32_dbpsadbw512_mask: + case X86::BI__builtin_ia32_shuf_f32x4: + case X86::BI__builtin_ia32_shuf_f64x2: + case X86::BI__builtin_ia32_shuf_i32x4: + case X86::BI__builtin_ia32_shuf_i64x2: + case X86::BI__builtin_ia32_shufpd512: + case X86::BI__builtin_ia32_shufps: + case X86::BI__builtin_ia32_shufps256: + case X86::BI__builtin_ia32_shufps512: + case X86::BI__builtin_ia32_dbpsadbw128: + case X86::BI__builtin_ia32_dbpsadbw256: + case X86::BI__builtin_ia32_dbpsadbw512: + case X86::BI__builtin_ia32_vpshldd128: + case X86::BI__builtin_ia32_vpshldd256: + case X86::BI__builtin_ia32_vpshldd512: + case X86::BI__builtin_ia32_vpshldq128: + case X86::BI__builtin_ia32_vpshldq256: + case X86::BI__builtin_ia32_vpshldq512: + case X86::BI__builtin_ia32_vpshldw128: + case X86::BI__builtin_ia32_vpshldw256: + case X86::BI__builtin_ia32_vpshldw512: + case X86::BI__builtin_ia32_vpshrdd128: + case X86::BI__builtin_ia32_vpshrdd256: + case X86::BI__builtin_ia32_vpshrdd512: + case X86::BI__builtin_ia32_vpshrdq128: + case X86::BI__builtin_ia32_vpshrdq256: + case X86::BI__builtin_ia32_vpshrdq512: + case X86::BI__builtin_ia32_vpshrdw128: + case X86::BI__builtin_ia32_vpshrdw256: + case X86::BI__builtin_ia32_vpshrdw512: i = 2; l = 0; u = 255; break; case X86::BI__builtin_ia32_fixupimmpd512_mask: @@ -2480,21 +3722,17 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_scatterpfqps: i = 4; l = 2; u = 3; break; - case X86::BI__builtin_ia32_pcmpestrm128: - case X86::BI__builtin_ia32_pcmpestri128: - case X86::BI__builtin_ia32_pcmpestria128: - case X86::BI__builtin_ia32_pcmpestric128: - case X86::BI__builtin_ia32_pcmpestrio128: - case X86::BI__builtin_ia32_pcmpestris128: - case X86::BI__builtin_ia32_pcmpestriz128: - i = 4; l = -128; u = 255; - break; case X86::BI__builtin_ia32_rndscalesd_round_mask: case X86::BI__builtin_ia32_rndscaless_round_mask: i = 4; l = 0; u = 255; break; } - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + + // Note that we don't force a hard error on the range check here, allowing + // template-generated or macro-generated dead code to potentially have out-of- + // range values. These need to code generate, but don't need to necessarily + // make any sense. We use a warning that defaults to an error. + return SemaBuiltinConstantArgRange(TheCall, i, l, u, /*RangeIsError*/ false); } /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo @@ -2522,7 +3760,7 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, /// Checks if a the given expression evaluates to null. /// -/// \brief Returns true if the value evaluates to null. +/// Returns true if the value evaluates to null. static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { // If the expression has non-null type, it doesn't evaluate to null. if (auto nullability @@ -2566,7 +3804,7 @@ bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { return false; } -/// \brief Diagnose use of %s directive in an NSString which is being passed +/// Diagnose use of %s directive in an NSString which is being passed /// as formatting string to formatting method. static void DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, @@ -2612,7 +3850,7 @@ DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, static bool isNonNullType(ASTContext &ctx, QualType type) { if (auto nullability = type->getNullability(ctx)) return *nullability == NullabilityKind::NonNull; - + return false; } @@ -2636,12 +3874,13 @@ static void CheckNonNullArguments(Sema &S, return; } - for (unsigned Val : NonNull->args()) { - if (Val >= Args.size()) + for (const ParamIdx &Idx : NonNull->args()) { + unsigned IdxAST = Idx.getASTIndex(); + if (IdxAST >= Args.size()) continue; if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); - NonNullArgs.set(Val); + NonNullArgs.set(IdxAST); } } } @@ -2654,12 +3893,12 @@ static void CheckNonNullArguments(Sema &S, parms = FD->parameters(); else parms = cast<ObjCMethodDecl>(FDecl)->parameters(); - + unsigned ParamIndex = 0; for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); I != E; ++I, ++ParamIndex) { const ParmVarDecl *PVD = *I; - if (PVD->hasAttr<NonNullAttr>() || + if (PVD->hasAttr<NonNullAttr>() || isNonNullType(S.Context, PVD->getType())) { if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); @@ -2681,7 +3920,7 @@ static void CheckNonNullArguments(Sema &S, // Dig out the function prototype, if there is one. Proto = type->getAs<FunctionProtoType>(); - } + } } // Fill in non-null argument information from the nullability @@ -2692,17 +3931,17 @@ static void CheckNonNullArguments(Sema &S, if (isNonNullType(S.Context, paramType)) { if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); - + NonNullArgs.set(Index); } - + ++Index; } } } // Check for non-null arguments. - for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size(); + for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size(); ArgIndex != ArgIndexEnd; ++ArgIndex) { if (NonNullArgs[ArgIndex]) CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); @@ -2835,7 +4074,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, return false; } -bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, +bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, ArrayRef<const Expr *> Args) { VariadicCallType CallType = Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply; @@ -2985,6 +4224,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Op == AtomicExpr::AO__atomic_exchange_n || Op == AtomicExpr::AO__atomic_compare_exchange_n; bool IsAddSub = false; + bool IsMinMax = false; switch (Op) { case AtomicExpr::AO__c11_atomic_init: @@ -3038,6 +4278,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Form = Arithmetic; break; + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_max: + IsMinMax = true; + Form = Arithmetic; + break; + case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: @@ -3120,12 +4366,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { // gcc does not enforce these rules for GNU atomics, but we do so for sanity. - if (IsAddSub && !ValType->isIntegerType() && !ValType->isPointerType()) { + if (IsAddSub && !ValType->isIntegerType() + && !ValType->isPointerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - if (!IsAddSub && !ValType->isIntegerType()) { + if (IsMinMax) { + const BuiltinType *BT = ValType->getAs<BuiltinType>(); + if (!BT || (BT->getKind() != BuiltinType::Int && + BT->getKind() != BuiltinType::UInt)) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_int32_or_ptr); + return ExprError(); + } + } + if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_bitwise_needs_atomic_int) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); @@ -3168,9 +4423,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, return ExprError(); } - // atomic_fetch_or takes a pointer to a volatile 'A'. We shouldn't let the - // volatile-ness of the pointee-type inject itself into the result or the - // other operands. Similarly atomic_load can take a pointer to a const 'A'. + // All atomic operations have an overload which takes a pointer to a volatile + // 'A'. We shouldn't let the volatile-ness of the pointee-type inject itself + // into the result or the other operands. Similarly atomic_load takes a + // pointer to a const 'A'. ValType.removeLocalVolatile(); ValType.removeLocalConst(); QualType ResultType = ValType; @@ -3183,16 +4439,27 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // The type of a parameter passed 'by value'. In the GNU atomics, such // arguments are actually passed as pointers. QualType ByValType = ValType; // 'CP' - if (!IsC11 && !IsN) + bool IsPassedByAddress = false; + if (!IsC11 && !IsN) { ByValType = Ptr->getType(); + IsPassedByAddress = true; + } - // The first argument --- the pointer --- has a fixed type; we - // deduce the types of the rest of the arguments accordingly. Walk - // the remaining arguments, converting them to the deduced value type. - for (unsigned i = 1; i != TheCall->getNumArgs(); ++i) { + // The first argument's non-CV pointer type is used to deduce the type of + // subsequent arguments, except for: + // - weak flag (always converted to bool) + // - memory order (always converted to int) + // - scope (always converted to int) + for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { QualType Ty; if (i < NumVals[Form] + 1) { switch (i) { + case 0: + // The first argument is always a pointer. It has a fixed type. + // It is always dereferenced, a nullptr is undefined. + CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart()); + // Nothing else to do: we already know all we want about this pointer. + continue; case 1: // The second argument is the non-atomic operand. For arithmetic, this // is always passed by value, and for a compare_exchange it is always @@ -3201,14 +4468,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, assert(Form != Load); if (Form == Init || (Form == Arithmetic && ValType->isIntegerType())) Ty = ValType; - else if (Form == Copy || Form == Xchg) + else if (Form == Copy || Form == Xchg) { + if (IsPassedByAddress) + // The value pointer is always dereferenced, a nullptr is undefined. + CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart()); Ty = ByValType; - else if (Form == Arithmetic) + } else if (Form == Arithmetic) Ty = Context.getPointerDiffType(); else { Expr *ValArg = TheCall->getArg(i); - // Treat this argument as _Nonnull as we want to show a warning if - // NULL is passed into it. + // The value pointer is always dereferenced, a nullptr is undefined. CheckNonNullArgument(*this, ValArg, DRE->getLocStart()); LangAS AS = LangAS::Default; // Keep address space of non-atomic pointer type. @@ -3221,8 +4490,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } break; case 2: - // The third argument to compare_exchange / GNU exchange is a - // (pointer to a) desired value. + // The third argument to compare_exchange / GNU exchange is the desired + // value, either by-value (for the C11 and *_n variant) or as a pointer. + if (IsPassedByAddress) + CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart()); Ty = ByValType; break; case 3: @@ -3306,7 +4577,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr *AE = new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(), SubExprs, ResultType, Op, TheCall->getRParenLoc()); - + if ((Op == AtomicExpr::AO__c11_atomic_load || Op == AtomicExpr::AO__c11_atomic_store || Op == AtomicExpr::AO__opencl_atomic_load || @@ -3393,6 +4664,12 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return ExprError(); } + if (ValType.isConstQualified()) { + Diag(DRE->getLocStart(), diag::err_atomic_builtin_cannot_be_const) + << FirstArg->getType() << FirstArg->getSourceRange(); + return ExprError(); + } + switch (ValType.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: @@ -3467,52 +4744,52 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { bool WarnAboutSemanticsChange = false; switch (BuiltinID) { default: llvm_unreachable("Unknown overloaded atomic builtin!"); - case Builtin::BI__sync_fetch_and_add: + case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_add_1: case Builtin::BI__sync_fetch_and_add_2: case Builtin::BI__sync_fetch_and_add_4: case Builtin::BI__sync_fetch_and_add_8: case Builtin::BI__sync_fetch_and_add_16: - BuiltinIndex = 0; + BuiltinIndex = 0; break; - - case Builtin::BI__sync_fetch_and_sub: + + case Builtin::BI__sync_fetch_and_sub: case Builtin::BI__sync_fetch_and_sub_1: case Builtin::BI__sync_fetch_and_sub_2: case Builtin::BI__sync_fetch_and_sub_4: case Builtin::BI__sync_fetch_and_sub_8: case Builtin::BI__sync_fetch_and_sub_16: - BuiltinIndex = 1; + BuiltinIndex = 1; break; - - case Builtin::BI__sync_fetch_and_or: + + case Builtin::BI__sync_fetch_and_or: case Builtin::BI__sync_fetch_and_or_1: case Builtin::BI__sync_fetch_and_or_2: case Builtin::BI__sync_fetch_and_or_4: case Builtin::BI__sync_fetch_and_or_8: case Builtin::BI__sync_fetch_and_or_16: - BuiltinIndex = 2; + BuiltinIndex = 2; break; - - case Builtin::BI__sync_fetch_and_and: + + case Builtin::BI__sync_fetch_and_and: case Builtin::BI__sync_fetch_and_and_1: case Builtin::BI__sync_fetch_and_and_2: case Builtin::BI__sync_fetch_and_and_4: case Builtin::BI__sync_fetch_and_and_8: case Builtin::BI__sync_fetch_and_and_16: - BuiltinIndex = 3; + BuiltinIndex = 3; break; - case Builtin::BI__sync_fetch_and_xor: + case Builtin::BI__sync_fetch_and_xor: case Builtin::BI__sync_fetch_and_xor_1: case Builtin::BI__sync_fetch_and_xor_2: case Builtin::BI__sync_fetch_and_xor_4: case Builtin::BI__sync_fetch_and_xor_8: case Builtin::BI__sync_fetch_and_xor_16: - BuiltinIndex = 4; + BuiltinIndex = 4; break; - case Builtin::BI__sync_fetch_and_nand: + case Builtin::BI__sync_fetch_and_nand: case Builtin::BI__sync_fetch_and_nand_1: case Builtin::BI__sync_fetch_and_nand_2: case Builtin::BI__sync_fetch_and_nand_4: @@ -3522,43 +4799,43 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { WarnAboutSemanticsChange = true; break; - case Builtin::BI__sync_add_and_fetch: + case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_add_and_fetch_1: case Builtin::BI__sync_add_and_fetch_2: case Builtin::BI__sync_add_and_fetch_4: case Builtin::BI__sync_add_and_fetch_8: case Builtin::BI__sync_add_and_fetch_16: - BuiltinIndex = 6; + BuiltinIndex = 6; break; - - case Builtin::BI__sync_sub_and_fetch: + + case Builtin::BI__sync_sub_and_fetch: case Builtin::BI__sync_sub_and_fetch_1: case Builtin::BI__sync_sub_and_fetch_2: case Builtin::BI__sync_sub_and_fetch_4: case Builtin::BI__sync_sub_and_fetch_8: case Builtin::BI__sync_sub_and_fetch_16: - BuiltinIndex = 7; + BuiltinIndex = 7; break; - - case Builtin::BI__sync_and_and_fetch: + + case Builtin::BI__sync_and_and_fetch: case Builtin::BI__sync_and_and_fetch_1: case Builtin::BI__sync_and_and_fetch_2: case Builtin::BI__sync_and_and_fetch_4: case Builtin::BI__sync_and_and_fetch_8: case Builtin::BI__sync_and_and_fetch_16: - BuiltinIndex = 8; + BuiltinIndex = 8; break; - - case Builtin::BI__sync_or_and_fetch: + + case Builtin::BI__sync_or_and_fetch: case Builtin::BI__sync_or_and_fetch_1: case Builtin::BI__sync_or_and_fetch_2: case Builtin::BI__sync_or_and_fetch_4: case Builtin::BI__sync_or_and_fetch_8: case Builtin::BI__sync_or_and_fetch_16: - BuiltinIndex = 9; + BuiltinIndex = 9; break; - - case Builtin::BI__sync_xor_and_fetch: + + case Builtin::BI__sync_xor_and_fetch: case Builtin::BI__sync_xor_and_fetch_1: case Builtin::BI__sync_xor_and_fetch_2: case Builtin::BI__sync_xor_and_fetch_4: @@ -3567,7 +4844,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { BuiltinIndex = 10; break; - case Builtin::BI__sync_nand_and_fetch: + case Builtin::BI__sync_nand_and_fetch: case Builtin::BI__sync_nand_and_fetch_1: case Builtin::BI__sync_nand_and_fetch_2: case Builtin::BI__sync_nand_and_fetch_4: @@ -3586,7 +4863,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { BuiltinIndex = 12; NumFixed = 2; break; - + case Builtin::BI__sync_bool_compare_and_swap: case Builtin::BI__sync_bool_compare_and_swap_1: case Builtin::BI__sync_bool_compare_and_swap_2: @@ -3597,16 +4874,16 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { NumFixed = 2; ResultType = Context.BoolTy; break; - - case Builtin::BI__sync_lock_test_and_set: + + case Builtin::BI__sync_lock_test_and_set: case Builtin::BI__sync_lock_test_and_set_1: case Builtin::BI__sync_lock_test_and_set_2: case Builtin::BI__sync_lock_test_and_set_4: case Builtin::BI__sync_lock_test_and_set_8: case Builtin::BI__sync_lock_test_and_set_16: - BuiltinIndex = 14; + BuiltinIndex = 14; break; - + case Builtin::BI__sync_lock_release: case Builtin::BI__sync_lock_release_1: case Builtin::BI__sync_lock_release_2: @@ -3617,14 +4894,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { NumFixed = 0; ResultType = Context.VoidTy; break; - - case Builtin::BI__sync_swap: + + case Builtin::BI__sync_swap: case Builtin::BI__sync_swap_1: case Builtin::BI__sync_swap_2: case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: - BuiltinIndex = 16; + BuiltinIndex = 16; break; } @@ -4115,21 +5392,25 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); - // If this is an implicit conversion from float -> float or double, remove it. + // If this is an implicit conversion from float -> float, double, or + // long double, remove it. if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) { // Only remove standard FloatCasts, leaving other casts inplace if (Cast->getCastKind() == CK_FloatingCast) { Expr *CastArg = Cast->getSubExpr(); if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { - assert((Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || - Cast->getType()->isSpecificBuiltinType(BuiltinType::Float)) && - "promotion from float to either float or double is the only expected cast here"); + assert( + (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) && + "promotion from float to either float, double, or long double is " + "the only expected cast here"); Cast->setSubExpr(nullptr); TheCall->setArg(NumArgs-1, CastArg); } } } - + return false; } @@ -4506,20 +5787,20 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, Expr *Arg = TheCall->getArg(ArgNum); DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl()); - + if (Arg->isTypeDependent() || Arg->isValueDependent()) return false; - + if (!Arg->isIntegerConstantExpr(Result, Context)) return Diag(TheCall->getLocStart(), diag::err_constant_integer_arg_type) << FDecl->getDeclName() << Arg->getSourceRange(); - + return false; } /// SemaBuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression in the range [Low, High]. bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, - int Low, int High) { + int Low, int High, bool RangeIsError) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -4531,9 +5812,18 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) return true; - if (Result.getSExtValue() < Low || Result.getSExtValue() > High) - return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) - << Low << High << Arg->getSourceRange(); + if (Result.getSExtValue() < Low || Result.getSExtValue() > High) { + if (RangeIsError) + return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) + << Result.toString(10) << Low << High << Arg->getSourceRange(); + else + // Defer the warning until we know if the code will be emitted so that + // dead code can ignore this. + DiagRuntimeBehavior(TheCall->getLocStart(), TheCall, + PDiag(diag::warn_argument_invalid_range) + << Result.toString(10) << Low << High + << Arg->getSourceRange()); + } return false; } @@ -4674,7 +5964,7 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { // TODO: This is less than ideal. Overload this to take a value. if (SemaBuiltinConstantArg(TheCall, 1, Result)) return true; - + if (Result != 1) return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val) << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); @@ -4831,11 +6121,13 @@ class FormatStringLiteral { StartToken, StartTokenByteOffset); } - SourceLocation getLocStart() const LLVM_READONLY { + SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return FExpr->getLocStart().getLocWithOffset(Offset); } - SourceLocation getLocEnd() const LLVM_READONLY { return FExpr->getLocEnd(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { return FExpr->getLocEnd(); } }; } // namespace @@ -4941,7 +6233,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, // cannot contain format specifiers and thus are not a security // liability. return SLCT_UncheckedLiteral; - + case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast<DeclRefExpr>(E); @@ -5018,18 +6310,22 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, case Stmt::CXXMemberCallExprClass: { const CallExpr *CE = cast<CallExpr>(E); if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) { - if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) { - unsigned ArgIndex = FA->getFormatIdx(); - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND)) - if (MD->isInstance()) - --ArgIndex; - const Expr *Arg = CE->getArg(ArgIndex - 1); - - return checkFormatStringExpr(S, Arg, Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg, Offset); - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + bool IsFirst = true; + StringLiteralCheckType CommonResult; + for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) { + const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex()); + StringLiteralCheckType Result = checkFormatStringExpr( + S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + if (IsFirst) { + CommonResult = Result; + IsFirst = false; + } + } + if (!IsFirst) + return CommonResult; + + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) { @@ -5049,8 +6345,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, const auto *ME = cast<ObjCMessageExpr>(E); if (const auto *ND = ME->getMethodDecl()) { if (const auto *FA = ND->getAttr<FormatArgAttr>()) { - unsigned ArgIndex = FA->getFormatIdx(); - const Expr *Arg = ME->getArg(ArgIndex - 1); + const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex()); return checkFormatStringExpr( S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); @@ -5334,14 +6629,14 @@ protected: void HandlePositionalNonpositionalArgs(SourceLocation Loc, const char *startSpec, unsigned specifierLen); - + SourceRange getFormatStringRange(); CharSourceRange getSpecifierRange(const char *startSpecifier, unsigned specifierLen); SourceLocation getLocationOfByte(const char *x); const Expr *getDataArg(unsigned i) const; - + bool CheckNumArgs(const analyze_format_string::FormatSpecifier &FS, const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen, @@ -5655,7 +6950,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, Loc, IsStringLocation, StringRange, FixIt); } -/// \brief If the format string is not within the funcion call, emit a note +/// If the format string is not within the function call, emit a note /// so that the function call and string are in diagnostic messages. /// /// \param InFunctionCall if true, the format string is within the function @@ -5760,7 +7055,7 @@ public: const char *startSpecifier, unsigned specifierLen); bool checkForCStrMembers(const analyze_printf::ArgType &AT, const Expr *E); - + void HandleEmptyObjCModifierFlag(const char *startFlag, unsigned flagLen) override; @@ -5769,7 +7064,7 @@ public: void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, const char *flagsEnd, - const char *conversionPosition) + const char *conversionPosition) override; }; @@ -5781,7 +7076,7 @@ bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( unsigned specifierLen) { const analyze_printf::PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); - + return HandleInvalidConversionSpecifier(FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier, specifierLen, @@ -6326,11 +7621,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ExprTy = TET->getUnderlyingExpr()->getType(); } - analyze_printf::ArgType::MatchKind match = AT.matchesType(S.Context, ExprTy); - - if (match == analyze_printf::ArgType::Match) { + const analyze_printf::ArgType::MatchKind Match = + AT.matchesType(S.Context, ExprTy); + bool Pedantic = Match == analyze_printf::ArgType::NoMatchPedantic; + if (Match == analyze_printf::ArgType::Match) return true; - } // Look through argument promotions for our error message's reported type. // This includes the integral and floating promotions, but excludes array @@ -6406,6 +7701,12 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, QualType CastTy; std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E); if (!CastTy.isNull()) { + // %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int + // (long in ASTContext). Only complain to pedants. + if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") && + (AT.isSizeT() || AT.isPtrdiffT()) && + AT.matchesType(S.Context, CastTy)) + Pedantic = true; IntendedTy = CastTy; ShouldNotPrintDirectly = true; } @@ -6413,10 +7714,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // We may be able to offer a FixItHint if it is a supported type. PrintfSpecifier fixedFS = FS; - bool success = + bool Success = fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext()); - if (success) { + if (Success) { // Get the fix string from the fixed format specifier SmallString<16> buf; llvm::raw_svector_ostream os(buf); @@ -6425,13 +7726,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { - unsigned diag = diag::warn_format_conversion_argument_type_mismatch; - if (match == analyze_format_string::ArgType::NoMatchPedantic) { - diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; - } + unsigned Diag = + Pedantic + ? diag::warn_format_conversion_argument_type_mismatch_pedantic + : diag::warn_format_conversion_argument_type_mismatch; // In this case, the specifier is wrong and should be changed to match // the argument. - EmitFormatDiagnostic(S.PDiag(diag) + EmitFormatDiagnostic(S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << IntendedTy << IsEnum << E->getSourceRange(), E->getLocStart(), @@ -6452,7 +7753,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CastFix << ")"; SmallVector<FixItHint,4> Hints; - if (!AT.matchesType(S.Context, IntendedTy) || ShouldNotPrintDirectly) + if (!AT.matchesType(S.Context, IntendedTy) || ShouldNotPrintDirectly) Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) { @@ -6484,14 +7785,16 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, Name = TypedefTy->getDecl()->getName(); else Name = CastTyName; - EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast) - << Name << IntendedTy << IsEnum - << E->getSourceRange(), + unsigned Diag = Pedantic + ? diag::warn_format_argument_needs_cast_pedantic + : diag::warn_format_argument_needs_cast; + EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum + << E->getSourceRange(), E->getLocStart(), /*IsStringLocation=*/false, SpecRange, Hints); } else { // In this case, the expression could be printed using a different - // specifier, but we've decided that the specifier is probably correct + // specifier, but we've decided that the specifier is probably correct // and we should cast instead. Just use the normal warning message. EmitFormatDiagnostic( S.PDiag(diag::warn_format_conversion_argument_type_mismatch) @@ -6510,13 +7813,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, switch (S.isValidVarArgType(ExprTy)) { case Sema::VAK_Valid: case Sema::VAK_ValidInCXX11: { - unsigned diag = diag::warn_format_conversion_argument_type_mismatch; - if (match == analyze_printf::ArgType::NoMatchPedantic) { - diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; - } + unsigned Diag = + Pedantic + ? diag::warn_format_conversion_argument_type_mismatch_pedantic + : diag::warn_format_conversion_argument_type_mismatch; EmitFormatDiagnostic( - S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy + S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum << CSR << E->getSourceRange(), E->getLocStart(), /*IsStringLocation*/ false, CSR); break; @@ -6566,7 +7869,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, //===--- CHECK: Scanf format string checking ------------------------------===// -namespace { +namespace { class CheckScanfHandler : public CheckFormatHandler { public: @@ -6586,7 +7889,7 @@ public: bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; - + bool HandleInvalidScanfConversionSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, @@ -6622,7 +7925,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( const char *startSpecifier, unsigned specifierLen) { using namespace analyze_scanf; - using namespace analyze_format_string; + using namespace analyze_format_string; const ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); @@ -6639,7 +7942,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( return false; } } - + // Check if the field with is non-zero. const OptionalAmount &Amt = FS.getFieldWidth(); if (Amt.getHowSpecified() == OptionalAmount::Constant) { @@ -6699,29 +8002,28 @@ bool CheckScanfHandler::HandleScanfSpecifier( return true; } - analyze_format_string::ArgType::MatchKind match = + analyze_format_string::ArgType::MatchKind Match = AT.matchesType(S.Context, Ex->getType()); - if (match == analyze_format_string::ArgType::Match) { + bool Pedantic = Match == analyze_format_string::ArgType::NoMatchPedantic; + if (Match == analyze_format_string::ArgType::Match) return true; - } ScanfSpecifier fixedFS = FS; - bool success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(), + bool Success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(), S.getLangOpts(), S.Context); - unsigned diag = diag::warn_format_conversion_argument_type_mismatch; - if (match == analyze_format_string::ArgType::NoMatchPedantic) { - diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; - } + unsigned Diag = + Pedantic ? diag::warn_format_conversion_argument_type_mismatch_pedantic + : diag::warn_format_conversion_argument_type_mismatch; - if (success) { + if (Success) { // Get the fix string from the fixed format specifier. SmallString<128> buf; llvm::raw_svector_ostream os(buf); fixedFS.toString(os); EmitFormatDiagnostic( - S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) + S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), /*IsStringLocation*/ false, @@ -6729,7 +8031,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( FixItHint::CreateReplacement( getSpecifierRange(startSpecifier, specifierLen), os.str())); } else { - EmitFormatDiagnostic(S.PDiag(diag) + EmitFormatDiagnostic(S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), @@ -7283,7 +8585,7 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call, //===--- CHECK: Standard memory functions ---------------------------------===// -/// \brief Takes the expression passed to the size_t parameter of functions +/// Takes the expression passed to the size_t parameter of functions /// such as memcmp, strncat, etc and warns if it's a comparison. /// /// This is to catch typos like `if (memcmp(&a, &b, sizeof(a) > 0))`. @@ -7314,7 +8616,7 @@ static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E, return true; } -/// \brief Determine whether the given type is or contains a dynamic class type +/// Determine whether the given type is or contains a dynamic class type /// (e.g., whether it has a vtable). static const CXXRecordDecl *getContainedDynamicClass(QualType T, bool &IsContained) { @@ -7345,28 +8647,205 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T, return nullptr; } -/// \brief If E is a sizeof expression, returns its argument expression, +static const UnaryExprOrTypeTraitExpr *getAsSizeOfExpr(const Expr *E) { + if (const auto *Unary = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) + if (Unary->getKind() == UETT_SizeOf) + return Unary; + return nullptr; +} + +/// If E is a sizeof expression, returns its argument expression, /// otherwise returns NULL. static const Expr *getSizeOfExprArg(const Expr *E) { - if (const UnaryExprOrTypeTraitExpr *SizeOf = - dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == UETT_SizeOf && !SizeOf->isArgumentType()) + if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E)) + if (!SizeOf->isArgumentType()) return SizeOf->getArgumentExpr()->IgnoreParenImpCasts(); - return nullptr; } -/// \brief If E is a sizeof expression, returns its argument type. +/// If E is a sizeof expression, returns its argument type. static QualType getSizeOfArgType(const Expr *E) { - if (const UnaryExprOrTypeTraitExpr *SizeOf = - dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == UETT_SizeOf) - return SizeOf->getTypeOfArgument(); - + if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E)) + return SizeOf->getTypeOfArgument(); return QualType(); } -/// \brief Check for dangerous or invalid arguments to memset(). +namespace { + +struct SearchNonTrivialToInitializeField + : DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField> { + using Super = + DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField>; + + SearchNonTrivialToInitializeField(const Expr *E, Sema &S) : E(E), S(S) {} + + void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT, + SourceLocation SL) { + if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { + asDerived().visitArray(PDIK, AT, SL); + return; + } + + Super::visitWithKind(PDIK, FT, SL); + } + + void visitARCStrong(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); + } + void visitARCWeak(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); + } + void visitStruct(QualType FT, SourceLocation SL) { + for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields()) + visit(FD->getType(), FD->getLocation()); + } + void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK, + const ArrayType *AT, SourceLocation SL) { + visit(getContext().getBaseElementType(AT), SL); + } + void visitTrivial(QualType FT, SourceLocation SL) {} + + static void diag(QualType RT, const Expr *E, Sema &S) { + SearchNonTrivialToInitializeField(E, S).visitStruct(RT, SourceLocation()); + } + + ASTContext &getContext() { return S.getASTContext(); } + + const Expr *E; + Sema &S; +}; + +struct SearchNonTrivialToCopyField + : CopiedTypeVisitor<SearchNonTrivialToCopyField, false> { + using Super = CopiedTypeVisitor<SearchNonTrivialToCopyField, false>; + + SearchNonTrivialToCopyField(const Expr *E, Sema &S) : E(E), S(S) {} + + void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT, + SourceLocation SL) { + if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { + asDerived().visitArray(PCK, AT, SL); + return; + } + + Super::visitWithKind(PCK, FT, SL); + } + + void visitARCStrong(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); + } + void visitARCWeak(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); + } + void visitStruct(QualType FT, SourceLocation SL) { + for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields()) + visit(FD->getType(), FD->getLocation()); + } + void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT, + SourceLocation SL) { + visit(getContext().getBaseElementType(AT), SL); + } + void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT, + SourceLocation SL) {} + void visitTrivial(QualType FT, SourceLocation SL) {} + void visitVolatileTrivial(QualType FT, SourceLocation SL) {} + + static void diag(QualType RT, const Expr *E, Sema &S) { + SearchNonTrivialToCopyField(E, S).visitStruct(RT, SourceLocation()); + } + + ASTContext &getContext() { return S.getASTContext(); } + + const Expr *E; + Sema &S; +}; + +} + +/// Detect if \c SizeofExpr is likely to calculate the sizeof an object. +static bool doesExprLikelyComputeSize(const Expr *SizeofExpr) { + SizeofExpr = SizeofExpr->IgnoreParenImpCasts(); + + if (const auto *BO = dyn_cast<BinaryOperator>(SizeofExpr)) { + if (BO->getOpcode() != BO_Mul && BO->getOpcode() != BO_Add) + return false; + + return doesExprLikelyComputeSize(BO->getLHS()) || + doesExprLikelyComputeSize(BO->getRHS()); + } + + return getAsSizeOfExpr(SizeofExpr) != nullptr; +} + +/// Check if the ArgLoc originated from a macro passed to the call at CallLoc. +/// +/// \code +/// #define MACRO 0 +/// foo(MACRO); +/// foo(0); +/// \endcode +/// +/// This should return true for the first call to foo, but not for the second +/// (regardless of whether foo is a macro or function). +static bool isArgumentExpandedFromMacro(SourceManager &SM, + SourceLocation CallLoc, + SourceLocation ArgLoc) { + if (!CallLoc.isMacroID()) + return SM.getFileID(CallLoc) != SM.getFileID(ArgLoc); + + return SM.getFileID(SM.getImmediateMacroCallerLoc(CallLoc)) != + SM.getFileID(SM.getImmediateMacroCallerLoc(ArgLoc)); +} + +/// Diagnose cases like 'memset(buf, sizeof(buf), 0)', which should have the +/// last two arguments transposed. +static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) { + if (BId != Builtin::BImemset && BId != Builtin::BIbzero) + return; + + const Expr *SizeArg = + Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts(); + + auto isLiteralZero = [](const Expr *E) { + return isa<IntegerLiteral>(E) && cast<IntegerLiteral>(E)->getValue() == 0; + }; + + // If we're memsetting or bzeroing 0 bytes, then this is likely an error. + SourceLocation CallLoc = Call->getRParenLoc(); + SourceManager &SM = S.getSourceManager(); + if (isLiteralZero(SizeArg) && + !isArgumentExpandedFromMacro(SM, CallLoc, SizeArg->getExprLoc())) { + + SourceLocation DiagLoc = SizeArg->getExprLoc(); + + // Some platforms #define bzero to __builtin_memset. See if this is the + // case, and if so, emit a better diagnostic. + if (BId == Builtin::BIbzero || + (CallLoc.isMacroID() && Lexer::getImmediateMacroName( + CallLoc, SM, S.getLangOpts()) == "bzero")) { + S.Diag(DiagLoc, diag::warn_suspicious_bzero_size); + S.Diag(DiagLoc, diag::note_suspicious_bzero_size_silence); + } else if (!isLiteralZero(Call->getArg(1)->IgnoreImpCasts())) { + S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 0; + S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 0; + } + return; + } + + // If the second argument to a memset is a sizeof expression and the third + // isn't, this is also likely an error. This should catch + // 'memset(buf, sizeof(buf), 0xff)'. + if (BId == Builtin::BImemset && + doesExprLikelyComputeSize(Call->getArg(1)) && + !doesExprLikelyComputeSize(Call->getArg(2))) { + SourceLocation DiagLoc = Call->getArg(1)->getExprLoc(); + S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 1; + S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 1; + return; + } +} + +/// Check for dangerous or invalid arguments to memset(). /// /// This issues warnings on known problematic, dangerous or unspecified /// arguments to the standard 'memset', 'memcpy', 'memmove', and 'memcmp' @@ -7395,6 +8874,9 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, Call->getLocStart(), Call->getRParenLoc())) return; + // Catch cases like 'memset(buf, sizeof(buf), 0)'. + CheckMemaccessSize(*this, BId, Call); + // We have special checking when the length is a sizeof expression. QualType SizeOfArgTy = getSizeOfArgType(LenExpr); const Expr *SizeOfArg = getSizeOfExprArg(LenExpr); @@ -7517,7 +8999,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, else if (BId == Builtin::BImemcmp) OperationType = 3; } - + DiagRuntimeBehavior( Dest->getExprLoc(), Dest, PDiag(diag::warn_dyn_class_memaccess) @@ -7531,7 +9013,23 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, PDiag(diag::warn_arc_object_memaccess) << ArgIdx << FnName << PointeeTy << Call->getCallee()->getSourceRange()); - else + else if (const auto *RT = PointeeTy->getAs<RecordType>()) { + if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && + RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) { + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_cstruct_memaccess) + << ArgIdx << FnName << PointeeTy << 0); + SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this); + } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) && + RT->getDecl()->isNonTrivialToPrimitiveCopy()) { + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_cstruct_memaccess) + << ArgIdx << FnName << PointeeTy << 1); + SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this); + } else { + continue; + } + } else continue; DiagRuntimeBehavior( @@ -7555,7 +9053,7 @@ static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) { const Expr *RHS = BO->getRHS()->IgnoreParenCasts(); const Expr *LHS = BO->getLHS()->IgnoreParenCasts(); - + if (isa<IntegerLiteral>(RHS)) Ex = LHS; else if (isa<IntegerLiteral>(LHS)) @@ -7597,7 +9095,7 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call, if (CheckMemorySizeofForComparison(*this, SizeArg, FnName, Call->getLocStart(), Call->getRParenLoc())) return; - + // Look for 'strlcpy(dst, x, sizeof(x))' if (const Expr *Ex = getSizeOfExprArg(SizeArg)) CompareWithSrc = Ex; @@ -7620,16 +9118,16 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call, const DeclRefExpr *SrcArgDRE = dyn_cast<DeclRefExpr>(SrcArg); if (!SrcArgDRE) return; - + const DeclRefExpr *CompareWithSrcDRE = dyn_cast<DeclRefExpr>(CompareWithSrc); - if (!CompareWithSrcDRE || + if (!CompareWithSrcDRE || SrcArgDRE->getDecl() != CompareWithSrcDRE->getDecl()) return; - + const Expr *OriginalSizeArg = Call->getArg(2); Diag(CompareWithSrcDRE->getLocStart(), diag::warn_strlcpycat_wrong_size) << OriginalSizeArg->getSourceRange() << FnName; - + // Output a FIXIT hint if the destination is an array (rather than a // pointer to an array). This could be enhanced to handle some // pointers if we know the actual size, like if DstArg is 'array+2' @@ -7643,7 +9141,7 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call, OS << "sizeof("; DstArg->printPretty(OS, nullptr, getPrintingPolicy()); OS << ")"; - + Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size) << FixItHint::CreateReplacement(OriginalSizeArg->getSourceRange(), OS.str()); @@ -7752,421 +9250,12 @@ void Sema::CheckStrncatArguments(const CallExpr *CE, << FixItHint::CreateReplacement(SR, OS.str()); } -//===--- CHECK: Return Address of Stack Variable --------------------------===// - -static const Expr *EvalVal(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl); -static const Expr *EvalAddr(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl); - -/// CheckReturnStackAddr - Check if a return statement returns the address -/// of a stack variable. -static void -CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, - SourceLocation ReturnLoc) { - const Expr *stackE = nullptr; - SmallVector<const DeclRefExpr *, 8> refVars; - - // Perform checking for returned stack addresses, local blocks, - // label addresses or references to temporaries. - if (lhsType->isPointerType() || - (!S.getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) { - stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/nullptr); - } else if (lhsType->isReferenceType()) { - stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/nullptr); - } - - if (!stackE) - return; // Nothing suspicious was found. - - // Parameters are initialized in the calling scope, so taking the address - // of a parameter reference doesn't need a warning. - for (auto *DRE : refVars) - if (isa<ParmVarDecl>(DRE->getDecl())) - return; - - SourceLocation diagLoc; - SourceRange diagRange; - if (refVars.empty()) { - diagLoc = stackE->getLocStart(); - diagRange = stackE->getSourceRange(); - } else { - // We followed through a reference variable. 'stackE' contains the - // problematic expression but we will warn at the return statement pointing - // at the reference variable. We will later display the "trail" of - // reference variables using notes. - diagLoc = refVars[0]->getLocStart(); - diagRange = refVars[0]->getSourceRange(); - } - - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { - // address of local var - S.Diag(diagLoc, diag::warn_ret_stack_addr_ref) << lhsType->isReferenceType() - << DR->getDecl()->getDeclName() << diagRange; - } else if (isa<BlockExpr>(stackE)) { // local block. - S.Diag(diagLoc, diag::err_ret_local_block) << diagRange; - } else if (isa<AddrLabelExpr>(stackE)) { // address of label. - S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange; - } else { // local temporary. - // If there is an LValue->RValue conversion, then the value of the - // reference type is used, not the reference. - if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetValExp)) { - if (ICE->getCastKind() == CK_LValueToRValue) { - return; - } - } - S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref) - << lhsType->isReferenceType() << diagRange; - } - - // Display the "trail" of reference variables that we followed until we - // found the problematic expression using notes. - for (unsigned i = 0, e = refVars.size(); i != e; ++i) { - const VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl()); - // If this var binds to another reference var, show the range of the next - // var, otherwise the var binds to the problematic expression, in which case - // show the range of the expression. - SourceRange range = (i < e - 1) ? refVars[i + 1]->getSourceRange() - : stackE->getSourceRange(); - S.Diag(VD->getLocation(), diag::note_ref_var_local_bind) - << VD->getDeclName() << range; - } -} - -/// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that -/// check if the expression in a return statement evaluates to an address -/// to a location on the stack, a local block, an address of a label, or a -/// reference to local temporary. The recursion is used to traverse the -/// AST of the return expression, with recursion backtracking when we -/// encounter a subexpression that (1) clearly does not lead to one of the -/// above problematic expressions (2) is something we cannot determine leads to -/// a problematic expression based on such local checking. -/// -/// Both EvalAddr and EvalVal follow through reference variables to evaluate -/// the expression that they point to. Such variables are added to the -/// 'refVars' vector so that we know what the reference variable "trail" was. -/// -/// EvalAddr processes expressions that are pointers that are used as -/// references (and not L-values). EvalVal handles all other values. -/// At the base case of the recursion is a check for the above problematic -/// expressions. -/// -/// This implementation handles: -/// -/// * pointer-to-pointer casts -/// * implicit conversions from array references to pointers -/// * taking the address of fields -/// * arbitrary interplay between "&" and "*" operators -/// * pointer arithmetic from an address of a stack variable -/// * taking the address of an array element where the array is on the stack -static const Expr *EvalAddr(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl) { - if (E->isTypeDependent()) - return nullptr; - - // We should only be called for evaluating pointer expressions. - assert((E->getType()->isAnyPointerType() || - E->getType()->isBlockPointerType() || - E->getType()->isObjCQualifiedIdType()) && - "EvalAddr only works on pointers"); - - E = E->IgnoreParens(); - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - switch (E->getStmtClass()) { - case Stmt::DeclRefExprClass: { - const DeclRefExpr *DR = cast<DeclRefExpr>(E); - - // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingVariableOrCapture()) - return nullptr; - - if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) - // If this is a reference variable, follow through to the expression that - // it points to. - if (V->hasLocalStorage() && - V->getType()->isReferenceType() && V->hasInit()) { - // Add the reference variable to the "trail". - refVars.push_back(DR); - return EvalAddr(V->getInit(), refVars, ParentDecl); - } - - return nullptr; - } - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is AddrOf. All others don't make sense as pointers. - const UnaryOperator *U = cast<UnaryOperator>(E); - - if (U->getOpcode() == UO_AddrOf) - return EvalVal(U->getSubExpr(), refVars, ParentDecl); - return nullptr; - } - - case Stmt::BinaryOperatorClass: { - // Handle pointer arithmetic. All other binary operators are not valid - // in this context. - const BinaryOperator *B = cast<BinaryOperator>(E); - BinaryOperatorKind op = B->getOpcode(); - - if (op != BO_Add && op != BO_Sub) - return nullptr; - - const Expr *Base = B->getLHS(); - - // Determine which argument is the real pointer base. It could be - // the RHS argument instead of the LHS. - if (!Base->getType()->isPointerType()) - Base = B->getRHS(); - - assert(Base->getType()->isPointerType()); - return EvalAddr(Base, refVars, ParentDecl); - } - - // For conditional operators we need to see if either the LHS or RHS are - // valid DeclRefExpr*s. If one of them is valid, we return it. - case Stmt::ConditionalOperatorClass: { - const ConditionalOperator *C = cast<ConditionalOperator>(E); - - // Handle the GNU extension for missing LHS. - // FIXME: That isn't a ConditionalOperator, so doesn't get here. - if (const Expr *LHSExpr = C->getLHS()) { - // In C++, we can have a throw-expression, which has 'void' type. - if (!LHSExpr->getType()->isVoidType()) - if (const Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl)) - return LHS; - } - - // In C++, we can have a throw-expression, which has 'void' type. - if (C->getRHS()->getType()->isVoidType()) - return nullptr; - - return EvalAddr(C->getRHS(), refVars, ParentDecl); - } - - case Stmt::BlockExprClass: - if (cast<BlockExpr>(E)->getBlockDecl()->hasCaptures()) - return E; // local block. - return nullptr; - - case Stmt::AddrLabelExprClass: - return E; // address of label. - - case Stmt::ExprWithCleanupsClass: - return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars, - ParentDecl); - - // For casts, we need to handle conversions from arrays to - // pointer values, and pointer-to-pointer conversions. - case Stmt::ImplicitCastExprClass: - case Stmt::CStyleCastExprClass: - case Stmt::CXXFunctionalCastExprClass: - case Stmt::ObjCBridgedCastExprClass: - case Stmt::CXXStaticCastExprClass: - case Stmt::CXXDynamicCastExprClass: - case Stmt::CXXConstCastExprClass: - case Stmt::CXXReinterpretCastExprClass: { - const Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); - switch (cast<CastExpr>(E)->getCastKind()) { - case CK_LValueToRValue: - case CK_NoOp: - case CK_BaseToDerived: - case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: - case CK_Dynamic: - case CK_CPointerToObjCPointerCast: - case CK_BlockPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - return EvalAddr(SubExpr, refVars, ParentDecl); - - case CK_ArrayToPointerDecay: - return EvalVal(SubExpr, refVars, ParentDecl); - - case CK_BitCast: - if (SubExpr->getType()->isAnyPointerType() || - SubExpr->getType()->isBlockPointerType() || - SubExpr->getType()->isObjCQualifiedIdType()) - return EvalAddr(SubExpr, refVars, ParentDecl); - else - return nullptr; - - default: - return nullptr; - } - } - - case Stmt::MaterializeTemporaryExprClass: - if (const Expr *Result = - EvalAddr(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) - return Result; - return E; - - // Everything else: we simply don't reason about them. - default: - return nullptr; - } -} - -/// EvalVal - This function is complements EvalAddr in the mutual recursion. -/// See the comments for EvalAddr for more details. -static const Expr *EvalVal(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl) { - do { - // We should only be called for evaluating non-pointer expressions, or - // expressions with a pointer type that are not used as references but - // instead - // are l-values (e.g., DeclRefExpr with a pointer type). - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - - E = E->IgnoreParens(); - switch (E->getStmtClass()) { - case Stmt::ImplicitCastExprClass: { - const ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E); - if (IE->getValueKind() == VK_LValue) { - E = IE->getSubExpr(); - continue; - } - return nullptr; - } - - case Stmt::ExprWithCleanupsClass: - return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars, - ParentDecl); - - case Stmt::DeclRefExprClass: { - // When we hit a DeclRefExpr we are looking at code that refers to a - // variable's name. If it's not a reference variable we check if it has - // local storage within the function, and if so, return the expression. - const DeclRefExpr *DR = cast<DeclRefExpr>(E); - - // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingVariableOrCapture()) - return nullptr; - - if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) { - // Check if it refers to itself, e.g. "int& i = i;". - if (V == ParentDecl) - return DR; - - if (V->hasLocalStorage()) { - if (!V->getType()->isReferenceType()) - return DR; - - // Reference variable, follow through to the expression that - // it points to. - if (V->hasInit()) { - // Add the reference variable to the "trail". - refVars.push_back(DR); - return EvalVal(V->getInit(), refVars, V); - } - } - } - - return nullptr; - } - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is Deref. All others don't resolve to a "name." This includes - // handling all sorts of rvalues passed to a unary operator. - const UnaryOperator *U = cast<UnaryOperator>(E); - - if (U->getOpcode() == UO_Deref) - return EvalAddr(U->getSubExpr(), refVars, ParentDecl); - - return nullptr; - } - - case Stmt::ArraySubscriptExprClass: { - // Array subscripts are potential references to data on the stack. We - // retrieve the DeclRefExpr* for the array variable if it indeed - // has local storage. - const auto *ASE = cast<ArraySubscriptExpr>(E); - if (ASE->isTypeDependent()) - return nullptr; - return EvalAddr(ASE->getBase(), refVars, ParentDecl); - } - - case Stmt::OMPArraySectionExprClass: { - return EvalAddr(cast<OMPArraySectionExpr>(E)->getBase(), refVars, - ParentDecl); - } - - case Stmt::ConditionalOperatorClass: { - // For conditional operators we need to see if either the LHS or RHS are - // non-NULL Expr's. If one is non-NULL, we return it. - const ConditionalOperator *C = cast<ConditionalOperator>(E); - - // Handle the GNU extension for missing LHS. - if (const Expr *LHSExpr = C->getLHS()) { - // In C++, we can have a throw-expression, which has 'void' type. - if (!LHSExpr->getType()->isVoidType()) - if (const Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl)) - return LHS; - } - - // In C++, we can have a throw-expression, which has 'void' type. - if (C->getRHS()->getType()->isVoidType()) - return nullptr; - - return EvalVal(C->getRHS(), refVars, ParentDecl); - } - - // Accesses to members are potential references to data on the stack. - case Stmt::MemberExprClass: { - const MemberExpr *M = cast<MemberExpr>(E); - - // Check for indirect access. We only want direct field accesses. - if (M->isArrow()) - return nullptr; - - // Check whether the member type is itself a reference, in which case - // we're not going to refer to the member, but to what the member refers - // to. - if (M->getMemberDecl()->getType()->isReferenceType()) - return nullptr; - - return EvalVal(M->getBase(), refVars, ParentDecl); - } - - case Stmt::MaterializeTemporaryExprClass: - if (const Expr *Result = - EvalVal(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) - return Result; - return E; - - default: - // Check that we don't return or take the address of a reference to a - // temporary. This is only useful in C++. - if (!E->isTypeDependent() && E->isRValue()) - return E; - - // Everything else: we simply don't reason about them. - return nullptr; - } - } while (true); -} - void Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod, const AttrVec *Attrs, const FunctionDecl *FD) { - CheckReturnStackAddr(*this, RetValExp, lhsType, ReturnLoc); - // Check if the return value is null but should not be. if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) || (!isObjCMethod && isNonNullType(Context, lhsType))) && @@ -8184,7 +9273,7 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, if (Op == OO_New || Op == OO_Array_New) { const FunctionProtoType *Proto = FD->getType()->castAs<FunctionProtoType>(); - if (!Proto->isNothrow(Context, /*ResultIfDependent*/true) && + if (!Proto->isNothrow(/*ResultIfDependent*/true) && CheckNonNullExpr(*this, RetValExp)) Diag(ReturnLoc, diag::warn_operator_new_returns_null) << FD << getLangOpts().CPlusPlus11; @@ -8933,7 +10022,7 @@ static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } -/// \brief Implements -Wsign-compare. +/// Implements -Wsign-compare. /// /// \param E the binary operator to check for warnings static void AnalyzeComparison(Sema &S, BinaryOperator *E) { @@ -9200,7 +10289,7 @@ static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, +static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, SourceLocation CContext, unsigned diag, bool pruneControlFlow = false) { if (pruneControlFlow) { @@ -9221,6 +10310,32 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } +/// Analyze the given compound assignment for the possible losing of +/// floating-point precision. +static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) { + assert(isa<CompoundAssignOperator>(E) && + "Must be compound assignment operation"); + // Recurse on the LHS and RHS in here + AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); + AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); + + // Now check the outermost expression + const auto *ResultBT = E->getLHS()->getType()->getAs<BuiltinType>(); + const auto *RBT = cast<CompoundAssignOperator>(E) + ->getComputationResultType() + ->getAs<BuiltinType>(); + + // If both source and target are floating points. + if (ResultBT && ResultBT->isFloatingPoint() && RBT && RBT->isFloatingPoint()) + // Builtin FP kinds are ordered by increasing FP rank. + if (ResultBT->getKind() < RBT->getKind()) + // We don't want to warn for system macro. + if (!S.SourceMgr.isInSystemMacro(E->getOperatorLoc())) + // warn about dropping FP rank. + DiagnoseImpCast(S, E->getRHS(), E->getLHS()->getType(), + E->getOperatorLoc(), + diag::warn_impcast_float_result_precision); +} /// Diagnose an implicit cast from a floating point value to an integer value. static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, @@ -9249,14 +10364,24 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, llvm::APSInt IntegerValue(S.Context.getIntWidth(T), T->hasUnsignedIntegerRepresentation()); - if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, - &isExact) == llvm::APFloat::opOK && - isExact) { + llvm::APFloat::opStatus Result = Value.convertToInteger( + IntegerValue, llvm::APFloat::rmTowardZero, &isExact); + + if (Result == llvm::APFloat::opOK && isExact) { if (IsLiteral) return; return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } + // Conversion of a floating-point value to a non-bool integer where the + // integral part cannot be represented by the integer type is undefined. + if (!IsBool && Result == llvm::APFloat::opInvalidOp) + return DiagnoseImpCast( + S, E, T, CContext, + IsLiteral ? diag::warn_impcast_literal_float_to_integer_out_of_range + : diag::warn_impcast_float_to_integer_out_of_range, + PruneWarnings); + unsigned DiagID = 0; if (IsLiteral) { // Warn on floating point literal to integer. @@ -9390,18 +10515,15 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, // Venture through the macro stacks to get to the source of macro arguments. // The new location is a better location than the complete location that was // passed in. - while (S.SourceMgr.isMacroArgExpansion(Loc)) - Loc = S.SourceMgr.getImmediateMacroCallerLoc(Loc); - - while (S.SourceMgr.isMacroArgExpansion(CC)) - CC = S.SourceMgr.getImmediateMacroCallerLoc(CC); + Loc = S.SourceMgr.getTopMacroCallerLoc(Loc); + CC = S.SourceMgr.getTopMacroCallerLoc(CC); // __null is usually wrapped in a macro. Go up a macro if that is the case. if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) { StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( Loc, S.SourceMgr, S.getLangOpts()); if (MacroName == "NULL") - Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; + Loc = S.SourceMgr.getImmediateExpansionRange(Loc).getBegin(); } // Only warn if the null and context location are in the same macro expansion. @@ -9591,7 +10713,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, return; return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); } - + // If the vector cast is cast between two vectors of the same size, it is // a bitcast, not a conversion. if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) @@ -9772,7 +10894,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, // We also want to warn about it in -Wconversion. // So if -Wconversion is off, use a completely identical diagnostic // in the sign-compare group. - // The conditional-checking code will + // The conditional-checking code will if (ICContext) { DiagID = diag::warn_impcast_integer_sign_conditional; *ICContext = true; @@ -9793,7 +10915,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, Source = S.Context.getCanonicalType(SourceType).getTypePtr(); } } - + if (const EnumType *SourceEnum = Source->getAs<EnumType>()) if (const EnumType *TargetEnum = Target->getAs<EnumType>()) if (SourceEnum->getDecl()->hasNameForLinkage() && @@ -9802,7 +10924,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, if (S.SourceMgr.isInSystemMacro(CC)) return; - return DiagnoseImpCast(S, E, SourceType, T, CC, + return DiagnoseImpCast(S, E, SourceType, T, CC, diag::warn_impcast_different_enum_types); } } @@ -9841,7 +10963,7 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, // ...then check whether it would have warned about either of the // candidates for a signedness conversion to the condition type. if (E->getType() == T) return; - + Suspicious = false; CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), E->getType(), CC, &Suspicious); @@ -9868,7 +10990,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, if (E->isTypeDependent() || E->isValueDependent()) return; - + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (isa<ConditionalOperator>(E)) { @@ -9912,6 +11034,9 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, // And with simple assignments. if (BO->getOpcode() == BO_Assign) return AnalyzeAssignment(S, BO); + // And with compound assignments. + if (BO->isAssignmentOp()) + return AnalyzeCompoundAssignment(S, BO); } // These break the otherwise-useful invariant below. Fortunately, @@ -9955,7 +11080,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, ::CheckBoolLikeConversion(S, U->getSubExpr(), CC); } -/// Diagnose integer type and any valid implicit convertion to it. +/// Diagnose integer type and any valid implicit conversion to it. static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { // Taking into account implicit conversions, // allow any integer. @@ -10018,7 +11143,7 @@ static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) { return false; } -/// \brief Diagnose pointers that are always non-null. +/// Diagnose pointers that are always non-null. /// \param E the expression containing the pointer /// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is /// compared to a null pointer @@ -10122,8 +11247,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, return; } - for (unsigned ArgNo : NonNull->args()) { - if (ArgNo == ParamNo) { + for (const ParamIdx &ArgNo : NonNull->args()) { + if (ArgNo.getASTIndex() == ParamNo) { ComplainAboutNonnullParamOrCall(NonNull); return; } @@ -10244,29 +11369,33 @@ void Sema::CheckForIntOverflow (Expr *E) { SmallVector<Expr *, 2> Exprs(1, E); do { - Expr *E = Exprs.pop_back_val(); + Expr *OriginalE = Exprs.pop_back_val(); + Expr *E = OriginalE->IgnoreParenCasts(); - if (isa<BinaryOperator>(E->IgnoreParenCasts())) { - E->IgnoreParenCasts()->EvaluateForOverflow(Context); + if (isa<BinaryOperator>(E)) { + E->EvaluateForOverflow(Context); continue; } - if (auto InitList = dyn_cast<InitListExpr>(E)) + if (auto InitList = dyn_cast<InitListExpr>(OriginalE)) Exprs.append(InitList->inits().begin(), InitList->inits().end()); - - if (isa<ObjCBoxedExpr>(E)) - E->IgnoreParenCasts()->EvaluateForOverflow(Context); + else if (isa<ObjCBoxedExpr>(OriginalE)) + E->EvaluateForOverflow(Context); + else if (auto Call = dyn_cast<CallExpr>(E)) + Exprs.append(Call->arg_begin(), Call->arg_end()); + else if (auto Message = dyn_cast<ObjCMessageExpr>(E)) + Exprs.append(Message->arg_begin(), Message->arg_end()); } while (!Exprs.empty()); } namespace { -/// \brief Visitor for expressions which looks for unsequenced operations on the +/// Visitor for expressions which looks for unsequenced operations on the /// same object. class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { using Base = EvaluatedExprVisitor<SequenceChecker>; - /// \brief A tree of sequenced regions within an expression. Two regions are + /// A tree of sequenced regions within an expression. Two regions are /// unsequenced if one is an ancestor or a descendent of the other. When we /// finish processing an expression with sequencing, such as a comma /// expression, we fold its tree nodes into its parent, since they are @@ -10280,7 +11409,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { SmallVector<Value, 8> Values; public: - /// \brief A region within an expression which may be sequenced with respect + /// A region within an expression which may be sequenced with respect /// to some other region. class Seq { friend class SequenceTree; @@ -10296,7 +11425,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { SequenceTree() { Values.push_back(Value(0)); } Seq root() const { return Seq(0); } - /// \brief Create a new sequence of operations, which is an unsequenced + /// Create a new sequence of operations, which is an unsequenced /// subset of \p Parent. This sequence of operations is sequenced with /// respect to other children of \p Parent. Seq allocate(Seq Parent) { @@ -10304,12 +11433,12 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { return Seq(Values.size() - 1); } - /// \brief Merge a sequence of operations into its parent. + /// Merge a sequence of operations into its parent. void merge(Seq S) { Values[S.Index].Merged = true; } - /// \brief Determine whether two operations are unsequenced. This operation + /// Determine whether two operations are unsequenced. This operation /// is asymmetric: \p Cur should be the more recent sequence, and \p Old /// should have been merged into its parent as appropriate. bool isUnsequenced(Seq Cur, Seq Old) { @@ -10324,7 +11453,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { } private: - /// \brief Pick a representative for a sequence. + /// Pick a representative for a sequence. unsigned representative(unsigned K) { if (Values[K].Merged) // Perform path compression as we go. @@ -10445,7 +11574,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { bool EvalOK = true; } *EvalTracker = nullptr; - /// \brief Find the object which is produced by the specified expression, + /// Find the object which is produced by the specified expression, /// if any. Object getObject(Expr *E, bool Mod) const { E = E->IgnoreParenCasts(); @@ -10467,7 +11596,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { return nullptr; } - /// \brief Note that an object was modified or used by an expression. + /// Note that an object was modified or used by an expression. void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) { Usage &U = UI.Uses[UK]; if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) { @@ -10478,7 +11607,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { } } - /// \brief Check whether a modification or use conflicts with a prior usage. + /// Check whether a modification or use conflicts with a prior usage. void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind, bool IsModMod) { if (UI.Diagnosed) @@ -10857,23 +11986,18 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, // information is added for it. diagnoseArrayStarInParamType(*this, PType, Param->getLocation()); - // MSVC destroys objects passed by value in the callee. Therefore a - // function definition which takes such a parameter must be able to call the - // object's destructor. However, we don't perform any direct access check - // on the dtor. - if (getLangOpts().CPlusPlus && Context.getTargetInfo() - .getCXXABI() - .areArgsDestroyedLeftToRightInCallee()) { - if (!Param->isInvalidDecl()) { - if (const RecordType *RT = Param->getType()->getAs<RecordType>()) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (!ClassDecl->isInvalidDecl() && - !ClassDecl->hasIrrelevantDestructor() && - !ClassDecl->isDependentContext()) { - CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); - MarkFunctionReferenced(Param->getLocation(), Destructor); - DiagnoseUseOfDecl(Destructor, Param->getLocation()); - } + // If the parameter is a c++ class type and it has to be destructed in the + // callee function, declare the destructor so that it can be called by the + // callee function. Do not perform any direct access check on the dtor here. + if (!Param->isInvalidDecl()) { + if (CXXRecordDecl *ClassDecl = Param->getType()->getAsCXXRecordDecl()) { + if (!ClassDecl->isInvalidDecl() && + !ClassDecl->hasIrrelevantDestructor() && + !ClassDecl->isDependentContext() && + ClassDecl->isParamDestroyedInCallee()) { + CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); + MarkFunctionReferenced(Param->getLocation(), Destructor); + DiagnoseUseOfDecl(Destructor, Param->getLocation()); } } } @@ -10956,7 +12080,7 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } -/// \brief Check whether this array fits the idiom of a size-one tail padded +/// Check whether this array fits the idiom of a size-one tail padded /// array member of a struct. /// /// We avoid emitting out-of-bounds access warnings for such arrays as they are @@ -11026,9 +12150,9 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const NamedDecl *ND = nullptr; if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(DRE->getDecl()); + ND = DRE->getDecl(); if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); + ND = ME->getMemberDecl(); if (index.isUnsigned() || !index.isNegative()) { llvm::APInt size = ArrayTy->getSize(); @@ -11111,9 +12235,9 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, dyn_cast<ArraySubscriptExpr>(BaseExpr)) BaseExpr = ASE->getBase()->IgnoreParenCasts(); if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(DRE->getDecl()); + ND = DRE->getDecl(); if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); + ND = ME->getMemberDecl(); } if (ND) @@ -11131,7 +12255,12 @@ void Sema::CheckArrayAccess(const Expr *expr) { const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr); CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE, AllowOnePastEnd > 0); - return; + expr = ASE->getBase(); + break; + } + case Stmt::MemberExprClass: { + expr = cast<MemberExpr>(expr)->getBase(); + break; } case Stmt::OMPArraySectionExprClass: { const OMPArraySectionExpr *ASE = cast<OMPArraySectionExpr>(expr); @@ -11315,11 +12444,11 @@ namespace { } void VisitBlockExpr(BlockExpr *block) { - // Look inside nested blocks + // Look inside nested blocks if (block->getBlockDecl()->capturesVariable(Variable)) Visit(block->getBlockDecl()->getBody()); } - + void VisitOpaqueValueExpr(OpaqueValueExpr *OVE) { if (Capturer) return; if (OVE->getSourceExpr()) @@ -11372,7 +12501,7 @@ static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) { } } } - + BlockExpr *block = dyn_cast<BlockExpr>(e); if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable)) return nullptr; @@ -11541,7 +12670,7 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { if (ArgRE->isObjCSelfExpr()) { Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << ArgRE->getDecl()->getName() << StringRef("super"); + << ArgRE->getDecl() << StringRef("'super'"); } } } else { @@ -11557,11 +12686,11 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { ValueDecl *Decl = ReceiverRE->getDecl(); Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << Decl->getName() << Decl->getName(); + << Decl << Decl; if (!ArgRE->isObjCSelfExpr()) { Diag(Decl->getLocation(), diag::note_objc_circular_container_declared_here) - << Decl->getName(); + << Decl; } } } @@ -11571,10 +12700,10 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { ObjCIvarDecl *Decl = IvarRE->getDecl(); Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << Decl->getName() << Decl->getName(); + << Decl << Decl; Diag(Decl->getLocation(), diag::note_objc_circular_container_declared_here) - << Decl->getName(); + << Decl; } } } @@ -11625,12 +12754,12 @@ void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) { RetainCycleOwner Owner; if (!considerVariable(Var, /*DeclRefExpr=*/nullptr, Owner)) return; - + // Because we don't have an expression for the variable, we have to set the // location explicitly here. Owner.Loc = Var->getLocation(); Owner.Range = Var->getSourceRange(); - + if (Expr *Capturer = findCapturingExpr(*this, Init, Owner)) diagnoseRetainCycle(*this, Capturer, Owner); } @@ -11703,7 +12832,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, if (PD) LHSType = PD->getType(); } - + if (LHSType.isNull()) LHSType = LHS->getType(); @@ -11720,14 +12849,14 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, // FIXME. Check for other life times. if (LT != Qualifiers::OCL_None) return; - + if (PRE) { if (PRE->isImplicitProperty()) return; const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); if (!PD) return; - + unsigned Attributes = PD->getPropertyAttributes(); if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) { // when 'assign' attribute was not explicitly specified @@ -11737,7 +12866,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, if (!(AsWrittenAttr & ObjCPropertyDecl::OBJC_PR_assign) && LHSType->isObjCRetainableType()) return; - + while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { if (cast->getCastKind() == CK_ARCConsumeObject) { Diag(Loc, diag::warn_arc_retained_property_assign) @@ -11967,7 +13096,7 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2); -/// \brief Check if two enumeration types are layout-compatible. +/// Check if two enumeration types are layout-compatible. static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { // C++11 [dcl.enum] p8: // Two enumeration types are layout-compatible if they have the same @@ -11976,7 +13105,7 @@ static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType()); } -/// \brief Check if two fields are layout-compatible. +/// Check if two fields are layout-compatible. static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) { if (!isLayoutCompatible(C, Field1->getType(), Field2->getType())) @@ -11997,7 +13126,7 @@ static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, return true; } -/// \brief Check if two standard-layout structs are layout-compatible. +/// Check if two standard-layout structs are layout-compatible. /// (C++11 [class.mem] p17) static bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { @@ -12041,7 +13170,7 @@ static bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1, return true; } -/// \brief Check if two standard-layout unions are layout-compatible. +/// Check if two standard-layout unions are layout-compatible. /// (C++11 [class.mem] p18) static bool isLayoutCompatibleUnion(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { @@ -12080,7 +13209,7 @@ static bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, return isLayoutCompatibleStruct(C, RD1, RD2); } -/// \brief Check if two types are layout-compatible in C++11 sense. +/// Check if two types are layout-compatible in C++11 sense. static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { if (T1.isNull() || T2.isNull()) return false; @@ -12118,7 +13247,7 @@ static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// -/// \brief Given a type tag expression find the type tag itself. +/// Given a type tag expression find the type tag itself. /// /// \param TypeExpr Type tag expression, as it appears in user's code. /// @@ -12189,7 +13318,7 @@ static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, } } -/// \brief Retrieve the C type corresponding to type tag TypeExpr. +/// Retrieve the C type corresponding to type tag TypeExpr. /// /// \param TypeExpr Expression that specifies a type tag. /// @@ -12283,13 +13412,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, bool IsPointerAttr = Attr->getIsPointer(); // Retrieve the argument representing the 'type_tag'. - if (Attr->getTypeTagIdx() >= ExprArgs.size()) { - // Add 1 to display the user's specified value. + unsigned TypeTagIdxAST = Attr->getTypeTagIdx().getASTIndex(); + if (TypeTagIdxAST >= ExprArgs.size()) { Diag(CallSiteLoc, diag::err_tag_index_out_of_range) - << 0 << Attr->getTypeTagIdx() + 1; + << 0 << Attr->getTypeTagIdx().getSourceIndex(); return; } - const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()]; + const Expr *TypeTagExpr = ExprArgs[TypeTagIdxAST]; bool FoundWrongKind; TypeTagData TypeInfo; if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context, @@ -12303,13 +13432,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, } // Retrieve the argument representing the 'arg_idx'. - if (Attr->getArgumentIdx() >= ExprArgs.size()) { - // Add 1 to display the user's specified value. + unsigned ArgumentIdxAST = Attr->getArgumentIdx().getASTIndex(); + if (ArgumentIdxAST >= ExprArgs.size()) { Diag(CallSiteLoc, diag::err_tag_index_out_of_range) - << 1 << Attr->getArgumentIdx() + 1; + << 1 << Attr->getArgumentIdx().getSourceIndex(); return; } - const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()]; + const Expr *ArgumentExpr = ExprArgs[ArgumentIdxAST]; if (IsPointerAttr) { // Skip implicit cast of pointer to `void *' (as a function argument). if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr)) diff --git a/gnu/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/gnu/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index aecc98e297e..501797b087a 100644 --- a/gnu/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/gnu/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -58,7 +59,7 @@ static bool isFunctionOrMethod(const Decl *D) { return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D); } -/// \brief Return true if the given decl has function type (function or +/// Return true if the given decl has function type (function or /// function-typed variable) or an Objective-C method or a block. static bool isFunctionOrMethodOrBlock(const Decl *D) { return isFunctionOrMethod(D) || isa<BlockDecl>(D); @@ -87,7 +88,7 @@ static bool hasFunctionProto(const Decl *D) { static unsigned getFunctionOrMethodNumParams(const Decl *D) { if (const FunctionType *FnTy = D->getFunctionType()) return cast<FunctionProtoType>(FnTy)->getNumParams(); - if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + if (const auto *BD = dyn_cast<BlockDecl>(D)) return BD->getNumParams(); return cast<ObjCMethodDecl>(D)->param_size(); } @@ -95,7 +96,7 @@ static unsigned getFunctionOrMethodNumParams(const Decl *D) { static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { if (const FunctionType *FnTy = D->getFunctionType()) return cast<FunctionProtoType>(FnTy)->getParamType(Idx); - if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + if (const auto *BD = dyn_cast<BlockDecl>(D)) return BD->getParamDecl(Idx)->getType(); return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType(); @@ -113,7 +114,7 @@ static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) { static QualType getFunctionOrMethodResultType(const Decl *D) { if (const FunctionType *FnTy = D->getFunctionType()) - return cast<FunctionType>(FnTy)->getReturnType(); + return FnTy->getReturnType(); return cast<ObjCMethodDecl>(D)->getReturnType(); } @@ -126,24 +127,21 @@ static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { } static bool isFunctionOrMethodVariadic(const Decl *D) { - if (const FunctionType *FnTy = D->getFunctionType()) { - const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); - return proto->isVariadic(); - } - if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + if (const FunctionType *FnTy = D->getFunctionType()) + return cast<FunctionProtoType>(FnTy)->isVariadic(); + if (const auto *BD = dyn_cast<BlockDecl>(D)) return BD->isVariadic(); - return cast<ObjCMethodDecl>(D)->isVariadic(); } static bool isInstanceMethod(const Decl *D) { - if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) + if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D)) return MethodDecl->isInstance(); return false; } static inline bool isNSStringType(QualType T, ASTContext &Ctx) { - const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); + const auto *PT = T->getAs<ObjCObjectPointerType>(); if (!PT) return false; @@ -159,11 +157,11 @@ static inline bool isNSStringType(QualType T, ASTContext &Ctx) { } static inline bool isCFStringType(QualType T, ASTContext &Ctx) { - const PointerType *PT = T->getAs<PointerType>(); + const auto *PT = T->getAs<PointerType>(); if (!PT) return false; - const RecordType *RT = PT->getPointeeType()->getAs<RecordType>(); + const auto *RT = PT->getPointeeType()->getAs<RecordType>(); if (!RT) return false; @@ -174,89 +172,86 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); } -static unsigned getNumAttributeArgs(const AttributeList &Attr) { +static unsigned getNumAttributeArgs(const ParsedAttr &AL) { // FIXME: Include the type in the argument list. - return Attr.getNumArgs() + Attr.hasParsedType(); + return AL.getNumArgs() + AL.hasParsedType(); } template <typename Compare> -static bool checkAttributeNumArgsImpl(Sema &S, const AttributeList &Attr, +static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, unsigned Num, unsigned Diag, Compare Comp) { - if (Comp(getNumAttributeArgs(Attr), Num)) { - S.Diag(Attr.getLoc(), Diag) << Attr.getName() << Num; + if (Comp(getNumAttributeArgs(AL), Num)) { + S.Diag(AL.getLoc(), Diag) << AL.getName() << Num; return false; } return true; } -/// \brief Check if the attribute has exactly as many args as Num. May +/// Check if the attribute has exactly as many args as Num. May /// output an error. -static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, - unsigned Num) { - return checkAttributeNumArgsImpl(S, Attr, Num, +static bool checkAttributeNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) { + return checkAttributeNumArgsImpl(S, AL, Num, diag::err_attribute_wrong_number_arguments, std::not_equal_to<unsigned>()); } -/// \brief Check if the attribute has at least as many args as Num. May +/// Check if the attribute has at least as many args as Num. May /// output an error. -static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr, +static bool checkAttributeAtLeastNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) { - return checkAttributeNumArgsImpl(S, Attr, Num, + return checkAttributeNumArgsImpl(S, AL, Num, diag::err_attribute_too_few_arguments, std::less<unsigned>()); } -/// \brief Check if the attribute has at most as many args as Num. May +/// Check if the attribute has at most as many args as Num. May /// output an error. -static bool checkAttributeAtMostNumArgs(Sema &S, const AttributeList &Attr, - unsigned Num) { - return checkAttributeNumArgsImpl(S, Attr, Num, +static bool checkAttributeAtMostNumArgs(Sema &S, const ParsedAttr &AL, + unsigned Num) { + return checkAttributeNumArgsImpl(S, AL, Num, diag::err_attribute_too_many_arguments, std::greater<unsigned>()); } -/// \brief A helper function to provide Attribute Location for the Attr types -/// AND the AttributeList. +/// A helper function to provide Attribute Location for the Attr types +/// AND the ParsedAttr. template <typename AttrInfo> -static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, +static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value, SourceLocation>::type -getAttrLoc(const AttrInfo &Attr) { - return Attr.getLocation(); -} -static SourceLocation getAttrLoc(const clang::AttributeList &Attr) { - return Attr.getLoc(); +getAttrLoc(const AttrInfo &AL) { + return AL.getLocation(); } +static SourceLocation getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); } -/// \brief A helper function to provide Attribute Name for the Attr types -/// AND the AttributeList. +/// A helper function to provide Attribute Name for the Attr types +/// AND the ParsedAttr. template <typename AttrInfo> -static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, +static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value, const AttrInfo *>::type -getAttrName(const AttrInfo &Attr) { - return &Attr; +getAttrName(const AttrInfo &AL) { + return &AL; } -static const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) { - return Attr.getName(); +static const IdentifierInfo *getAttrName(const ParsedAttr &AL) { + return AL.getName(); } -/// \brief If Expr is a valid integer constant, get the value of the integer +/// If Expr is a valid integer constant, get the value of the integer /// expression and return success or failure. May output an error. -template<typename AttrInfo> -static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr, +template <typename AttrInfo> +static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, uint32_t &Val, unsigned Idx = UINT_MAX) { llvm::APSInt I(32); if (Expr->isTypeDependent() || Expr->isValueDependent() || !Expr->isIntegerConstantExpr(I, S.Context)) { if (Idx != UINT_MAX) - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type) - << getAttrName(Attr) << Idx << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) + << getAttrName(AI) << Idx << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); else - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_type) - << getAttrName(Attr) << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) + << getAttrName(AI) << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); return false; } @@ -271,14 +266,14 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr, return true; } -/// \brief Wrapper around checkUInt32Argument, with an extra check to be sure +/// Wrapper around checkUInt32Argument, with an extra check to be sure /// that the result will fit into a regular (signed) int. All args have the same /// purpose as they do in checkUInt32Argument. -template<typename AttrInfo> -static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr *Expr, +template <typename AttrInfo> +static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Expr, int &Val, unsigned Idx = UINT_MAX) { uint32_t UVal; - if (!checkUInt32Argument(S, Attr, Expr, UVal, Idx)) + if (!checkUInt32Argument(S, AI, Expr, UVal, Idx)) return false; if (UVal > (uint32_t)std::numeric_limits<int>::max()) { @@ -293,12 +288,12 @@ static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr * return true; } -/// \brief Diagnose mutually exclusive attributes when present on a given +/// Diagnose mutually exclusive attributes when present on a given /// declaration. Returns true if diagnosed. template <typename AttrTy> static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, IdentifierInfo *Ident) { - if (AttrTy *A = D->getAttr<AttrTy>()) { + if (const auto *A = D->getAttr<AttrTy>()) { S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) << Ident << A; S.Diag(A->getLocation(), diag::note_conflicting_attribute); @@ -307,14 +302,14 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, return false; } -/// \brief Check if IdxExpr is a valid parameter index for a function or +/// Check if IdxExpr is a valid parameter index for a function or /// instance method D. May output an error. /// /// \returns true if IdxExpr is a valid index. template <typename AttrInfo> static bool checkFunctionOrMethodParameterIndex( - Sema &S, const Decl *D, const AttrInfo &Attr, unsigned AttrArgNum, - const Expr *IdxExpr, uint64_t &Idx, bool AllowImplicitThis = false) { + Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum, + const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) { assert(isFunctionOrMethodOrBlock(D)); // In C++ the implicit 'this' function parameter also counts. @@ -328,44 +323,43 @@ static bool checkFunctionOrMethodParameterIndex( llvm::APSInt IdxInt; if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) { - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type) - << getAttrName(Attr) << AttrArgNum << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) + << getAttrName(AI) << AttrArgNum << AANT_ArgumentIntegerConstant << IdxExpr->getSourceRange(); return false; } - Idx = IdxInt.getLimitedValue(); - if (Idx < 1 || (!IV && Idx > NumParams)) { - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_out_of_bounds) - << getAttrName(Attr) << AttrArgNum << IdxExpr->getSourceRange(); + unsigned IdxSource = IdxInt.getLimitedValue(UINT_MAX); + if (IdxSource < 1 || (!IV && IdxSource > NumParams)) { + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) + << getAttrName(AI) << AttrArgNum << IdxExpr->getSourceRange(); return false; } - Idx--; // Convert to zero-based. - if (HasImplicitThisParam && !AllowImplicitThis) { - if (Idx == 0) { - S.Diag(getAttrLoc(Attr), + if (HasImplicitThisParam && !CanIndexImplicitThis) { + if (IdxSource == 1) { + S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument) - << getAttrName(Attr) << IdxExpr->getSourceRange(); + << getAttrName(AI) << IdxExpr->getSourceRange(); return false; } - --Idx; } + Idx = ParamIdx(IdxSource, D); return true; } -/// \brief Check if the argument \p ArgNum of \p Attr is a ASCII string literal. +/// Check if the argument \p ArgNum of \p Attr is a ASCII string literal. /// If not emit an error and return false. If the argument is an identifier it /// will emit an error with a fixit hint and treat it as if it was a string /// literal. -bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, - unsigned ArgNum, StringRef &Str, +bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, + StringRef &Str, SourceLocation *ArgLocation) { // Look for identifiers. If we have one emit a hint to fix it to a literal. - if (Attr.isArgIdent(ArgNum)) { - IdentifierLoc *Loc = Attr.getArgAsIdent(ArgNum); + if (AL.isArgIdent(ArgNum)) { + IdentifierLoc *Loc = AL.getArgAsIdent(ArgNum); Diag(Loc->Loc, diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentString + << AL.getName() << AANT_ArgumentString << FixItHint::CreateInsertion(Loc->Loc, "\"") << FixItHint::CreateInsertion(getLocForEndOfToken(Loc->Loc), "\""); Str = Loc->Ident->getName(); @@ -375,14 +369,14 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, } // Now check for an actual string literal. - Expr *ArgExpr = Attr.getArgAsExpr(ArgNum); - StringLiteral *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts()); + Expr *ArgExpr = AL.getArgAsExpr(ArgNum); + const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts()); if (ArgLocation) *ArgLocation = ArgExpr->getLocStart(); if (!Literal || !Literal->isAscii()) { Diag(ArgExpr->getLocStart(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentString; + << AL.getName() << AANT_ArgumentString; return false; } @@ -390,35 +384,34 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, return true; } -/// \brief Applies the given attribute to the Decl without performing any +/// Applies the given attribute to the Decl without performing any /// additional semantic checking. template <typename AttrType> -static void handleSimpleAttribute(Sema &S, Decl *D, - const AttributeList &Attr) { - D->addAttr(::new (S.Context) AttrType(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); +static void handleSimpleAttribute(Sema &S, Decl *D, const ParsedAttr &AL) { + D->addAttr(::new (S.Context) AttrType(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } template <typename AttrType> static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D, - const AttributeList &Attr) { - handleSimpleAttribute<AttrType>(S, D, Attr); + const ParsedAttr &AL) { + handleSimpleAttribute<AttrType>(S, D, AL); } -/// \brief Applies the given attribute to the Decl so long as the Decl doesn't +/// Applies the given attribute to the Decl so long as the Decl doesn't /// already have one of the given incompatible attributes. template <typename AttrType, typename IncompatibleAttrType, typename... IncompatibleAttrTypes> static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, Attr.getRange(), - Attr.getName())) + const ParsedAttr &AL) { + if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL.getRange(), + AL.getName())) return; handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, - Attr); + AL); } -/// \brief Check if the passed-in expression is of type int or bool. +/// Check if the passed-in expression is of type int or bool. static bool isIntOrBool(Expr *Exp) { QualType QT = Exp->getType(); return QT->isBooleanType() || QT->isIntegerType(); @@ -441,17 +434,17 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { return true; } -/// \brief Check if passed in Decl is a pointer type. +/// Check if passed in Decl is a pointer type. /// Note that this function may produce an error message. /// \return true if the Decl is a pointer type; false otherwise static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, - const AttributeList &Attr) { - const ValueDecl *vd = cast<ValueDecl>(D); - QualType QT = vd->getType(); + const ParsedAttr &AL) { + const auto *VD = cast<ValueDecl>(D); + QualType QT = VD->getType(); if (QT->isAnyPointerType()) return true; - if (const RecordType *RT = QT->getAs<RecordType>()) { + if (const auto *RT = QT->getAs<RecordType>()) { // If it's an incomplete type, it could be a smart pointer; skip it. // (We don't want to force template instantiation if we can avoid it, // since that would alter the order in which templates are instantiated.) @@ -462,19 +455,19 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, return true; } - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer) - << Attr.getName() << QT; + S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_pointer) + << AL.getName() << QT; return false; } -/// \brief Checks that the passed in QualType either is of RecordType or points +/// Checks that the passed in QualType either is of RecordType or points /// to RecordType. Returns the relevant RecordType, null if it does not exit. static const RecordType *getRecordType(QualType QT) { - if (const RecordType *RT = QT->getAs<RecordType>()) + if (const auto *RT = QT->getAs<RecordType>()) return RT; // Now check if we point to record type. - if (const PointerType *PT = QT->getAs<PointerType>()) + if (const auto *PT = QT->getAs<PointerType>()) return PT->getPointeeType()->getAs<RecordType>(); return nullptr; @@ -501,7 +494,7 @@ static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { return true; // Else check if any base classes have a capability. - if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { + if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { CXXBasePaths BPaths(false, false); if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &) { const auto *Type = BS->getType()->getAs<RecordType>(); @@ -559,18 +552,18 @@ static bool isCapabilityExpr(Sema &S, const Expr *Ex) { return typeHasCapability(S, Ex->getType()); } -/// \brief Checks that all attribute arguments, starting from Sidx, resolve to +/// Checks that all attribute arguments, starting from Sidx, resolve to /// a capability object. /// \param Sidx The attribute argument index to start checking with. /// \param ParamIdxOk Whether an argument can be indexing into a function /// parameter list. static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, - const AttributeList &Attr, + const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args, int Sidx = 0, bool ParamIdxOk = false) { - for (unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) { - Expr *ArgExp = Attr.getArgAsExpr(Idx); + for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx) { + Expr *ArgExp = AL.getArgAsExpr(Idx); if (ArgExp->isTypeDependent()) { // FIXME -- need to check this again on template instantiation @@ -578,7 +571,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, continue; } - if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) { + if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) { if (StrLit->getLength() == 0 || (StrLit->isAscii() && StrLit->getString() == StringRef("*"))) { // Pass empty strings to the analyzer without warnings. @@ -589,8 +582,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // We allow constant strings to be used as a placeholder for expressions // that are not valid C++ syntax, but warn that they are ignored. - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) << - Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL.getName(); Args.push_back(ArgExp); continue; } @@ -599,9 +591,9 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // A pointer to member expression of the form &MyClass::mu is treated // specially -- we need to look at the type of the member. - if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(ArgExp)) + if (const auto *UOp = dyn_cast<UnaryOperator>(ArgExp)) if (UOp->getOpcode() == UO_AddrOf) - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr())) + if (const auto *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr())) if (DRE->getDecl()->isCXXInstanceMember()) ArgTy = DRE->getDecl()->getType(); @@ -610,16 +602,16 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // Now check if we index into a record type function param. if(!RT && ParamIdxOk) { - FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArgExp); + const auto *FD = dyn_cast<FunctionDecl>(D); + const auto *IL = dyn_cast<IntegerLiteral>(ArgExp); if(FD && IL) { unsigned int NumParams = FD->getNumParams(); llvm::APInt ArgValue = IL->getValue(); uint64_t ParamIdxFromOne = ArgValue.getZExtValue(); uint64_t ParamIdxFromZero = ParamIdxFromOne - 1; - if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range) - << Attr.getName() << Idx + 1 << NumParams; + if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) + << AL.getName() << Idx + 1 << NumParams; continue; } ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType(); @@ -631,8 +623,8 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // capability may be on the type, and the expression is a capability // boolean logic expression. Eg) requires_capability(A || B && !C) if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp)) - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) - << Attr.getName() << ArgTy; + S.Diag(AL.getLoc(), diag::warn_thread_attribute_argument_not_lockable) + << AL.getName() << ArgTy; Args.push_back(ArgExp); } @@ -642,22 +634,20 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // Attribute Implementations //===----------------------------------------------------------------------===// -static void handlePtGuardedVarAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!threadSafetyCheckIsPointer(S, D, Attr)) +static void handlePtGuardedVarAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!threadSafetyCheckIsPointer(S, D, AL)) return; D->addAttr(::new (S.Context) - PtGuardedVarAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + PtGuardedVarAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static bool checkGuardedByAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, - Expr* &Arg) { - SmallVector<Expr*, 1> Args; +static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, + Expr *&Arg) { + SmallVector<Expr *, 1> Args; // check that all arguments are lockable objects - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size != 1) return false; @@ -667,273 +657,239 @@ static bool checkGuardedByAttrCommon(Sema &S, Decl *D, return true; } -static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *Arg = nullptr; - if (!checkGuardedByAttrCommon(S, D, Attr, Arg)) + if (!checkGuardedByAttrCommon(S, D, AL, Arg)) return; - D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) GuardedByAttr( + AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex())); } -static void handlePtGuardedByAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *Arg = nullptr; - if (!checkGuardedByAttrCommon(S, D, Attr, Arg)) + if (!checkGuardedByAttrCommon(S, D, AL, Arg)) return; - if (!threadSafetyCheckIsPointer(S, D, Attr)) + if (!threadSafetyCheckIsPointer(S, D, AL)) return; - D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(), - S.Context, Arg, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PtGuardedByAttr( + AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex())); } -static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return false; // Check that this attribute only applies to lockable types. QualType QT = cast<ValueDecl>(D)->getType(); if (!QT->isDependentType() && !typeHasCapability(S, QT)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_lockable) + << AL.getName(); return false; } // Check that all arguments are lockable objects. - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); if (Args.empty()) return false; return true; } -static void handleAcquiredAfterAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkAcquireOrderAttrCommon(S, D, Attr, Args)) +static void handleAcquiredAfterAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkAcquireOrderAttrCommon(S, D, AL, Args)) return; Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) - AcquiredAfterAttr(Attr.getRange(), S.Context, - StartArg, Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AcquiredAfterAttr( + AL.getRange(), S.Context, StartArg, Args.size(), + AL.getAttributeSpellingListIndex())); } -static void handleAcquiredBeforeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkAcquireOrderAttrCommon(S, D, Attr, Args)) +static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkAcquireOrderAttrCommon(S, D, AL, Args)) return; Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) - AcquiredBeforeAttr(Attr.getRange(), S.Context, - StartArg, Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AcquiredBeforeAttr( + AL.getRange(), S.Context, StartArg, Args.size(), + AL.getAttributeSpellingListIndex())); } -static bool checkLockFunAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args) { // zero or more arguments ok // check that all arguments are lockable objects - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, /*ParamIdxOk=*/true); return true; } -static void handleAssertSharedLockAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) +static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; unsigned Size = Args.size(); Expr **StartArg = Size == 0 ? nullptr : &Args[0]; D->addAttr(::new (S.Context) - AssertSharedLockAttr(Attr.getRange(), S.Context, StartArg, Size, - Attr.getAttributeSpellingListIndex())); + AssertSharedLockAttr(AL.getRange(), S.Context, StartArg, Size, + AL.getAttributeSpellingListIndex())); } static void handleAssertExclusiveLockAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) + const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; unsigned Size = Args.size(); Expr **StartArg = Size == 0 ? nullptr : &Args[0]; - D->addAttr(::new (S.Context) - AssertExclusiveLockAttr(Attr.getRange(), S.Context, - StartArg, Size, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AssertExclusiveLockAttr( + AL.getRange(), S.Context, StartArg, Size, + AL.getAttributeSpellingListIndex())); } -/// \brief Checks to be sure that the given parameter number is in bounds, and is -/// an integral type. Will emit appropriate diagnostics if this returns +/// Checks to be sure that the given parameter number is in bounds, and +/// is an integral type. Will emit appropriate diagnostics if this returns /// false. /// -/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used -/// to actually retrieve the argument, so it's base-0. +/// AttrArgNo is used to actually retrieve the argument, so it's base-0. template <typename AttrInfo> static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, - const AttrInfo &Attr, Expr *AttrArg, - unsigned FuncParamNo, unsigned AttrArgNo, - bool AllowDependentType = false) { - uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo, AttrArg, + const AttrInfo &AI, unsigned AttrArgNo) { + assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument"); + Expr *AttrArg = AI.getArgAsExpr(AttrArgNo); + ParamIdx Idx; + if (!checkFunctionOrMethodParameterIndex(S, FD, AI, AttrArgNo + 1, AttrArg, Idx)) return false; - const ParmVarDecl *Param = FD->getParamDecl(Idx); - if (AllowDependentType && Param->getType()->isDependentType()) - return true; + const ParmVarDecl *Param = FD->getParamDecl(Idx.getASTIndex()); if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) { SourceLocation SrcLoc = AttrArg->getLocStart(); S.Diag(SrcLoc, diag::err_attribute_integers_only) - << getAttrName(Attr) << Param->getSourceRange(); + << getAttrName(AI) << Param->getSourceRange(); return false; } return true; } -/// \brief Checks to be sure that the given parameter number is in bounds, and is -/// an integral type. Will emit appropriate diagnostics if this returns false. -/// -/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used -/// to actually retrieve the argument, so it's base-0. -static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, - const AttributeList &Attr, - unsigned FuncParamNo, unsigned AttrArgNo, - bool AllowDependentType = false) { - assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument"); - return checkParamIsIntegerType(S, FD, Attr, Attr.getArgAsExpr(AttrArgNo), - FuncParamNo, AttrArgNo, AllowDependentType); -} - -static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1) || - !checkAttributeAtMostNumArgs(S, Attr, 2)) +static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1) || + !checkAttributeAtMostNumArgs(S, AL, 2)) return; const auto *FD = cast<FunctionDecl>(D); if (!FD->getReturnType()->isPointerType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL.getName(); return; } - const Expr *SizeExpr = Attr.getArgAsExpr(0); - int SizeArgNo; + const Expr *SizeExpr = AL.getArgAsExpr(0); + int SizeArgNoVal; // Parameter indices are 1-indexed, hence Index=1 - if (!checkPositiveIntArgument(S, Attr, SizeExpr, SizeArgNo, /*Index=*/1)) + if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Index=*/1)) return; - - if (!checkParamIsIntegerType(S, FD, Attr, SizeArgNo, /*AttrArgNo=*/0)) + if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0)) return; + ParamIdx SizeArgNo(SizeArgNoVal, D); - // Args are 1-indexed, so 0 implies that the arg was not present - int NumberArgNo = 0; - if (Attr.getNumArgs() == 2) { - const Expr *NumberExpr = Attr.getArgAsExpr(1); + ParamIdx NumberArgNo; + if (AL.getNumArgs() == 2) { + const Expr *NumberExpr = AL.getArgAsExpr(1); + int Val; // Parameter indices are 1-based, hence Index=2 - if (!checkPositiveIntArgument(S, Attr, NumberExpr, NumberArgNo, - /*Index=*/2)) + if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Index=*/2)) return; - - if (!checkParamIsIntegerType(S, FD, Attr, NumberArgNo, /*AttrArgNo=*/1)) + if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1)) return; + NumberArgNo = ParamIdx(Val, D); } - D->addAttr(::new (S.Context) AllocSizeAttr( - Attr.getRange(), S.Context, SizeArgNo, NumberArgNo, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + AllocSizeAttr(AL.getRange(), S.Context, SizeArgNo, NumberArgNo, + AL.getAttributeSpellingListIndex())); } -static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return false; - if (!isIntOrBool(Attr.getArgAsExpr(0))) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIntOrBool; + if (!isIntOrBool(AL.getArgAsExpr(0))) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIntOrBool; return false; } // check that all arguments are lockable objects - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 1); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 1); return true; } static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 2> Args; - if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) - SharedTrylockFunctionAttr(Attr.getRange(), S.Context, - Attr.getArgAsExpr(0), - Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) SharedTrylockFunctionAttr( + AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), Args.size(), + AL.getAttributeSpellingListIndex())); } static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 2> Args; - if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr( - Attr.getRange(), S.Context, Attr.getArgAsExpr(0), Args.data(), - Args.size(), Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), + Args.size(), AL.getAttributeSpellingListIndex())); } -static void handleLockReturnedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check that the argument is lockable object SmallVector<Expr*, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size == 0) return; D->addAttr(::new (S.Context) - LockReturnedAttr(Attr.getRange(), S.Context, Args[0], - Attr.getAttributeSpellingListIndex())); + LockReturnedAttr(AL.getRange(), S.Context, Args[0], + AL.getAttributeSpellingListIndex())); } -static void handleLocksExcludedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; // check that all arguments are lockable objects SmallVector<Expr*, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size == 0) return; Expr **StartArg = &Args[0]; D->addAttr(::new (S.Context) - LocksExcludedAttr(Attr.getRange(), S.Context, StartArg, Size, - Attr.getAttributeSpellingListIndex())); + LocksExcludedAttr(AL.getRange(), S.Context, StartArg, Size, + AL.getAttributeSpellingListIndex())); } -static bool checkFunctionConditionAttr(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL, Expr *&Cond, StringRef &Msg) { - Cond = Attr.getArgAsExpr(0); + Cond = AL.getArgAsExpr(0); if (!Cond->isTypeDependent()) { ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); if (Converted.isInvalid()) @@ -941,7 +897,7 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, Cond = Converted.get(); } - if (!S.checkStringLiteralArgumentAttr(Attr, 1, Msg)) + if (!S.checkStringLiteralArgumentAttr(AL, 1, Msg)) return false; if (Msg.empty()) @@ -951,8 +907,8 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, if (isa<FunctionDecl>(D) && !Cond->isValueDependent() && !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), Diags)) { - S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::err_attr_cond_never_constant_expr) + << AL.getName(); for (const PartialDiagnosticAt &PDiag : Diags) S.Diag(PDiag.first, PDiag.second); return false; @@ -960,15 +916,15 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, return true; } -static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.Diag(Attr.getLoc(), diag::ext_clang_enable_if); +static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.Diag(AL.getLoc(), diag::ext_clang_enable_if); Expr *Cond; StringRef Msg; - if (checkFunctionConditionAttr(S, D, Attr, Cond, Msg)) + if (checkFunctionConditionAttr(S, D, AL, Cond, Msg)) D->addAttr(::new (S.Context) - EnableIfAttr(Attr.getRange(), S.Context, Cond, Msg, - Attr.getAttributeSpellingListIndex())); + EnableIfAttr(AL.getRange(), S.Context, Cond, Msg, + AL.getAttributeSpellingListIndex())); } namespace { @@ -1017,21 +973,21 @@ public: }; } -static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.Diag(Attr.getLoc(), diag::ext_clang_diagnose_if); +static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.Diag(AL.getLoc(), diag::ext_clang_diagnose_if); Expr *Cond; StringRef Msg; - if (!checkFunctionConditionAttr(S, D, Attr, Cond, Msg)) + if (!checkFunctionConditionAttr(S, D, AL, Cond, Msg)) return; StringRef DiagTypeStr; - if (!S.checkStringLiteralArgumentAttr(Attr, 2, DiagTypeStr)) + if (!S.checkStringLiteralArgumentAttr(AL, 2, DiagTypeStr)) return; DiagnoseIfAttr::DiagnosticType DiagType; if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) { - S.Diag(Attr.getArgAsExpr(2)->getLocStart(), + S.Diag(AL.getArgAsExpr(2)->getLocStart(), diag::err_diagnose_if_invalid_diagnostic_type); return; } @@ -1040,21 +996,20 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const auto *FD = dyn_cast<FunctionDecl>(D)) ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); D->addAttr(::new (S.Context) DiagnoseIfAttr( - Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D), - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, + cast<NamedDecl>(D), AL.getAttributeSpellingListIndex())); } -static void handlePassObjectSizeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->hasAttr<PassObjectSizeAttr>()) { S.Diag(D->getLocStart(), diag::err_attribute_only_once_per_parameter) - << Attr.getName(); + << AL.getName(); return; } - Expr *E = Attr.getArgAsExpr(0); + Expr *E = AL.getArgAsExpr(0); uint32_t Type; - if (!checkUInt32Argument(S, Attr, E, Type, /*Idx=*/1)) + if (!checkUInt32Argument(S, AL, E, Type, /*Idx=*/1)) return; // pass_object_size's argument is passed in as the second argument of @@ -1062,7 +1017,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, // argument; namely, it must be in the range [0, 3]. if (Type > 3) { S.Diag(E->getLocStart(), diag::err_attribute_argument_outof_range) - << Attr.getName() << 0 << 3 << E->getSourceRange(); + << AL.getName() << 0 << 3 << E->getSourceRange(); return; } @@ -1072,112 +1027,109 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, // definition, so we defer the constness check until later. if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) { S.Diag(D->getLocStart(), diag::err_attribute_pointers_only) - << Attr.getName() << 1; + << AL.getName() << 1; return; } - D->addAttr(::new (S.Context) - PassObjectSizeAttr(Attr.getRange(), S.Context, (int)Type, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PassObjectSizeAttr( + AL.getRange(), S.Context, (int)Type, AL.getAttributeSpellingListIndex())); } -static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ConsumableAttr::ConsumedState DefaultState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *IL = Attr.getArgAsIdent(0); + if (AL.isArgIdent(0)) { + IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ConsumableAttr::ConvertStrToConsumedState(IL->Ident->getName(), DefaultState)) { S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << IL->Ident; + << AL.getName() << IL->Ident; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentIdentifier; return; } - + D->addAttr(::new (S.Context) - ConsumableAttr(Attr.getRange(), S.Context, DefaultState, - Attr.getAttributeSpellingListIndex())); + ConsumableAttr(AL.getRange(), S.Context, DefaultState, + AL.getAttributeSpellingListIndex())); } static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, - const AttributeList &Attr) { + const ParsedAttr &AL) { ASTContext &CurrContext = S.getASTContext(); QualType ThisType = MD->getThisType(CurrContext)->getPointeeType(); - + if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) { if (!RD->hasAttr<ConsumableAttr>()) { - S.Diag(Attr.getLoc(), diag::warn_attr_on_unconsumable_class) << + S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) << RD->getNameAsString(); - + return false; } } - + return true; } -static void handleCallableWhenAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; - - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) + + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) return; - + SmallVector<CallableWhenAttr::ConsumedState, 3> States; - for (unsigned ArgIndex = 0; ArgIndex < Attr.getNumArgs(); ++ArgIndex) { + for (unsigned ArgIndex = 0; ArgIndex < AL.getNumArgs(); ++ArgIndex) { CallableWhenAttr::ConsumedState CallableState; - + StringRef StateString; SourceLocation Loc; - if (Attr.isArgIdent(ArgIndex)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(ArgIndex); + if (AL.isArgIdent(ArgIndex)) { + IdentifierLoc *Ident = AL.getArgAsIdent(ArgIndex); StateString = Ident->Ident->getName(); Loc = Ident->Loc; } else { - if (!S.checkStringLiteralArgumentAttr(Attr, ArgIndex, StateString, &Loc)) + if (!S.checkStringLiteralArgumentAttr(AL, ArgIndex, StateString, &Loc)) return; } if (!CallableWhenAttr::ConvertStrToConsumedState(StateString, CallableState)) { S.Diag(Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << StateString; + << AL.getName() << StateString; return; } - + States.push_back(CallableState); } - + D->addAttr(::new (S.Context) - CallableWhenAttr(Attr.getRange(), S.Context, States.data(), - States.size(), Attr.getAttributeSpellingListIndex())); + CallableWhenAttr(AL.getRange(), S.Context, States.data(), + States.size(), AL.getAttributeSpellingListIndex())); } -static void handleParamTypestateAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ParamTypestateAttr::ConsumedState ParamState; - - if (Attr.isArgIdent(0)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(0); + + if (AL.isArgIdent(0)) { + IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef StateString = Ident->Ident->getName(); if (!ParamTypestateAttr::ConvertStrToConsumedState(StateString, ParamState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << StateString; + << AL.getName() << StateString; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } - + // FIXME: This check is currently being done in the analysis. It can be // enabled here only after the parser propagates attributes at // template specialization definition, not declaration. @@ -1185,34 +1137,33 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); // //if (!RD || !RD->hasAttr<ConsumableAttr>()) { - // S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) << + // S.Diag(AL.getLoc(), diag::warn_return_state_for_unconsumable_type) << // ReturnType.getAsString(); // return; //} - + D->addAttr(::new (S.Context) - ParamTypestateAttr(Attr.getRange(), S.Context, ParamState, - Attr.getAttributeSpellingListIndex())); + ParamTypestateAttr(AL.getRange(), S.Context, ParamState, + AL.getAttributeSpellingListIndex())); } -static void handleReturnTypestateAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ReturnTypestateAttr::ConsumedState ReturnState; - - if (Attr.isArgIdent(0)) { - IdentifierLoc *IL = Attr.getArgAsIdent(0); + + if (AL.isArgIdent(0)) { + IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(), ReturnState)) { S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << IL->Ident; + << AL.getName() << IL->Ident; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } - + // FIXME: This check is currently being done in the analysis. It can be // enabled here only after the parser propagates attributes at // template specialization definition, not declaration. @@ -1224,9 +1175,9 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, //} else if (const CXXConstructorDecl *Constructor = // dyn_cast<CXXConstructorDecl>(D)) { // ReturnType = Constructor->getThisType(S.getASTContext())->getPointeeType(); - // + // //} else { - // + // // ReturnType = cast<FunctionDecl>(D)->getCallResultType(); //} // @@ -1237,72 +1188,70 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, // ReturnType.getAsString(); // return; //} - + D->addAttr(::new (S.Context) - ReturnTypestateAttr(Attr.getRange(), S.Context, ReturnState, - Attr.getAttributeSpellingListIndex())); + ReturnTypestateAttr(AL.getRange(), S.Context, ReturnState, + AL.getAttributeSpellingListIndex())); } -static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) +static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) return; - + SetTypestateAttr::ConsumedState NewState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(0); + if (AL.isArgIdent(0)) { + IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!SetTypestateAttr::ConvertStrToConsumedState(Param, NewState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << Param; + << AL.getName() << Param; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } - + D->addAttr(::new (S.Context) - SetTypestateAttr(Attr.getRange(), S.Context, NewState, - Attr.getAttributeSpellingListIndex())); + SetTypestateAttr(AL.getRange(), S.Context, NewState, + AL.getAttributeSpellingListIndex())); } -static void handleTestTypestateAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) +static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) return; - - TestTypestateAttr::ConsumedState TestState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(0); + + TestTypestateAttr::ConsumedState TestState; + if (AL.isArgIdent(0)) { + IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!TestTypestateAttr::ConvertStrToConsumedState(Param, TestState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << Param; + << AL.getName() << Param; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } - + D->addAttr(::new (S.Context) - TestTypestateAttr(Attr.getRange(), S.Context, TestState, - Attr.getAttributeSpellingListIndex())); + TestTypestateAttr(AL.getRange(), S.Context, TestState, + AL.getAttributeSpellingListIndex())); } -static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, - const AttributeList &Attr) { +static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Remember this typedef decl, we will need it later for diagnostics. S.ExtVectorDecls.push_back(cast<TypedefNameDecl>(D)); } -static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (TagDecl *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { +static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (auto *TD = dyn_cast<TagDecl>(D)) + TD->addAttr(::new (S.Context) PackedAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); + else if (auto *FD = dyn_cast<FieldDecl>(D)) { bool BitfieldByteAligned = (!FD->getType()->isDependentType() && !FD->getType()->isIncompleteType() && FD->isBitField() && @@ -1311,81 +1260,80 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.getASTContext().getTargetInfo().getTriple().isPS4()) { if (BitfieldByteAligned) // The PS4 target needs to maintain ABI backwards compatibility. - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) - << Attr.getName() << FD->getType(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type) + << AL.getName() << FD->getType(); else FD->addAttr(::new (S.Context) PackedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } else { // Report warning about changed offset in the newer compiler versions. if (BitfieldByteAligned) - S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield); + S.Diag(AL.getLoc(), diag::warn_attribute_packed_for_bitfield); FD->addAttr(::new (S.Context) PackedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } } else - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName(); } -static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) { +static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) { // The IBOutlet/IBOutletCollection attributes only apply to instance // variables or properties of Objective-C classes. The outlet must also // have an object reference type. - if (const ObjCIvarDecl *VD = dyn_cast<ObjCIvarDecl>(D)) { + if (const auto *VD = dyn_cast<ObjCIvarDecl>(D)) { if (!VD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::warn_iboutlet_object_type) - << Attr.getName() << VD->getType() << 0; + S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) + << AL.getName() << VD->getType() << 0; return false; } } - else if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) { + else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { if (!PD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::warn_iboutlet_object_type) - << Attr.getName() << PD->getType() << 1; + S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) + << AL.getName() << PD->getType() << 1; return false; } } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL.getName(); return false; } return true; } -static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkIBOutletCommon(S, D, Attr)) +static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkIBOutletCommon(S, D, AL)) return; D->addAttr(::new (S.Context) - IBOutletAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + IBOutletAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleIBOutletCollection(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) { // The iboutletcollection attribute can have zero or one arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } - if (!checkIBOutletCommon(S, D, Attr)) + if (!checkIBOutletCommon(S, D, AL)) return; ParsedType PT; - if (Attr.hasParsedType()) - PT = Attr.getTypeArg(); + if (AL.hasParsedType()) + PT = AL.getTypeArg(); else { - PT = S.getTypeName(S.Context.Idents.get("NSObject"), Attr.getLoc(), + PT = S.getTypeName(S.Context.Idents.get("NSObject"), AL.getLoc(), S.getScopeForContext(D->getDeclContext()->getParent())); if (!PT) { - S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << "NSObject"; + S.Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject"; return; } } @@ -1393,22 +1341,22 @@ static void handleIBOutletCollection(Sema &S, Decl *D, TypeSourceInfo *QTLoc = nullptr; QualType QT = S.GetTypeFromParser(PT, &QTLoc); if (!QTLoc) - QTLoc = S.Context.getTrivialTypeSourceInfo(QT, Attr.getLoc()); + QTLoc = S.Context.getTrivialTypeSourceInfo(QT, AL.getLoc()); // Diagnose use of non-object type in iboutletcollection attribute. // FIXME. Gnu attribute extension ignores use of builtin types in // attributes. So, __attribute__((iboutletcollection(char))) will be // treated as __attribute__((iboutletcollection())). if (!QT->isObjCIdType() && !QT->isObjCObjectType()) { - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype : diag::err_iboutletcollection_type) << QT; return; } D->addAttr(::new (S.Context) - IBOutletCollectionAttr(Attr.getRange(), S.Context, QTLoc, - Attr.getAttributeSpellingListIndex())); + IBOutletCollectionAttr(AL.getRange(), S.Context, QTLoc, + AL.getAttributeSpellingListIndex())); } bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { @@ -1435,35 +1383,36 @@ bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { return T->isAnyPointerType() || T->isBlockPointerType(); } -static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, +static bool attrNonNullArgCheck(Sema &S, QualType T, const ParsedAttr &AL, SourceRange AttrParmRange, SourceRange TypeRange, bool isReturnValue = false) { if (!S.isValidPointerAttrType(T)) { if (isReturnValue) - S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) - << Attr.getName() << AttrParmRange << TypeRange; + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL.getName() << AttrParmRange << TypeRange; else - S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) - << Attr.getName() << AttrParmRange << TypeRange << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) + << AL.getName() << AttrParmRange << TypeRange << 0; return false; } return true; } -static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { - SmallVector<unsigned, 8> NonNullArgs; - for (unsigned I = 0; I < Attr.getNumArgs(); ++I) { - Expr *Ex = Attr.getArgAsExpr(I); - uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, I + 1, Ex, Idx)) +static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<ParamIdx, 8> NonNullArgs; + for (unsigned I = 0; I < AL.getNumArgs(); ++I) { + Expr *Ex = AL.getArgAsExpr(I); + ParamIdx Idx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx)) return; // Is the function argument a pointer type? - if (Idx < getFunctionOrMethodNumParams(D) && - !attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr, - Ex->getSourceRange(), - getFunctionOrMethodParamRange(D, Idx))) + if (Idx.getASTIndex() < getFunctionOrMethodNumParams(D) && + !attrNonNullArgCheck( + S, getFunctionOrMethodParamType(D, Idx.getASTIndex()), AL, + Ex->getSourceRange(), + getFunctionOrMethodParamRange(D, Idx.getASTIndex()))) continue; NonNullArgs.push_back(Idx); @@ -1473,7 +1422,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { // arguments have a nonnull attribute; warn if there aren't any. Skip this // check if the attribute came from a macro expansion or a template // instantiation. - if (NonNullArgs.empty() && Attr.getLoc().isFileID() && + if (NonNullArgs.empty() && AL.getLoc().isFileID() && !S.inTemplateInstantiation()) { bool AnyPointers = isFunctionOrMethodVariadic(D); for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); @@ -1484,80 +1433,77 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { } if (!AnyPointers) - S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); + S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_no_pointers); } - unsigned *Start = NonNullArgs.data(); + ParamIdx *Start = NonNullArgs.data(); unsigned Size = NonNullArgs.size(); llvm::array_pod_sort(Start, Start + Size); D->addAttr(::new (S.Context) - NonNullAttr(Attr.getRange(), S.Context, Start, Size, - Attr.getAttributeSpellingListIndex())); + NonNullAttr(AL.getRange(), S.Context, Start, Size, + AL.getAttributeSpellingListIndex())); } static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, - const AttributeList &Attr) { - if (Attr.getNumArgs() > 0) { + const ParsedAttr &AL) { + if (AL.getNumArgs() > 0) { if (D->getFunctionType()) { - handleNonNullAttr(S, D, Attr); + handleNonNullAttr(S, D, AL); } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_parm_no_args) + S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_parm_no_args) << D->getSourceRange(); } return; } // Is the argument a pointer type? - if (!attrNonNullArgCheck(S, D->getType(), Attr, SourceRange(), + if (!attrNonNullArgCheck(S, D->getType(), AL, SourceRange(), D->getSourceRange())) return; D->addAttr(::new (S.Context) - NonNullAttr(Attr.getRange(), S.Context, nullptr, 0, - Attr.getAttributeSpellingListIndex())); + NonNullAttr(AL.getRange(), S.Context, nullptr, 0, + AL.getAttributeSpellingListIndex())); } -static void handleReturnsNonNullAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ResultType = getFunctionOrMethodResultType(D); SourceRange SR = getFunctionOrMethodResultSourceRange(D); - if (!attrNonNullArgCheck(S, ResultType, Attr, SourceRange(), SR, + if (!attrNonNullArgCheck(S, ResultType, AL, SourceRange(), SR, /* isReturnValue */ true)) return; D->addAttr(::new (S.Context) - ReturnsNonNullAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ReturnsNonNullAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleNoEscapeAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->isInvalidDecl()) return; // noescape only applies to pointer types. QualType T = cast<ParmVarDecl>(D)->getType(); if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) - << Attr.getName() << Attr.getRange() << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) + << AL.getName() << AL.getRange() << 0; return; } D->addAttr(::new (S.Context) NoEscapeAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleAssumeAlignedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - Expr *E = Attr.getArgAsExpr(0), - *OE = Attr.getNumArgs() > 1 ? Attr.getArgAsExpr(1) : nullptr; - S.AddAssumeAlignedAttr(Attr.getRange(), D, E, OE, - Attr.getAttributeSpellingListIndex()); +static void handleAssumeAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0), + *OE = AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr; + S.AddAssumeAlignedAttr(AL.getRange(), D, E, OE, + AL.getAttributeSpellingListIndex()); } -static void handleAllocAlignAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - S.AddAllocAlignAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), - Attr.getAttributeSpellingListIndex()); +static void handleAllocAlignAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.AddAllocAlignAttr(AL.getRange(), D, AL.getArgAsExpr(0), + AL.getAttributeSpellingListIndex()); } void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -1615,7 +1561,7 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, unsigned SpellingListIndex) { QualType ResultType = getFunctionOrMethodResultType(D); - AllocAlignAttr TmpAttr(AttrRange, Context, 0, SpellingListIndex); + AllocAlignAttr TmpAttr(AttrRange, Context, ParamIdx(), SpellingListIndex); SourceLocation AttrLoc = AttrRange.getBegin(); if (!ResultType->isDependentType() && @@ -1625,28 +1571,22 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, return; } - uint64_t IndexVal; + ParamIdx Idx; const auto *FuncDecl = cast<FunctionDecl>(D); if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr, - /*AttrArgNo=*/1, ParamExpr, - IndexVal)) + /*AttrArgNo=*/1, ParamExpr, Idx)) return; - QualType Ty = getFunctionOrMethodParamType(D, IndexVal); + QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) { Diag(ParamExpr->getLocStart(), diag::err_attribute_integers_only) - << &TmpAttr << FuncDecl->getParamDecl(IndexVal)->getSourceRange(); + << &TmpAttr + << FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange(); return; } - // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex - // because that has corrected for the implicit this parameter, and is zero- - // based. The attribute expects what the user wrote explicitly. - llvm::APSInt Val; - ParamExpr->EvaluateAsInt(Val, Context); - - D->addAttr(::new (Context) AllocAlignAttr( - AttrRange, Context, Val.getZExtValue(), SpellingListIndex)); + D->addAttr(::new (Context) + AllocAlignAttr(AttrRange, Context, Idx, SpellingListIndex)); } /// Normalize the attribute, __foo__ becomes foo. @@ -1660,7 +1600,7 @@ static bool normalizeName(StringRef &AttrName) { return false; } -static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { +static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // This attribute must be applied to a function declaration. The first // argument to the attribute must be an identifier, the name of the resource, // for example: malloc. The following arguments must be argument indexes, the @@ -1706,15 +1646,15 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { Module = &S.PP.getIdentifierTable().get(ModuleName); } - SmallVector<unsigned, 8> OwnershipArgs; + SmallVector<ParamIdx, 8> OwnershipArgs; for (unsigned i = 1; i < AL.getNumArgs(); ++i) { Expr *Ex = AL.getArgAsExpr(i); - uint64_t Idx; + ParamIdx Idx; if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx)) return; // Is the function argument a pointer type? - QualType T = getFunctionOrMethodParamType(D, Idx); + QualType T = getFunctionOrMethodParamType(D, Idx.getASTIndex()); int Err = -1; // No error switch (K) { case OwnershipAttr::Takes: @@ -1745,14 +1685,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { } else if (K == OwnershipAttr::Returns && I->getOwnKind() == OwnershipAttr::Returns) { // A returns attribute conflicts with any other returns attribute using - // a different index. Note, diagnostic reporting is 1-based, but stored - // argument indexes are 0-based. + // a different index. if (std::find(I->args_begin(), I->args_end(), Idx) == I->args_end()) { S.Diag(I->getLocation(), diag::err_ownership_returns_index_mismatch) - << *(I->args_begin()) + 1; + << I->args_begin()->getSourceIndex(); if (I->args_size()) S.Diag(AL.getLoc(), diag::note_ownership_returns_index_mismatch) - << (unsigned)Idx + 1 << Ex->getSourceRange(); + << Idx.getSourceIndex() << Ex->getSourceRange(); return; } } @@ -1760,25 +1699,22 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { OwnershipArgs.push_back(Idx); } - unsigned* start = OwnershipArgs.data(); - unsigned size = OwnershipArgs.size(); - llvm::array_pod_sort(start, start + size); - + ParamIdx *Start = OwnershipArgs.data(); + unsigned Size = OwnershipArgs.size(); + llvm::array_pod_sort(Start, Start + Size); D->addAttr(::new (S.Context) - OwnershipAttr(AL.getLoc(), S.Context, Module, start, size, - AL.getAttributeSpellingListIndex())); + OwnershipAttr(AL.getLoc(), S.Context, Module, Start, Size, + AL.getAttributeSpellingListIndex())); } -static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } - NamedDecl *nd = cast<NamedDecl>(D); - // gcc rejects // class c { // static int a __attribute__((weakref ("v2"))); @@ -1791,8 +1727,8 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { // we reject them const DeclContext *Ctx = D->getDeclContext()->getRedeclContext(); if (!Ctx->isFileContext()) { - S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) - << nd; + S.Diag(AL.getLoc(), diag::err_attribute_weakref_not_global_context) + << cast<NamedDecl>(D); return; } @@ -1822,88 +1758,71 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { // of transforming it into an AliasAttr. The WeakRefAttr never uses the // StringRef parameter it was given anyway. StringRef Str; - if (Attr.getNumArgs() && S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (AL.getNumArgs() && S.checkStringLiteralArgumentAttr(AL, 0, Str)) // GCC will accept anything as the argument of weakref. Should we // check for an existing decl? - D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); D->addAttr(::new (S.Context) - WeakRefAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + WeakRefAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleIFuncAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; // Aliases should be on declarations, not definitions. const auto *FD = cast<FunctionDecl>(D); if (FD->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 1; + S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 1; return; } - D->addAttr(::new (S.Context) IFuncAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) IFuncAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } -static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { - S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin); + S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_darwin); return; } if (S.Context.getTargetInfo().getTriple().isNVPTX()) { - S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_nvptx); + S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_nvptx); } // Aliases should be on declarations, not definitions. if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 0; + S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 0; return; } } else { const auto *VD = cast<VarDecl>(D); if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD << 0; + S.Diag(AL.getLoc(), diag::err_alias_is_definition) << VD << 0; return; } } // FIXME: check if target symbol exists in current file - D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); -} - -static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<HotAttr>(S, D, Attr.getRange(), Attr.getName())) - return; - - D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } -static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr.getRange(), Attr.getName())) - return; - - D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleTLSModelAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Model; SourceLocation LiteralLoc; // Check that it is a string. - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Model, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Model, &LiteralLoc)) return; // Check that the value. @@ -1914,60 +1833,101 @@ static void handleTLSModelAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) - TLSModelAttr(Attr.getRange(), S.Context, Model, - Attr.getAttributeSpellingListIndex())); + TLSModelAttr(AL.getRange(), S.Context, Model, + AL.getAttributeSpellingListIndex())); } -static void handleRestrictAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ResultType = getFunctionOrMethodResultType(D); if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) { D->addAttr(::new (S.Context) RestrictAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; } - S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) - << Attr.getName() << getFunctionOrMethodResultSourceRange(D); + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL.getName() << getFunctionOrMethodResultSourceRange(D); +} + +static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + FunctionDecl *FD = cast<FunctionDecl>(D); + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + return; + + SmallVector<IdentifierInfo *, 8> CPUs; + for (unsigned ArgNo = 0; ArgNo < getNumAttributeArgs(AL); ++ArgNo) { + if (!AL.isArgIdent(ArgNo)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *CPUArg = AL.getArgAsIdent(ArgNo); + StringRef CPUName = CPUArg->Ident->getName().trim(); + + if (!S.Context.getTargetInfo().validateCPUSpecificCPUDispatch(CPUName)) { + S.Diag(CPUArg->Loc, diag::err_invalid_cpu_specific_dispatch_value) + << CPUName << (AL.getKind() == ParsedAttr::AT_CPUDispatch); + return; + } + + const TargetInfo &Target = S.Context.getTargetInfo(); + if (llvm::any_of(CPUs, [CPUName, &Target](const IdentifierInfo *Cur) { + return Target.CPUSpecificManglingCharacter(CPUName) == + Target.CPUSpecificManglingCharacter(Cur->getName()); + })) { + S.Diag(AL.getLoc(), diag::warn_multiversion_duplicate_entries); + return; + } + CPUs.push_back(CPUArg->Ident); + } + + FD->setIsMultiVersion(true); + if (AL.getKind() == ParsedAttr::AT_CPUSpecific) + D->addAttr(::new (S.Context) CPUSpecificAttr( + AL.getRange(), S.Context, CPUs.data(), CPUs.size(), + AL.getAttributeSpellingListIndex())); + else + D->addAttr(::new (S.Context) CPUDispatchAttr( + AL.getRange(), S.Context, CPUs.data(), CPUs.size(), + AL.getAttributeSpellingListIndex())); } -static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::Cpp; + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL.getName() << AttributeLangSupport::Cpp; return; } - if (CommonAttr *CA = S.mergeCommonAttr(D, Attr.getRange(), Attr.getName(), - Attr.getAttributeSpellingListIndex())) + if (CommonAttr *CA = S.mergeCommonAttr(D, AL.getRange(), AL.getName(), + AL.getAttributeSpellingListIndex())) D->addAttr(CA); } -static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL.getRange(), + AL.getName())) return; - if (Attr.isDeclspecAttribute()) { + if (AL.isDeclspecAttribute()) { const auto &Triple = S.getASTContext().getTargetInfo().getTriple(); const auto &Arch = Triple.getArch(); if (Arch != llvm::Triple::x86 && (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb)) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_on_arch) - << Attr.getName() << Triple.getArchName(); + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_on_arch) + << AL.getName() << Triple.getArchName(); return; } } - D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NakedAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) { +static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { if (hasDeclarator(D)) return; - if (S.CheckNoReturnAttr(Attrs)) - return; - if (!isa<ObjCMethodDecl>(D)) { S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) << Attrs.getName() << ExpectedFunctionOrMethod; @@ -1978,16 +1938,14 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) { Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); } -static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (S.CheckNoCallerSavedRegsAttr(Attr)) - return; - - D->addAttr(::new (S.Context) AnyX86NoCallerSavedRegistersAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { + if (!S.getLangOpts().CFProtectionBranch) + S.Diag(Attrs.getLoc(), diag::warn_nocf_check_attribute_ignored); + else + handleSimpleAttribute<AnyX86NoCfCheckAttr>(S, D, Attrs); } -bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) { +bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { if (!checkAttributeNumArgs(*this, Attrs, 0)) { Attrs.setInvalid(); return true; @@ -1996,221 +1954,167 @@ bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) { return false; } -bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &Attr) { +bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. - if (!Attr.existsInTarget(Context.getTargetInfo())) { - Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) << Attr.getName(); - Attr.setInvalid(); - return true; - } - - if (!checkAttributeNumArgs(*this, Attr, 0)) { - Attr.setInvalid(); + if (!AL.existsInTarget(Context.getTargetInfo())) { + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL.getName(); + AL.setInvalid(); return true; } return false; } -static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - +static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // The checking path for 'noreturn' and 'analyzer_noreturn' are different // because 'analyzer_noreturn' does not impact the type. if (!isFunctionOrMethodOrBlock(D)) { ValueDecl *VD = dyn_cast<ValueDecl>(D); if (!VD || (!VD->getType()->isBlockPointerType() && !VD->getType()->isFunctionPointerType())) { - S.Diag(Attr.getLoc(), - Attr.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type + S.Diag(AL.getLoc(), + AL.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type : diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrBlock; + << AL.getName() << ExpectedFunctionMethodOrBlock; return; } } - + D->addAttr(::new (S.Context) - AnalyzerNoReturnAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + AnalyzerNoReturnAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } // PS3 PPU-specific. -static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { -/* - Returning a Vector Class in Registers - - According to the PPU ABI specifications, a class with a single member of - vector type is returned in memory when used as the return value of a function. - This results in inefficient code when implementing vector classes. To return - the value in a single vector register, add the vecreturn attribute to the - class definition. This attribute is also applicable to struct types. - - Example: - - struct Vector - { - __vector float xyzw; - } __attribute__((vecreturn)); - - Vector Add(Vector lhs, Vector rhs) - { - Vector result; - result.xyzw = vec_add(lhs.xyzw, rhs.xyzw); - return result; // This will be returned in a register - } -*/ +static void handleVecReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + /* + Returning a Vector Class in Registers + + According to the PPU ABI specifications, a class with a single member of + vector type is returned in memory when used as the return value of a + function. + This results in inefficient code when implementing vector classes. To return + the value in a single vector register, add the vecreturn attribute to the + class definition. This attribute is also applicable to struct types. + + Example: + + struct Vector + { + __vector float xyzw; + } __attribute__((vecreturn)); + + Vector Add(Vector lhs, Vector rhs) + { + Vector result; + result.xyzw = vec_add(lhs.xyzw, rhs.xyzw); + return result; // This will be returned in a register + } + */ if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << A; + S.Diag(AL.getLoc(), diag::err_repeat_attribute) << A; return; } - RecordDecl *record = cast<RecordDecl>(D); + const auto *R = cast<RecordDecl>(D); int count = 0; - if (!isa<CXXRecordDecl>(record)) { - S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member); + if (!isa<CXXRecordDecl>(R)) { + S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member); return; } - if (!cast<CXXRecordDecl>(record)->isPOD()) { - S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_pod_record); + if (!cast<CXXRecordDecl>(R)->isPOD()) { + S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_pod_record); return; } - for (const auto *I : record->fields()) { + for (const auto *I : R->fields()) { if ((count == 1) || !I->getType()->isVectorType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member); + S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member); return; } count++; } - D->addAttr(::new (S.Context) - VecReturnAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) VecReturnAttr( + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { if (isa<ParmVarDecl>(D)) { // [[carries_dependency]] can only be applied to a parameter if it is a // parameter of a function declaration or lambda. if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) { - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), diag::err_carries_dependency_param_not_function_decl); return; } } D->addAttr(::new (S.Context) CarriesDependencyAttr( - Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleNotTailCalledAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) NotTailCalledAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); -} - -static void handleDisableTailCallsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<NakedAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) DisableTailCallsAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); -} - -static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (VD->hasLocalStorage()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - return; - } - } else if (!isFunctionOrMethod(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableOrFunction; - return; - } - - D->addAttr(::new (S.Context) - UsedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - bool IsCXX17Attr = Attr.isCXX11Attribute() && !Attr.getScopeName(); - - if (IsCXX17Attr && isa<VarDecl>(D)) { - // The C++17 spelling of this attribute cannot be applied to a static data - // member per [dcl.attr.unused]p2. - if (cast<VarDecl>(D)->isStaticDataMember()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedForMaybeUnused; - return; - } - } +static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + bool IsCXX17Attr = AL.isCXX11Attribute() && !AL.getScopeName(); // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr) - S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName(); + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL.getName(); D->addAttr(::new (S.Context) UnusedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t priority = ConstructorAttr::DefaultPriority; - if (Attr.getNumArgs() && - !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) + if (AL.getNumArgs() && + !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; D->addAttr(::new (S.Context) - ConstructorAttr(Attr.getRange(), S.Context, priority, - Attr.getAttributeSpellingListIndex())); + ConstructorAttr(AL.getRange(), S.Context, priority, + AL.getAttributeSpellingListIndex())); } -static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t priority = DestructorAttr::DefaultPriority; - if (Attr.getNumArgs() && - !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) + if (AL.getNumArgs() && + !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; D->addAttr(::new (S.Context) - DestructorAttr(Attr.getRange(), S.Context, priority, - Attr.getAttributeSpellingListIndex())); + DestructorAttr(AL.getRange(), S.Context, priority, + AL.getAttributeSpellingListIndex())); } template <typename AttrTy> -static void handleAttrWithMessage(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) { // Handle the case where the attribute has a text message. StringRef Str; - if (Attr.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (AL.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; - D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AttrTy(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_objc_attr_protocol_requires_definition) - << Attr.getName() << Attr.getRange(); + S.Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition) + << AL.getName() << AL.getRange(); return; } D->addAttr(::new (S.Context) - ObjCExplicitProtocolImplAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCExplicitProtocolImplAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } static bool checkAvailabilityAttr(Sema &S, SourceRange Range, @@ -2252,7 +2156,7 @@ static bool checkAvailabilityAttr(Sema &S, SourceRange Range, return false; } -/// \brief Check whether the two versions match. +/// Check whether the two versions match. /// /// If either version tuple is empty, then they are assumed to match. If /// \p BeforeIsOkay is true, then \p X can be less than or equal to \p Y. @@ -2302,7 +2206,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); for (unsigned i = 0, e = Attrs.size(); i != e;) { - const AvailabilityAttr *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]); + const auto *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]); if (!OldAA) { ++i; continue; @@ -2434,37 +2338,34 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, return nullptr; } -static void handleAvailabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) +static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeNumArgs(S, AL, 1)) return; - IdentifierLoc *Platform = Attr.getArgAsIdent(0); - unsigned Index = Attr.getAttributeSpellingListIndex(); - + IdentifierLoc *Platform = AL.getArgAsIdent(0); + unsigned Index = AL.getAttributeSpellingListIndex(); + IdentifierInfo *II = Platform->Ident; if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty()) S.Diag(Platform->Loc, diag::warn_availability_unknown_platform) << Platform->Ident; - NamedDecl *ND = dyn_cast<NamedDecl>(D); + auto *ND = dyn_cast<NamedDecl>(D); if (!ND) // We warned about this already, so just return. return; - AvailabilityChange Introduced = Attr.getAvailabilityIntroduced(); - AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); - AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); - bool IsUnavailable = Attr.getUnavailableLoc().isValid(); - bool IsStrict = Attr.getStrictLoc().isValid(); + AvailabilityChange Introduced = AL.getAvailabilityIntroduced(); + AvailabilityChange Deprecated = AL.getAvailabilityDeprecated(); + AvailabilityChange Obsoleted = AL.getAvailabilityObsoleted(); + bool IsUnavailable = AL.getUnavailableLoc().isValid(); + bool IsStrict = AL.getStrictLoc().isValid(); StringRef Str; - if (const StringLiteral *SE = - dyn_cast_or_null<StringLiteral>(Attr.getMessageExpr())) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getMessageExpr())) Str = SE->getString(); StringRef Replacement; - if (const StringLiteral *SE = - dyn_cast_or_null<StringLiteral>(Attr.getReplacementExpr())) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getReplacementExpr())) Replacement = SE->getString(); - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(), II, + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, AL.getRange(), II, false/*Implicit*/, Introduced.Version, Deprecated.Version, @@ -2509,7 +2410,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - Attr.getRange(), + AL.getRange(), NewII, true/*Implicit*/, NewIntroduced, @@ -2534,7 +2435,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, if (NewII) { AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - Attr.getRange(), + AL.getRange(), NewII, true/*Implicit*/, Introduced.Version, @@ -2552,23 +2453,23 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, } static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; - assert(checkAttributeAtMostNumArgs(S, Attr, 3) && + assert(checkAttributeAtMostNumArgs(S, AL, 3) && "Invalid number of arguments in an external_source_symbol attribute"); StringRef Language; - if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(0))) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(0))) Language = SE->getString(); StringRef DefinedIn; - if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(1))) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(1))) DefinedIn = SE->getString(); - bool IsGeneratedDeclaration = Attr.getArgAsIdent(2) != nullptr; + bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr; D->addAttr(::new (S.Context) ExternalSourceSymbolAttr( - Attr.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration, + AL.getAttributeSpellingListIndex())); } template <class T> @@ -2601,12 +2502,12 @@ TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } -static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr, +static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, bool isTypeVisibility) { // Visibility attributes don't mean anything on a typedef. if (isa<TypedefNameDecl>(D)) { - S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored) - << Attr.getName(); + S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) + << AL.getName(); return; } @@ -2615,84 +2516,82 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr, !(isa<TagDecl>(D) || isa<ObjCInterfaceDecl>(D) || isa<NamespaceDecl>(D))) { - S.Diag(Attr.getRange().getBegin(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedTypeOrNamespace; + S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type) + << AL.getName() << ExpectedTypeOrNamespace; return; } // Check that the argument is a string literal. StringRef TypeStr; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, TypeStr, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, TypeStr, &LiteralLoc)) return; VisibilityAttr::VisibilityType type; if (!VisibilityAttr::ConvertStrToVisibilityType(TypeStr, type)) { S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) - << Attr.getName() << TypeStr; + << AL.getName() << TypeStr; return; } - + // Complain about attempts to use protected visibility on targets // (like Darwin) that don't support it. if (type == VisibilityAttr::Protected && !S.Context.getTargetInfo().hasProtectedVisibility()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_protected_visibility); + S.Diag(AL.getLoc(), diag::warn_attribute_protected_visibility); type = VisibilityAttr::Default; } - unsigned Index = Attr.getAttributeSpellingListIndex(); - clang::Attr *newAttr; + unsigned Index = AL.getAttributeSpellingListIndex(); + Attr *newAttr; if (isTypeVisibility) { - newAttr = S.mergeTypeVisibilityAttr(D, Attr.getRange(), + newAttr = S.mergeTypeVisibilityAttr(D, AL.getRange(), (TypeVisibilityAttr::VisibilityType) type, Index); } else { - newAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type, Index); + newAttr = S.mergeVisibilityAttr(D, AL.getRange(), type, Index); } if (newAttr) D->addAttr(newAttr); } -static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, - const AttributeList &Attr) { - ObjCMethodDecl *method = cast<ObjCMethodDecl>(decl); - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; +static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *M = cast<ObjCMethodDecl>(D); + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } - IdentifierLoc *IL = Attr.getArgAsIdent(0); + IdentifierLoc *IL = AL.getArgAsIdent(0); ObjCMethodFamilyAttr::FamilyKind F; if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) { - S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << Attr.getName() - << IL->Ident; + S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) + << AL.getName() << IL->Ident; return; } if (F == ObjCMethodFamilyAttr::OMF_init && - !method->getReturnType()->isObjCObjectPointerType()) { - S.Diag(method->getLocation(), diag::err_init_method_bad_return_type) - << method->getReturnType(); + !M->getReturnType()->isObjCObjectPointerType()) { + S.Diag(M->getLocation(), diag::err_init_method_bad_return_type) + << M->getReturnType(); // Ignore the attribute. return; } - method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(), - S.Context, F, - Attr.getAttributeSpellingListIndex())); + D->addAttr(new (S.Context) ObjCMethodFamilyAttr( + AL.getRange(), S.Context, F, AL.getAttributeSpellingListIndex())); } -static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { +static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { QualType T = TD->getUnderlyingType(); if (!T->isCARCBridgableType()) { S.Diag(TD->getLocation(), diag::err_nsobject_attribute); return; } } - else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) { + else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { QualType T = PD->getType(); if (!T->isCARCBridgableType()) { S.Diag(PD->getLocation(), diag::err_nsobject_attribute); @@ -2705,16 +2604,16 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject)); // // In this case it follows tradition and suppresses an error in the above - // case. + // case. S.Diag(D->getLocation(), diag::warn_nsobject_attribute); } D->addAttr(::new (S.Context) - ObjCNSObjectAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCNSObjectAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleObjCIndependentClass(Sema &S, Decl *D, const AttributeList &Attr) { - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { +static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { QualType T = TD->getUnderlyingType(); if (!T->isObjCObjectPointerType()) { S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute); @@ -2725,45 +2624,45 @@ static void handleObjCIndependentClass(Sema &S, Decl *D, const AttributeList &At return; } D->addAttr(::new (S.Context) - ObjCIndependentClassAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCIndependentClassAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; +static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } - IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; BlocksAttr::BlockType type; if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << II; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << II; return; } D->addAttr(::new (S.Context) - BlocksAttr(Attr.getRange(), S.Context, type, - Attr.getAttributeSpellingListIndex())); + BlocksAttr(AL.getRange(), S.Context, type, + AL.getAttributeSpellingListIndex())); } -static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; - if (Attr.getNumArgs() > 0) { - Expr *E = Attr.getArgAsExpr(0); + if (AL.getNumArgs() > 0) { + Expr *E = AL.getArgAsExpr(0); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIntegerConstant + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } if (Idx.isSigned() && Idx.isNegative()) { - S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero) + S.Diag(AL.getLoc(), diag::err_attribute_sentinel_less_than_zero) << E->getSourceRange(); return; } @@ -2772,13 +2671,13 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { } unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos; - if (Attr.getNumArgs() > 1) { - Expr *E = Attr.getArgAsExpr(1); + if (AL.getNumArgs() > 1) { + Expr *E = AL.getArgAsExpr(1); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 2 << AANT_ArgumentIntegerConstant + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } @@ -2787,34 +2686,34 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { if ((Idx.isSigned() && Idx.isNegative()) || nullPos > 1) { // FIXME: This error message could be improved, it would be nice // to say what the bounds actually are. - S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) + S.Diag(AL.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) << E->getSourceRange(); return; } } - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { const FunctionType *FT = FD->getType()->castAs<FunctionType>(); if (isa<FunctionNoProtoType>(FT)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments); + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_named_arguments); return; } if (!cast<FunctionProtoType>(FT)->isVariadic()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; } - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { if (!MD->isVariadic()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; } - } else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + } else if (const auto *BD = dyn_cast<BlockDecl>(D)) { if (!BD->isVariadic()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; return; } - } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) { + } else if (const auto *V = dyn_cast<VarDecl>(D)) { QualType Ty = V->getType(); if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { const FunctionType *FT = Ty->isFunctionPointerType() @@ -2822,84 +2721,83 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); if (!cast<FunctionProtoType>(FT)->isVariadic()) { int m = Ty->isFunctionPointerType() ? 0 : 1; - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; return; } } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrBlock; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionMethodOrBlock; return; } } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrBlock; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionMethodOrBlock; return; } D->addAttr(::new (S.Context) - SentinelAttr(Attr.getRange(), S.Context, sentinel, nullPos, - Attr.getAttributeSpellingListIndex())); + SentinelAttr(AL.getRange(), S.Context, sentinel, nullPos, + AL.getAttributeSpellingListIndex())); } -static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->getFunctionType() && D->getFunctionType()->getReturnType()->isVoidType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) - << Attr.getName() << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) + << AL.getName() << 0; return; } - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) if (MD->getReturnType()->isVoidType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) - << Attr.getName() << 1; + S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) + << AL.getName() << 1; return; } - + // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. - if (!S.getLangOpts().CPlusPlus17 && Attr.isCXX11Attribute() && - !Attr.getScopeName()) - S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName(); + if (!S.getLangOpts().CPlusPlus17 && AL.isCXX11Attribute() && + !AL.getScopeName()) + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL.getName(); - D->addAttr(::new (S.Context) - WarnUnusedResultAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + WarnUnusedResultAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // weak_import only applies to variable & function declarations. bool isDef = false; if (!D->canBeWeakImported(isDef)) { if (isDef) - S.Diag(Attr.getLoc(), diag::warn_attribute_invalid_on_definition) + S.Diag(AL.getLoc(), diag::warn_attribute_invalid_on_definition) << "weak_import"; else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) || (S.Context.getTargetInfo().getTriple().isOSDarwin() && (isa<ObjCInterfaceDecl>(D) || isa<EnumDecl>(D)))) { // Nothing to warn about here. } else - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableOrFunction; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedVariableOrFunction; return; } D->addAttr(::new (S.Context) - WeakImportAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + WeakImportAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } // Handles reqd_work_group_size and work_group_size_hint. template <typename WorkGroupAttr> -static void handleWorkGroupSize(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t WGSize[3]; for (unsigned i = 0; i < 3; ++i) { - const Expr *E = Attr.getArgAsExpr(i); - if (!checkUInt32Argument(S, Attr, E, WGSize[i], i)) + const Expr *E = AL.getArgAsExpr(i); + if (!checkUInt32Argument(S, AL, E, WGSize[i], i)) return; if (WGSize[i] == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) - << Attr.getName() << E->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) + << AL.getName() << E->getSourceRange(); return; } } @@ -2908,73 +2806,81 @@ static void handleWorkGroupSize(Sema &S, Decl *D, if (Existing && !(Existing->getXDim() == WGSize[0] && Existing->getYDim() == WGSize[1] && Existing->getZDim() == WGSize[2])) - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); - D->addAttr(::new (S.Context) WorkGroupAttr(Attr.getRange(), S.Context, + D->addAttr(::new (S.Context) WorkGroupAttr(AL.getRange(), S.Context, WGSize[0], WGSize[1], WGSize[2], - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } // Handles intel_reqd_sub_group_size. -static void handleSubGroupSize(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t SGSize; - const Expr *E = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, E, SGSize)) + const Expr *E = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, E, SGSize)) return; if (SGSize == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) - << Attr.getName() << E->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) + << AL.getName() << E->getSourceRange(); return; } OpenCLIntelReqdSubGroupSizeAttr *Existing = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>(); if (Existing && Existing->getSubGroupSize() != SGSize) - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); D->addAttr(::new (S.Context) OpenCLIntelReqdSubGroupSizeAttr( - Attr.getRange(), S.Context, SGSize, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, SGSize, + AL.getAttributeSpellingListIndex())); } -static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.hasParsedType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; +static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.hasParsedType()) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } TypeSourceInfo *ParmTSI = nullptr; - QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg(), &ParmTSI); + QualType ParmType = S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI); assert(ParmTSI && "no type source info for attribute argument"); if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() && (ParmType->isBooleanType() || !ParmType->isIntegralType(S.getASTContext()))) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_vec_type_hint) + S.Diag(AL.getLoc(), diag::err_attribute_argument_vec_type_hint) << ParmType; return; } if (VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>()) { if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) { - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); return; } } - D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) VecTypeHintAttr(AL.getLoc(), S.Context, ParmTSI, - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, unsigned AttrSpellingListIndex) { + // Explicit or partial specializations do not inherit + // the section attribute from the primary template. + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (AttrSpellingListIndex == SectionAttr::Declspec_allocate && + FD->isFunctionTemplateSpecialization()) + return nullptr; + } if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) { if (ExistingAttr->getName() == Name) return nullptr; - Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section); + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) + << 1 /*section*/; Diag(Range.getBegin(), diag::note_previous_attribute); return nullptr; } @@ -2985,18 +2891,19 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) { std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName); if (!Error.empty()) { - Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error; + Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error + << 1 /*'section'*/; return false; } return true; } -static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Make sure that there is a string literal as the sections's single // argument. StringRef Str; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc)) return; if (!S.checkSectionName(LiteralLoc, Str)) @@ -3010,12 +2917,65 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - unsigned Index = Attr.getAttributeSpellingListIndex(); - SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(), Str, Index); + unsigned Index = AL.getAttributeSpellingListIndex(); + SectionAttr *NewAttr = S.mergeSectionAttr(D, AL.getRange(), Str, Index); if (NewAttr) D->addAttr(NewAttr); } +static bool checkCodeSegName(Sema&S, SourceLocation LiteralLoc, StringRef CodeSegName) { + std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName); + if (!Error.empty()) { + S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error + << 0 /*'code-seg'*/; + return false; + } + return true; +} + +CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range, + StringRef Name, + unsigned AttrSpellingListIndex) { + // Explicit or partial specializations do not inherit + // the code_seg attribute from the primary template. + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isFunctionTemplateSpecialization()) + return nullptr; + } + if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) { + if (ExistingAttr->getName() == Name) + return nullptr; + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) + << 0 /*codeseg*/; + Diag(Range.getBegin(), diag::note_previous_attribute); + return nullptr; + } + return ::new (Context) CodeSegAttr(Range, Context, Name, + AttrSpellingListIndex); +} + +static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Str; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc)) + return; + if (!checkCodeSegName(S, LiteralLoc, Str)) + return; + if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) { + if (!ExistingAttr->isImplicit()) { + S.Diag(AL.getLoc(), + ExistingAttr->getName() == Str + ? diag::warn_duplicate_codeseg_attribute + : diag::err_conflicting_codeseg_attribute); + return; + } + D->dropAttr<CodeSegAttr>(); + } + if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL.getRange(), Str, + AL.getAttributeSpellingListIndex())) + D->addAttr(CSA); +} + // Check for things we'd like to warn about. Multiversioning issues are // handled later in the process, once we know how many exist. bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { @@ -3044,30 +3004,50 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { << Unsupported << None << CurFeature; } - return true; + return false; } -static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc) || - !S.checkTargetAttr(LiteralLoc, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || + S.checkTargetAttr(LiteralLoc, Str)) return; - unsigned Index = Attr.getAttributeSpellingListIndex(); + + unsigned Index = AL.getAttributeSpellingListIndex(); TargetAttr *NewAttr = - ::new (S.Context) TargetAttr(Attr.getRange(), S.Context, Str, Index); + ::new (S.Context) TargetAttr(AL.getRange(), S.Context, Str, Index); D->addAttr(NewAttr); } -static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { - Expr *E = Attr.getArgAsExpr(0); +static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0); + uint32_t VecWidth; + if (!checkUInt32Argument(S, AL, E, VecWidth)) { + AL.setInvalid(); + return; + } + + MinVectorWidthAttr *Existing = D->getAttr<MinVectorWidthAttr>(); + if (Existing && Existing->getVectorWidth() != VecWidth) { + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); + return; + } + + D->addAttr(::new (S.Context) + MinVectorWidthAttr(AL.getRange(), S.Context, VecWidth, + AL.getAttributeSpellingListIndex())); +} + +static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0); SourceLocation Loc = E->getExprLoc(); FunctionDecl *FD = nullptr; DeclarationNameInfo NI; // gcc only allows for simple identifiers. Since we support more than gcc, we // will warn the user. - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) { if (DRE->hasQualifier()) S.Diag(Loc, diag::warn_cleanup_ext); FD = dyn_cast<FunctionDecl>(DRE->getDecl()); @@ -3077,7 +3057,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { << NI.getName(); return; } - } else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { + } else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { if (ULE->hasExplicitTemplateArgs()) S.Diag(Loc, diag::warn_cleanup_ext); FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); @@ -3112,49 +3092,49 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { } D->addAttr(::new (S.Context) - CleanupAttr(Attr.getRange(), S.Context, FD, - Attr.getAttributeSpellingListIndex())); + CleanupAttr(AL.getRange(), S.Context, FD, + AL.getAttributeSpellingListIndex())); } static void handleEnumExtensibilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 0 << AANT_ArgumentIdentifier; + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 0 << AANT_ArgumentIdentifier; return; } EnumExtensibilityAttr::Kind ExtensibilityKind; - IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; if (!EnumExtensibilityAttr::ConvertStrToKind(II->getName(), ExtensibilityKind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << II; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << II; return; } D->addAttr(::new (S.Context) EnumExtensibilityAttr( - Attr.getRange(), S.Context, ExtensibilityKind, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, ExtensibilityKind, + AL.getAttributeSpellingListIndex())); } /// Handle __attribute__((format_arg((idx)))) attribute based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { - Expr *IdxExpr = Attr.getArgAsExpr(0); - uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, IdxExpr, Idx)) +static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *IdxExpr = AL.getArgAsExpr(0); + ParamIdx Idx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx)) return; // Make sure the format string is really a string. - QualType Ty = getFunctionOrMethodParamType(D, Idx); + QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); bool NotNSStringTy = !isNSStringType(Ty, S.Context); if (NotNSStringTy && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a string type" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; @@ -3164,21 +3144,14 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_result_not) << (NotNSStringTy ? "string type" : "NSString") << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; } - // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex - // because that has corrected for the implicit this parameter, and is zero- - // based. The attribute expects what the user wrote explicitly. - llvm::APSInt Val; - IdxExpr->EvaluateAsInt(Val, S.Context); - - D->addAttr(::new (S.Context) - FormatArgAttr(Attr.getRange(), S.Context, Val.getZExtValue(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) FormatArgAttr( + AL.getRange(), S.Context, Idx, AL.getAttributeSpellingListIndex())); } enum FormatAttrKind { @@ -3214,43 +3187,42 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) { /// Handle __attribute__((init_priority(priority))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html -static void handleInitPriorityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.getLangOpts().CPlusPlus) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName(); return; } - + if (S.getCurFunctionOrMethodDecl()) { - S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr); - Attr.setInvalid(); + S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); + AL.setInvalid(); return; } QualType T = cast<VarDecl>(D)->getType(); if (S.Context.getAsArrayType(T)) T = S.Context.getBaseElementType(T); if (!T->getAs<RecordType>()) { - S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr); - Attr.setInvalid(); + S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); + AL.setInvalid(); return; } - Expr *E = Attr.getArgAsExpr(0); + Expr *E = AL.getArgAsExpr(0); uint32_t prioritynum; - if (!checkUInt32Argument(S, Attr, E, prioritynum)) { - Attr.setInvalid(); + if (!checkUInt32Argument(S, AL, E, prioritynum)) { + AL.setInvalid(); return; } if (prioritynum < 101 || prioritynum > 65535) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_outof_range) - << E->getSourceRange() << Attr.getName() << 101 << 65535; - Attr.setInvalid(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_outof_range) + << E->getSourceRange() << AL.getName() << 101 << 65535; + AL.setInvalid(); return; } D->addAttr(::new (S.Context) - InitPriorityAttr(Attr.getRange(), S.Context, prioritynum, - Attr.getAttributeSpellingListIndex())); + InitPriorityAttr(AL.getRange(), S.Context, prioritynum, + AL.getAttributeSpellingListIndex())); } FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, @@ -3276,10 +3248,10 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, /// Handle __attribute__((format(type,idx,firstarg))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; +static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } @@ -3288,7 +3260,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { bool HasImplicitThisParam = isInstanceMethod(D); unsigned NumArgs = getFunctionOrMethodNumParams(D) + HasImplicitThisParam; - IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; StringRef Format = II->getName(); if (normalizeName(Format)) { @@ -3298,25 +3270,25 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Check for supported formats. FormatAttrKind Kind = getFormatAttrKind(Format); - + if (Kind == IgnoredFormat) return; - + if (Kind == InvalidFormat) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << II->getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << II->getName(); return; } // checks for the 2nd argument - Expr *IdxExpr = Attr.getArgAsExpr(1); + Expr *IdxExpr = AL.getArgAsExpr(1); uint32_t Idx; - if (!checkUInt32Argument(S, Attr, IdxExpr, Idx, 2)) + if (!checkUInt32Argument(S, AL, IdxExpr, Idx, 2)) return; if (Idx < 1 || Idx > NumArgs) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << 2 << IdxExpr->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << 2 << IdxExpr->getSourceRange(); return; } @@ -3325,7 +3297,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (HasImplicitThisParam) { if (ArgIdx == 0) { - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), diag::err_format_attribute_implicit_this_format_string) << IdxExpr->getSourceRange(); return; @@ -3338,7 +3310,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (Kind == CFStringFormat) { if (!isCFStringType(Ty, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a CFString" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); return; @@ -3347,23 +3319,23 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // FIXME: do we need to check if the type is NSString*? What are the // semantics? if (!isNSStringType(Ty, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "an NSString" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); return; } } else if (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a string type" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); return; } // check the 3rd argument - Expr *FirstArgExpr = Attr.getArgAsExpr(2); + Expr *FirstArgExpr = AL.getArgAsExpr(2); uint32_t FirstArg; - if (!checkUInt32Argument(S, Attr, FirstArgExpr, FirstArg, 3)) + if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3)) return; // check if the function is variadic if the 3rd argument non-zero @@ -3380,43 +3352,42 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // variable the input is just the current time + the format string. if (Kind == StrftimeFormat) { if (FirstArg != 0) { - S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter) + S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter) << FirstArgExpr->getSourceRange(); return; } // if 0 it disables parameter checking (to use with e.g. va_list) } else if (FirstArg != 0 && FirstArg != NumArgs) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << 3 << FirstArgExpr->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << 3 << FirstArgExpr->getSourceRange(); return; } - FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), II, + FormatAttr *NewAttr = S.mergeFormatAttr(D, AL.getRange(), II, Idx, FirstArg, - Attr.getAttributeSpellingListIndex()); + AL.getAttributeSpellingListIndex()); if (NewAttr) D->addAttr(NewAttr); } -static void handleTransparentUnionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Try to find the underlying union declaration. RecordDecl *RD = nullptr; - TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); + const auto *TD = dyn_cast<TypedefNameDecl>(D); if (TD && TD->getUnderlyingType()->isUnionType()) RD = TD->getUnderlyingType()->getAsUnionType()->getDecl(); else RD = dyn_cast<RecordDecl>(D); if (!RD || !RD->isUnion()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedUnion; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedUnion; return; } if (!RD->isCompleteDefinition()) { if (!RD->isBeingDefined()) - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_not_definition); return; } @@ -3424,7 +3395,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, RecordDecl::field_iterator Field = RD->field_begin(), FieldEnd = RD->field_end(); if (Field == FieldEnd) { - S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_zero_fields); + S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_zero_fields); return; } @@ -3468,15 +3439,15 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, } RD->addAttr(::new (S.Context) - TransparentUnionAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + TransparentUnionAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Make sure that there is a string literal as the annotation's single // argument. StringRef Str; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; // Don't duplicate annotations that are already set. @@ -3484,16 +3455,15 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (I->getAnnotation() == Str) return; } - + D->addAttr(::new (S.Context) - AnnotateAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + AnnotateAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } -static void handleAlignValueAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - S.AddAlignValueAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), - Attr.getAttributeSpellingListIndex()); +static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.AddAlignValueAttr(AL.getRange(), D, AL.getArgAsExpr(0), + AL.getAttributeSpellingListIndex()); } void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -3502,9 +3472,9 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, SourceLocation AttrLoc = AttrRange.getBegin(); QualType T; - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) T = TD->getUnderlyingType(); - else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + else if (const auto *VD = dyn_cast<ValueDecl>(D)) T = VD->getType(); else llvm_unreachable("Unknown decl type for align_value"); @@ -3541,42 +3511,32 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, D->addAttr(::new (Context) AlignValueAttr(TmpAttr)); } -static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } - if (Attr.getNumArgs() == 0) { - D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, - true, nullptr, Attr.getAttributeSpellingListIndex())); + if (AL.getNumArgs() == 0) { + D->addAttr(::new (S.Context) AlignedAttr(AL.getRange(), S.Context, + true, nullptr, AL.getAttributeSpellingListIndex())); return; } - Expr *E = Attr.getArgAsExpr(0); - if (Attr.isPackExpansion() && !E->containsUnexpandedParameterPack()) { - S.Diag(Attr.getEllipsisLoc(), + Expr *E = AL.getArgAsExpr(0); + if (AL.isPackExpansion() && !E->containsUnexpandedParameterPack()) { + S.Diag(AL.getEllipsisLoc(), diag::err_pack_expansion_without_parameter_packs); return; } - if (!Attr.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E)) + if (!AL.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E)) return; - if (E->isValueDependent()) { - if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) { - if (!TND->getUnderlyingType()->isDependentType()) { - S.Diag(Attr.getLoc(), diag::err_alignment_dependent_typedef_name) - << E->getSourceRange(); - return; - } - } - } - - S.AddAlignedAttr(Attr.getRange(), D, E, Attr.getAttributeSpellingListIndex(), - Attr.isPackExpansion()); + S.AddAlignedAttr(AL.getRange(), D, E, AL.getAttributeSpellingListIndex(), + AL.isPackExpansion()); } void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -3600,12 +3560,12 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, int DiagKind = -1; if (isa<ParmVarDecl>(D)) { DiagKind = 0; - } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + } else if (const auto *VD = dyn_cast<VarDecl>(D)) { if (VD->getStorageClass() == SC_Register) DiagKind = 1; if (VD->isExceptionVariable()) DiagKind = 2; - } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + } else if (const auto *FD = dyn_cast<FieldDecl>(D)) { if (FD->isBitField()) DiagKind = 3; } else if (!isa<TagDecl>(D)) { @@ -3621,7 +3581,18 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, } } - if (E->isTypeDependent() || E->isValueDependent()) { + if (E->isValueDependent()) { + // We can't support a dependent alignment on a non-dependent type, + // because we have no way to model that a type is "alignment-dependent" + // but not dependent in any other way. + if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) { + if (!TND->getUnderlyingType()->isDependentType()) { + Diag(AttrLoc, diag::err_alignment_dependent_typedef_name) + << E->getSourceRange(); + return; + } + } + // Save dependent expressions in the AST to be instantiated. AlignedAttr *AA = ::new (Context) AlignedAttr(TmpAttr); AA->setPackExpansion(IsPackExpansion); @@ -3629,7 +3600,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, return; } - // FIXME: Cache the number on the Attr object? + // FIXME: Cache the number on the AL object? llvm::APSInt Alignment; ExprResult ICE = VerifyIntegerConstantExpression(E, &Alignment, @@ -3667,7 +3638,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, unsigned MaxTLSAlign = Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign()) .getQuantity(); - auto *VD = dyn_cast<VarDecl>(D); + const auto *VD = dyn_cast<VarDecl>(D); if (MaxTLSAlign && AlignVal > MaxTLSAlign && VD && VD->getTLSKind() != VarDecl::TLS_None) { Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) @@ -3684,7 +3655,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS, unsigned SpellingListIndex, bool IsPackExpansion) { - // FIXME: Cache the number on the Attr object if non-dependent? + // FIXME: Cache the number on the AL object if non-dependent? // FIXME: Perform checking of type validity AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, false, TS, SpellingListIndex); @@ -3696,11 +3667,11 @@ void Sema::CheckAlignasUnderalignment(Decl *D) { assert(D->hasAttrs() && "no attributes on decl"); QualType UnderlyingTy, DiagTy; - if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + if (const auto *VD = dyn_cast<ValueDecl>(D)) { UnderlyingTy = DiagTy = VD->getType(); } else { UnderlyingTy = DiagTy = Context.getTagDeclType(cast<TagDecl>(D)); - if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) + if (const auto *ED = dyn_cast<EnumDecl>(D)) UnderlyingTy = ED->getIntegerType(); } if (DiagTy->isDependentType() || DiagTy->isIncompleteType()) @@ -3820,18 +3791,18 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, /// Despite what would be logical, the mode attribute is a decl attribute, not a /// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be /// HImode, not an intermediate pointer. -static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleModeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // This attribute isn't documented, but glibc uses it. It changes // the width of an int or unsigned int to the specified size. - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL.getName() << AANT_ArgumentIdentifier; return; } - IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *Name = AL.getArgAsIdent(0)->Ident; - S.AddModeAttr(Attr.getRange(), D, Name, Attr.getAttributeSpellingListIndex()); + S.AddModeAttr(AL.getRange(), D, Name, AL.getAttributeSpellingListIndex()); } void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, @@ -3877,9 +3848,9 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, } QualType OldTy; - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) OldTy = TD->getUnderlyingType(); - else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + else if (const auto *ED = dyn_cast<EnumDecl>(D)) { // Something like 'typedef enum { X } __attribute__((mode(XX))) T;'. // Try to get type from enum declaration, default to int. OldTy = ED->getIntegerType(); @@ -3897,7 +3868,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, // Base type can also be a vector type (see PR17453). // Distinguish between base type and base element type. QualType OldElemTy = OldTy; - if (const VectorType *VT = OldTy->getAs<VectorType>()) + if (const auto *VT = OldTy->getAs<VectorType>()) OldElemTy = VT->getElementType(); // GCC allows 'mode' attribute on enumeration types (even incomplete), except @@ -3946,7 +3917,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, if (VectorSize.getBoolValue()) { NewTy = Context.getVectorType(NewTy, VectorSize.getZExtValue(), VectorType::GenericVector); - } else if (const VectorType *OldVT = OldTy->getAs<VectorType>()) { + } else if (const auto *OldVT = OldTy->getAs<VectorType>()) { // Complex machine mode does not support base vector types. if (ComplexMode) { Diag(AttrLoc, diag::err_complex_mode_vector_type); @@ -3965,9 +3936,9 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, } // Install the new type. - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + if (auto *TD = dyn_cast<TypedefNameDecl>(D)) TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy); - else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) + else if (auto *ED = dyn_cast<EnumDecl>(D)) ED->setIntegerType(NewTy); else cast<ValueDecl>(D)->setType(NewTy); @@ -3976,10 +3947,10 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, ModeAttr(AttrRange, Context, Name, SpellingListIndex)); } -static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleNoDebugAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) - NoDebugAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + NoDebugAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, @@ -4011,7 +3982,7 @@ InternalLinkageAttr * Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex) { - if (auto VD = dyn_cast<VarDecl>(D)) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { // Attribute applies to Var but not any subclass of it (like ParmVar, // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { @@ -4068,71 +4039,70 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } -static void handleAlwaysInlineAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL.getRange(), + AL.getName())) return; if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr( - D, Attr.getRange(), Attr.getName(), - Attr.getAttributeSpellingListIndex())) + D, AL.getRange(), AL.getName(), + AL.getAttributeSpellingListIndex())) D->addAttr(Inline); } -static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleMinSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (MinSizeAttr *MinSize = S.mergeMinSizeAttr( - D, Attr.getRange(), Attr.getAttributeSpellingListIndex())) + D, AL.getRange(), AL.getAttributeSpellingListIndex())) D->addAttr(MinSize); } -static void handleOptimizeNoneAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr( - D, Attr.getRange(), Attr.getAttributeSpellingListIndex())) + D, AL.getRange(), AL.getAttributeSpellingListIndex())) D->addAttr(Optnone); } -static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL.getRange(), + AL.getName())) return; - auto *VD = cast<VarDecl>(D); + const auto *VD = cast<VarDecl>(D); if (!VD->hasGlobalStorage()) { - S.Diag(Attr.getLoc(), diag::err_cuda_nonglobal_constant); + S.Diag(AL.getLoc(), diag::err_cuda_nonglobal_constant); return; } D->addAttr(::new (S.Context) CUDAConstantAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL.getRange(), + AL.getName())) return; - auto *VD = cast<VarDecl>(D); + const auto *VD = cast<VarDecl>(D); // extern __shared__ is only allowed on arrays with no length (e.g. // "int x[]"). - if (VD->hasExternalStorage() && !isa<IncompleteArrayType>(VD->getType())) { - S.Diag(Attr.getLoc(), diag::err_cuda_extern_shared) << VD; + if (!S.getLangOpts().CUDARelocatableDeviceCode && VD->hasExternalStorage() && + !isa<IncompleteArrayType>(VD->getType())) { + S.Diag(AL.getLoc(), diag::err_cuda_extern_shared) << VD; return; } if (S.getLangOpts().CUDA && VD->hasLocalStorage() && - S.CUDADiagIfHostCode(Attr.getLoc(), diag::err_cuda_host_shared) + S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared) << S.CurrentCUDATarget()) return; D->addAttr(::new (S.Context) CUDASharedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, Attr.getRange(), - Attr.getName()) || - checkAttrMutualExclusion<CUDAHostAttr>(S, D, Attr.getRange(), - Attr.getName())) { +static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, AL.getRange(), + AL.getName()) || + checkAttrMutualExclusion<CUDAHostAttr>(S, D, AL.getRange(), + AL.getName())) { return; } - FunctionDecl *FD = cast<FunctionDecl>(D); + const auto *FD = cast<FunctionDecl>(D); if (!FD->getReturnType()->isVoidType()) { SourceRange RTRange = FD->getReturnTypeSourceRange(); S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) @@ -4154,88 +4124,88 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(FD->getLocStart(), diag::warn_kern_is_inline) << FD; D->addAttr(::new (S.Context) - CUDAGlobalAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + CUDAGlobalAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - FunctionDecl *Fn = cast<FunctionDecl>(D); +static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *Fn = cast<FunctionDecl>(D); if (!Fn->isInlineSpecified()) { - S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); + S.Diag(AL.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); return; } D->addAttr(::new (S.Context) - GNUInlineAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + GNUInlineAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (hasDeclarator(D)) return; - // Diagnostic is emitted elsewhere: here we store the (valid) Attr + // Diagnostic is emitted elsewhere: here we store the (valid) AL // in the Decl node for syntactic reasoning, e.g., pretty-printing. CallingConv CC; - if (S.CheckCallingConvAttr(Attr, CC, /*FD*/nullptr)) + if (S.CheckCallingConvAttr(AL, CC, /*FD*/nullptr)) return; if (!isa<ObjCMethodDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionOrMethod; return; } - switch (Attr.getKind()) { - case AttributeList::AT_FastCall: + switch (AL.getKind()) { + case ParsedAttr::AT_FastCall: D->addAttr(::new (S.Context) - FastCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + FastCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_StdCall: + case ParsedAttr::AT_StdCall: D->addAttr(::new (S.Context) - StdCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + StdCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_ThisCall: + case ParsedAttr::AT_ThisCall: D->addAttr(::new (S.Context) - ThisCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ThisCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_CDecl: + case ParsedAttr::AT_CDecl: D->addAttr(::new (S.Context) - CDeclAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + CDeclAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_Pascal: + case ParsedAttr::AT_Pascal: D->addAttr(::new (S.Context) - PascalAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + PascalAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_SwiftCall: + case ParsedAttr::AT_SwiftCall: D->addAttr(::new (S.Context) - SwiftCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + SwiftCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_VectorCall: + case ParsedAttr::AT_VectorCall: D->addAttr(::new (S.Context) - VectorCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + VectorCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_MSABI: + case ParsedAttr::AT_MSABI: D->addAttr(::new (S.Context) - MSABIAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + MSABIAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_SysVABI: + case ParsedAttr::AT_SysVABI: D->addAttr(::new (S.Context) - SysVABIAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + SysVABIAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_RegCall: + case ParsedAttr::AT_RegCall: D->addAttr(::new (S.Context) RegCallAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_Pcs: { + case ParsedAttr::AT_Pcs: { PcsAttr::PCSType PCS; switch (CC) { case CC_AAPCS: @@ -4249,37 +4219,37 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { } D->addAttr(::new (S.Context) - PcsAttr(Attr.getRange(), S.Context, PCS, - Attr.getAttributeSpellingListIndex())); + PcsAttr(AL.getRange(), S.Context, PCS, + AL.getAttributeSpellingListIndex())); return; } - case AttributeList::AT_IntelOclBicc: + case ParsedAttr::AT_IntelOclBicc: D->addAttr(::new (S.Context) - IntelOclBiccAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + IntelOclBiccAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_PreserveMost: + case ParsedAttr::AT_PreserveMost: D->addAttr(::new (S.Context) PreserveMostAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_PreserveAll: + case ParsedAttr::AT_PreserveAll: D->addAttr(::new (S.Context) PreserveAllAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; default: llvm_unreachable("unexpected attribute kind"); } } -static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; std::vector<StringRef> DiagnosticIdentifiers; - for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef RuleName; - if (!S.checkStringLiteralArgumentAttr(Attr, I, RuleName, nullptr)) + if (!S.checkStringLiteralArgumentAttr(AL, I, RuleName, nullptr)) return; // FIXME: Warn if the rule name is unknown. This is tricky because only @@ -4287,11 +4257,11 @@ static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) { DiagnosticIdentifiers.push_back(RuleName); } D->addAttr(::new (S.Context) SuppressAttr( - Attr.getRange(), S.Context, DiagnosticIdentifiers.data(), - DiagnosticIdentifiers.size(), Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, DiagnosticIdentifiers.data(), + DiagnosticIdentifiers.size(), AL.getAttributeSpellingListIndex())); } -bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, +bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, const FunctionDecl *FD) { if (Attrs.isInvalid()) return true; @@ -4301,7 +4271,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, return false; } - unsigned ReqArgs = Attrs.getKind() == AttributeList::AT_Pcs ? 1 : 0; + unsigned ReqArgs = Attrs.getKind() == ParsedAttr::AT_Pcs ? 1 : 0; if (!checkAttributeNumArgs(*this, Attrs, ReqArgs)) { Attrs.setInvalid(); return true; @@ -4309,23 +4279,39 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, // TODO: diagnose uses of these conventions on the wrong target. switch (Attrs.getKind()) { - case AttributeList::AT_CDecl: CC = CC_C; break; - case AttributeList::AT_FastCall: CC = CC_X86FastCall; break; - case AttributeList::AT_StdCall: CC = CC_X86StdCall; break; - case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break; - case AttributeList::AT_Pascal: CC = CC_X86Pascal; break; - case AttributeList::AT_SwiftCall: CC = CC_Swift; break; - case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break; - case AttributeList::AT_RegCall: CC = CC_X86RegCall; break; - case AttributeList::AT_MSABI: + case ParsedAttr::AT_CDecl: + CC = CC_C; + break; + case ParsedAttr::AT_FastCall: + CC = CC_X86FastCall; + break; + case ParsedAttr::AT_StdCall: + CC = CC_X86StdCall; + break; + case ParsedAttr::AT_ThisCall: + CC = CC_X86ThisCall; + break; + case ParsedAttr::AT_Pascal: + CC = CC_X86Pascal; + break; + case ParsedAttr::AT_SwiftCall: + CC = CC_Swift; + break; + case ParsedAttr::AT_VectorCall: + CC = CC_X86VectorCall; + break; + case ParsedAttr::AT_RegCall: + CC = CC_X86RegCall; + break; + case ParsedAttr::AT_MSABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : CC_Win64; break; - case AttributeList::AT_SysVABI: + case ParsedAttr::AT_SysVABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV : CC_C; break; - case AttributeList::AT_Pcs: { + case ParsedAttr::AT_Pcs: { StringRef StrRef; if (!checkStringLiteralArgumentAttr(Attrs, 0, StrRef)) { Attrs.setInvalid(); @@ -4343,9 +4329,15 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, Diag(Attrs.getLoc(), diag::err_invalid_pcs); return true; } - case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break; - case AttributeList::AT_PreserveMost: CC = CC_PreserveMost; break; - case AttributeList::AT_PreserveAll: CC = CC_PreserveAll; break; + case ParsedAttr::AT_IntelOclBicc: + CC = CC_IntelOclBicc; + break; + case ParsedAttr::AT_PreserveMost: + CC = CC_PreserveMost; + break; + case ParsedAttr::AT_PreserveAll: + CC = CC_PreserveAll; + break; default: llvm_unreachable("unexpected attribute kind"); } @@ -4370,39 +4362,39 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, } /// Pointer-like types in the default address space. -static bool isValidSwiftContextType(QualType type) { - if (!type->hasPointerRepresentation()) - return type->isDependentType(); - return type->getPointeeType().getAddressSpace() == LangAS::Default; +static bool isValidSwiftContextType(QualType Ty) { + if (!Ty->hasPointerRepresentation()) + return Ty->isDependentType(); + return Ty->getPointeeType().getAddressSpace() == LangAS::Default; } /// Pointers and references in the default address space. -static bool isValidSwiftIndirectResultType(QualType type) { - if (auto ptrType = type->getAs<PointerType>()) { - type = ptrType->getPointeeType(); - } else if (auto refType = type->getAs<ReferenceType>()) { - type = refType->getPointeeType(); +static bool isValidSwiftIndirectResultType(QualType Ty) { + if (const auto *PtrType = Ty->getAs<PointerType>()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs<ReferenceType>()) { + Ty = RefType->getPointeeType(); } else { - return type->isDependentType(); + return Ty->isDependentType(); } - return type.getAddressSpace() == LangAS::Default; + return Ty.getAddressSpace() == LangAS::Default; } /// Pointers and references to pointers in the default address space. -static bool isValidSwiftErrorResultType(QualType type) { - if (auto ptrType = type->getAs<PointerType>()) { - type = ptrType->getPointeeType(); - } else if (auto refType = type->getAs<ReferenceType>()) { - type = refType->getPointeeType(); +static bool isValidSwiftErrorResultType(QualType Ty) { + if (const auto *PtrType = Ty->getAs<PointerType>()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs<ReferenceType>()) { + Ty = RefType->getPointeeType(); } else { - return type->isDependentType(); + return Ty->isDependentType(); } - if (!type.getQualifiers().empty()) + if (!Ty.getQualifiers().empty()) return false; - return isValidSwiftContextType(type); + return isValidSwiftContextType(Ty); } -static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &Attrs, +static void handleParameterABIAttr(Sema &S, Decl *D, const ParsedAttr &Attrs, ParameterABI Abi) { S.AddParameterABIAttr(Attrs.getRange(), D, Abi, Attrs.getAttributeSpellingListIndex()); @@ -4461,34 +4453,34 @@ void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi, /// Checks a regparm attribute, returning true if it is ill-formed and /// otherwise setting numParams to the appropriate value. -bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { - if (Attr.isInvalid()) +bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { + if (AL.isInvalid()) return true; - if (!checkAttributeNumArgs(*this, Attr, 1)) { - Attr.setInvalid(); + if (!checkAttributeNumArgs(*this, AL, 1)) { + AL.setInvalid(); return true; } uint32_t NP; - Expr *NumParamsExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(*this, Attr, NumParamsExpr, NP)) { - Attr.setInvalid(); + Expr *NumParamsExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(*this, AL, NumParamsExpr, NP)) { + AL.setInvalid(); return true; } if (Context.getTargetInfo().getRegParmMax() == 0) { - Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform) + Diag(AL.getLoc(), diag::err_attribute_regparm_wrong_platform) << NumParamsExpr->getSourceRange(); - Attr.setInvalid(); + AL.setInvalid(); return true; } numParams = NP; if (numParams > Context.getTargetInfo().getRegParmMax()) { - Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number) + Diag(AL.getLoc(), diag::err_attribute_regparm_invalid_number) << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange(); - Attr.setInvalid(); + AL.setInvalid(); return true; } @@ -4500,7 +4492,7 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { // non-nullptr Expr result on success. Otherwise, it returns nullptr // and may output an error. static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, - const CUDALaunchBoundsAttr &Attr, + const CUDALaunchBoundsAttr &AL, const unsigned Idx) { if (S.DiagnoseUnexpandedParameterPack(E)) return nullptr; @@ -4513,7 +4505,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, llvm::APSInt I(64); if (!E->isIntegerConstantExpr(I, S.Context)) { S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) - << &Attr << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); + << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); return nullptr; } // Make sure we can fit it in 32 bits. @@ -4524,7 +4516,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, } if (I < 0) S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) - << &Attr << Idx << E->getSourceRange(); + << &AL << Idx << E->getSourceRange(); // We may need to perform implicit conversion of the argument. InitializedEntity Entity = InitializedEntity::InitializeParameter( @@ -4554,253 +4546,232 @@ void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex)); } -static void handleLaunchBoundsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1) || - !checkAttributeAtMostNumArgs(S, Attr, 2)) +static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1) || + !checkAttributeAtMostNumArgs(S, AL, 2)) return; - S.AddLaunchBoundsAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), - Attr.getNumArgs() > 1 ? Attr.getArgAsExpr(1) : nullptr, - Attr.getAttributeSpellingListIndex()); + S.AddLaunchBoundsAttr(AL.getRange(), D, AL.getArgAsExpr(0), + AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr, + AL.getAttributeSpellingListIndex()); } static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier; - return; - } - - if (!checkAttributeNumArgs(S, Attr, 3)) - return; - - IdentifierInfo *ArgumentKind = Attr.getArgAsIdent(0)->Ident; - - if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier; return; } - uint64_t ArgumentIdx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 2, Attr.getArgAsExpr(1), + ParamIdx ArgumentIdx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, AL.getArgAsExpr(1), ArgumentIdx)) return; - uint64_t TypeTagIdx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 3, Attr.getArgAsExpr(2), + ParamIdx TypeTagIdx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 3, AL.getArgAsExpr(2), TypeTagIdx)) return; - bool IsPointer = (Attr.getName()->getName() == "pointer_with_type_tag"); + bool IsPointer = AL.getName()->getName() == "pointer_with_type_tag"; if (IsPointer) { // Ensure that buffer has a pointer type. - QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx); - if (!BufferTy->isPointerType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) - << Attr.getName() << 0; - } + unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex(); + if (ArgumentIdxAST >= getFunctionOrMethodNumParams(D) || + !getFunctionOrMethodParamType(D, ArgumentIdxAST)->isPointerType()) + S.Diag(AL.getLoc(), diag::err_attribute_pointers_only) + << AL.getName() << 0; } - D->addAttr(::new (S.Context) - ArgumentWithTypeTagAttr(Attr.getRange(), S.Context, ArgumentKind, - ArgumentIdx, TypeTagIdx, IsPointer, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr( + AL.getRange(), S.Context, AL.getArgAsIdent(0)->Ident, ArgumentIdx, + TypeTagIdx, IsPointer, AL.getAttributeSpellingListIndex())); } static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } - - if (!checkAttributeNumArgs(S, Attr, 1)) + + if (!checkAttributeNumArgs(S, AL, 1)) return; if (!isa<VarDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariable; + S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type) + << AL.getName() << ExpectedVariable; return; } - IdentifierInfo *PointerKind = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *PointerKind = AL.getArgAsIdent(0)->Ident; TypeSourceInfo *MatchingCTypeLoc = nullptr; - S.GetTypeFromParser(Attr.getMatchingCType(), &MatchingCTypeLoc); + S.GetTypeFromParser(AL.getMatchingCType(), &MatchingCTypeLoc); assert(MatchingCTypeLoc && "no type source info for attribute argument"); D->addAttr(::new (S.Context) - TypeTagForDatatypeAttr(Attr.getRange(), S.Context, PointerKind, + TypeTagForDatatypeAttr(AL.getRange(), S.Context, PointerKind, MatchingCTypeLoc, - Attr.getLayoutCompatible(), - Attr.getMustBeNull(), - Attr.getAttributeSpellingListIndex())); + AL.getLayoutCompatible(), + AL.getMustBeNull(), + AL.getAttributeSpellingListIndex())); } -static void handleXRayLogArgsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - uint64_t ArgCount; +static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + ParamIdx ArgCount; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, Attr.getArgAsExpr(0), + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, AL.getArgAsExpr(0), ArgCount, - true /* AllowImplicitThis*/)) + true /* CanIndexImplicitThis */)) return; - // ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1. - D->addAttr(::new (S.Context) - XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount, - Attr.getAttributeSpellingListIndex())); + // ArgCount isn't a parameter index [0;n), it's a count [1;n] + D->addAttr(::new (S.Context) XRayLogArgsAttr( + AL.getRange(), S.Context, ArgCount.getSourceIndex(), + AL.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// -static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType type) { - return type->isDependentType() || - type->isObjCRetainableType(); +static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) { + return QT->isDependentType() || QT->isObjCRetainableType(); } -static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { - return type->isDependentType() || - type->isObjCObjectPointerType() || - S.Context.isObjCNSObjectType(type); +static bool isValidSubjectOfNSAttribute(Sema &S, QualType QT) { + return QT->isDependentType() || QT->isObjCObjectPointerType() || + S.Context.isObjCNSObjectType(QT); } -static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { - return type->isDependentType() || - type->isPointerType() || - isValidSubjectOfNSAttribute(S, type); +static bool isValidSubjectOfCFAttribute(Sema &S, QualType QT) { + return QT->isDependentType() || QT->isPointerType() || + isValidSubjectOfNSAttribute(S, QT); } -static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.AddNSConsumedAttr(Attr.getRange(), D, Attr.getAttributeSpellingListIndex(), - Attr.getKind() == AttributeList::AT_NSConsumed, +static void handleNSConsumedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.AddNSConsumedAttr(AL.getRange(), D, AL.getAttributeSpellingListIndex(), + AL.getKind() == ParsedAttr::AT_NSConsumed, /*template instantiation*/ false); } -void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D, - unsigned spellingIndex, bool isNSConsumed, - bool isTemplateInstantiation) { - ParmVarDecl *param = cast<ParmVarDecl>(D); - bool typeOK; +void Sema::AddNSConsumedAttr(SourceRange AttrRange, Decl *D, + unsigned SpellingIndex, bool IsNSConsumed, + bool IsTemplateInstantiation) { + const auto *Param = cast<ParmVarDecl>(D); + bool TypeOK; - if (isNSConsumed) { - typeOK = isValidSubjectOfNSAttribute(*this, param->getType()); - } else { - typeOK = isValidSubjectOfCFAttribute(*this, param->getType()); - } + if (IsNSConsumed) + TypeOK = isValidSubjectOfNSAttribute(*this, Param->getType()); + else + TypeOK = isValidSubjectOfCFAttribute(*this, Param->getType()); - if (!typeOK) { + if (!TypeOK) { // These attributes are normally just advisory, but in ARC, ns_consumed // is significant. Allow non-dependent code to contain inappropriate // attributes even in ARC, but require template instantiations to be // set up correctly. - Diag(D->getLocStart(), - (isTemplateInstantiation && isNSConsumed && - getLangOpts().ObjCAutoRefCount - ? diag::err_ns_attribute_wrong_parameter_type - : diag::warn_ns_attribute_wrong_parameter_type)) - << attrRange - << (isNSConsumed ? "ns_consumed" : "cf_consumed") - << (isNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); + Diag(D->getLocStart(), (IsTemplateInstantiation && IsNSConsumed && + getLangOpts().ObjCAutoRefCount + ? diag::err_ns_attribute_wrong_parameter_type + : diag::warn_ns_attribute_wrong_parameter_type)) + << AttrRange << (IsNSConsumed ? "ns_consumed" : "cf_consumed") + << (IsNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); return; } - if (isNSConsumed) - param->addAttr(::new (Context) - NSConsumedAttr(attrRange, Context, spellingIndex)); + if (IsNSConsumed) + D->addAttr(::new (Context) + NSConsumedAttr(AttrRange, Context, SpellingIndex)); else - param->addAttr(::new (Context) - CFConsumedAttr(attrRange, Context, spellingIndex)); + D->addAttr(::new (Context) + CFConsumedAttr(AttrRange, Context, SpellingIndex)); } -bool Sema::checkNSReturnsRetainedReturnType(SourceLocation loc, - QualType type) { - if (isValidSubjectOfNSReturnsRetainedAttribute(type)) +bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) { + if (isValidSubjectOfNSReturnsRetainedAttribute(QT)) return false; - Diag(loc, diag::warn_ns_attribute_wrong_return_type) - << "'ns_returns_retained'" << 0 << 0; + Diag(Loc, diag::warn_ns_attribute_wrong_return_type) + << "'ns_returns_retained'" << 0 << 0; return true; } static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - QualType returnType; + const ParsedAttr &AL) { + QualType ReturnType; - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) - returnType = MD->getReturnType(); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + ReturnType = MD->getReturnType(); else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && - (Attr.getKind() == AttributeList::AT_NSReturnsRetained)) + (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) return; // ignore: was handled as a type attribute - else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) - returnType = PD->getType(); - else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - returnType = FD->getReturnType(); - else if (auto *Param = dyn_cast<ParmVarDecl>(D)) { - returnType = Param->getType()->getPointeeType(); - if (returnType.isNull()) { + else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) + ReturnType = PD->getType(); + else if (const auto *FD = dyn_cast<FunctionDecl>(D)) + ReturnType = FD->getReturnType(); + else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) { + ReturnType = Param->getType()->getPointeeType(); + if (ReturnType.isNull()) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << Attr.getName() << /*pointer-to-CF*/2 - << Attr.getRange(); + << AL.getName() << /*pointer-to-CF*/2 + << AL.getRange(); return; } - } else if (Attr.isUsedAsTypeAttr()) { + } else if (AL.isUsedAsTypeAttr()) { return; } else { AttributeDeclKind ExpectedDeclKind; - switch (Attr.getKind()) { + switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsRetained: - case AttributeList::AT_NSReturnsAutoreleased: - case AttributeList::AT_NSReturnsNotRetained: + case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: ExpectedDeclKind = ExpectedFunctionOrMethod; break; - case AttributeList::AT_CFReturnsRetained: - case AttributeList::AT_CFReturnsNotRetained: + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: ExpectedDeclKind = ExpectedFunctionMethodOrParameter; break; } S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedDeclKind; + << AL.getRange() << AL.getName() << ExpectedDeclKind; return; } - bool typeOK; - bool cf; - switch (Attr.getKind()) { + bool TypeOK; + bool Cf; + switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsRetained: - typeOK = isValidSubjectOfNSReturnsRetainedAttribute(returnType); - cf = false; + case ParsedAttr::AT_NSReturnsRetained: + TypeOK = isValidSubjectOfNSReturnsRetainedAttribute(ReturnType); + Cf = false; break; - - case AttributeList::AT_NSReturnsAutoreleased: - case AttributeList::AT_NSReturnsNotRetained: - typeOK = isValidSubjectOfNSAttribute(S, returnType); - cf = false; + + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: + TypeOK = isValidSubjectOfNSAttribute(S, ReturnType); + Cf = false; break; - case AttributeList::AT_CFReturnsRetained: - case AttributeList::AT_CFReturnsNotRetained: - typeOK = isValidSubjectOfCFAttribute(S, returnType); - cf = true; + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + TypeOK = isValidSubjectOfCFAttribute(S, ReturnType); + Cf = true; break; } - if (!typeOK) { - if (Attr.isUsedAsTypeAttr()) + if (!TypeOK) { + if (AL.isUsedAsTypeAttr()) return; if (isa<ParmVarDecl>(D)) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << Attr.getName() << /*pointer-to-CF*/2 - << Attr.getRange(); + << AL.getName() << /*pointer-to-CF*/2 + << AL.getRange(); } else { // Needs to be kept in sync with warn_ns_attribute_wrong_return_type. enum : unsigned { @@ -4813,43 +4784,43 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, else if (isa<ObjCPropertyDecl>(D)) SubjectKind = Property; S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << Attr.getName() << SubjectKind << cf - << Attr.getRange(); + << AL.getName() << SubjectKind << Cf + << AL.getRange(); } return; } - switch (Attr.getKind()) { + switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsAutoreleased: D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_CFReturnsNotRetained: + case ParsedAttr::AT_CFReturnsNotRetained: D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_NSReturnsNotRetained: + case ParsedAttr::AT_NSReturnsNotRetained: D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsRetained: D->addAttr(::new (S.Context) CFReturnsRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_NSReturnsRetained: + case ParsedAttr::AT_NSReturnsRetained: D->addAttr(::new (S.Context) NSReturnsRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; }; } static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, - const AttributeList &Attrs) { + const ParsedAttr &Attrs) { const int EP_ObjCMethod = 1; const int EP_ObjCProperty = 2; - + SourceLocation loc = Attrs.getLoc(); QualType resultType; if (isa<ObjCMethodDecl>(D)) @@ -4874,116 +4845,91 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, } static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, - const AttributeList &Attrs) { - ObjCMethodDecl *method = cast<ObjCMethodDecl>(D); - - DeclContext *DC = method->getDeclContext(); - if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { + const ParsedAttr &Attrs) { + const auto *Method = cast<ObjCMethodDecl>(D); + + const DeclContext *DC = Method->getDeclContext(); + if (const auto *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << Attrs.getName() << 0; + << Attrs.getName() << 0; S.Diag(PDecl->getLocation(), diag::note_protocol_decl); return; } - if (method->getMethodFamily() == OMF_dealloc) { + if (Method->getMethodFamily() == OMF_dealloc) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << Attrs.getName() << 1; + << Attrs.getName() << 1; return; } - - method->addAttr(::new (S.Context) - ObjCRequiresSuperAttr(Attrs.getRange(), S.Context, - Attrs.getAttributeSpellingListIndex())); -} -static void handleCFAuditedTransferAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) - CFAuditedTransferAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleCFUnknownTransferAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) - CFUnknownTransferAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCRequiresSuperAttr( + Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); } -static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { - IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; +static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; if (!Parm) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; return; } // Typedefs only allow objc_bridge(id) and have some additional checking. - if (auto TD = dyn_cast<TypedefNameDecl>(D)) { + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { if (!Parm->Ident->isStr("id")) { - S.Diag(Attr.getLoc(), diag::err_objc_attr_typedef_not_id) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) + << AL.getName(); return; } // Only allow 'cv void *'. QualType T = TD->getUnderlyingType(); if (!T->isVoidPointerType()) { - S.Diag(Attr.getLoc(), diag::err_objc_attr_typedef_not_void_pointer); + S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_void_pointer); return; } } - + D->addAttr(::new (S.Context) - ObjCBridgeAttr(Attr.getRange(), S.Context, Parm->Ident, - Attr.getAttributeSpellingListIndex())); + ObjCBridgeAttr(AL.getRange(), S.Context, Parm->Ident, + AL.getAttributeSpellingListIndex())); } -static void handleObjCBridgeMutableAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { - IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; +static void handleObjCBridgeMutableAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; if (!Parm) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; return; } - + D->addAttr(::new (S.Context) - ObjCBridgeMutableAttr(Attr.getRange(), S.Context, Parm->Ident, - Attr.getAttributeSpellingListIndex())); + ObjCBridgeMutableAttr(AL.getRange(), S.Context, Parm->Ident, + AL.getAttributeSpellingListIndex())); } -static void handleObjCBridgeRelatedAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { +static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { IdentifierInfo *RelatedClass = - Attr.isArgIdent(0) ? Attr.getArgAsIdent(0)->Ident : nullptr; + AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr; if (!RelatedClass) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; return; } IdentifierInfo *ClassMethod = - Attr.getArgAsIdent(1) ? Attr.getArgAsIdent(1)->Ident : nullptr; + AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr; IdentifierInfo *InstanceMethod = - Attr.getArgAsIdent(2) ? Attr.getArgAsIdent(2)->Ident : nullptr; + AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr; D->addAttr(::new (S.Context) - ObjCBridgeRelatedAttr(Attr.getRange(), S.Context, RelatedClass, + ObjCBridgeRelatedAttr(AL.getRange(), S.Context, RelatedClass, ClassMethod, InstanceMethod, - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleObjCDesignatedInitializer(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { ObjCInterfaceDecl *IFace; - if (ObjCCategoryDecl *CatDecl = - dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) + if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) IFace = CatDecl->getClassInterface(); else IFace = cast<ObjCInterfaceDecl>(D->getDeclContext()); @@ -4993,29 +4939,28 @@ static void handleObjCDesignatedInitializer(Sema &S, Decl *D, IFace->setHasDesignatedInitializers(); D->addAttr(::new (S.Context) - ObjCDesignatedInitializerAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCDesignatedInitializerAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleObjCRuntimeName(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef MetaDataName; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, MetaDataName)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName)) return; D->addAttr(::new (S.Context) - ObjCRuntimeNameAttr(Attr.getRange(), S.Context, + ObjCRuntimeNameAttr(AL.getRange(), S.Context, MetaDataName, - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } // When a user wants to use objc_boxable with a union or struct // but they don't have access to the declaration (legacy/third-party code) // then they can 'enable' this feature with a typedef: // typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct; -static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) { bool notify = false; - RecordDecl *RD = dyn_cast<RecordDecl>(D); + auto *RD = dyn_cast<RecordDecl>(D); if (RD && RD->getDefinition()) { RD = RD->getDefinition(); notify = true; @@ -5023,8 +4968,8 @@ static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { if (RD) { ObjCBoxableAttr *BoxableAttr = ::new (S.Context) - ObjCBoxableAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex()); + ObjCBoxableAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex()); RD->addAttr(BoxableAttr); if (notify) { // we need to notify ASTReader/ASTWriter about @@ -5035,36 +4980,35 @@ static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { } } -static void handleObjCOwnershipAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (hasDeclarator(D)) return; S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedVariable; + << AL.getRange() << AL.getName() << ExpectedVariable; } static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - ValueDecl *vd = cast<ValueDecl>(D); - QualType type = vd->getType(); + const ParsedAttr &AL) { + const auto *VD = cast<ValueDecl>(D); + QualType QT = VD->getType(); - if (!type->isDependentType() && - !type->isObjCLifetimeType()) { - S.Diag(Attr.getLoc(), diag::err_objc_precise_lifetime_bad_type) - << type; + if (!QT->isDependentType() && + !QT->isObjCLifetimeType()) { + S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type) + << QT; return; } - Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime(); + Qualifiers::ObjCLifetime Lifetime = QT.getObjCLifetime(); // If we have no lifetime yet, check the lifetime we're presumably // going to infer. - if (lifetime == Qualifiers::OCL_None && !type->isDependentType()) - lifetime = type->getObjCARCImplicitLifetime(); + if (Lifetime == Qualifiers::OCL_None && !QT->isDependentType()) + Lifetime = QT->getObjCARCImplicitLifetime(); - switch (lifetime) { + switch (Lifetime) { case Qualifiers::OCL_None: - assert(type->isDependentType() && + assert(QT->isDependentType() && "didn't infer lifetime for non-dependent type?"); break; @@ -5074,14 +5018,14 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: - S.Diag(Attr.getLoc(), diag::warn_objc_precise_lifetime_meaningless) - << (lifetime == Qualifiers::OCL_Autoreleasing); + S.Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless) + << (Lifetime == Qualifiers::OCL_Autoreleasing); break; } D->addAttr(::new (S.Context) - ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCPreciseLifetimeAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// @@ -5101,16 +5045,16 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range, return ::new (Context) UuidAttr(Range, Context, Uuid, AttrSpellingListIndex); } -static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::C; + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL.getName() << AttributeLangSupport::C; return; } StringRef StrRef; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, StrRef, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, StrRef, &LiteralLoc)) return; // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or @@ -5142,162 +5086,158 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { // separating attributes nor of the [ and the ] are in the AST. // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc" // on cfe-dev. - if (Attr.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. - S.Diag(Attr.getLoc(), diag::warn_atl_uuid_deprecated); + if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. + S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated); - UuidAttr *UA = S.mergeUuidAttr(D, Attr.getRange(), - Attr.getAttributeSpellingListIndex(), StrRef); + UuidAttr *UA = S.mergeUuidAttr(D, AL.getRange(), + AL.getAttributeSpellingListIndex(), StrRef); if (UA) D->addAttr(UA); } -static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::C; + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL.getName() << AttributeLangSupport::C; return; } MSInheritanceAttr *IA = S.mergeMSInheritanceAttr( - D, Attr.getRange(), /*BestCase=*/true, - Attr.getAttributeSpellingListIndex(), - (MSInheritanceAttr::Spelling)Attr.getSemanticSpelling()); + D, AL.getRange(), /*BestCase=*/true, + AL.getAttributeSpellingListIndex(), + (MSInheritanceAttr::Spelling)AL.getSemanticSpelling()); if (IA) { D->addAttr(IA); S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D)); } } -static void handleDeclspecThreadAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - VarDecl *VD = cast<VarDecl>(D); +static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *VD = cast<VarDecl>(D); if (!S.Context.getTargetInfo().isTLSSupported()) { - S.Diag(Attr.getLoc(), diag::err_thread_unsupported); + S.Diag(AL.getLoc(), diag::err_thread_unsupported); return; } if (VD->getTSCSpec() != TSCS_unspecified) { - S.Diag(Attr.getLoc(), diag::err_declspec_thread_on_thread_variable); + S.Diag(AL.getLoc(), diag::err_declspec_thread_on_thread_variable); return; } if (VD->hasLocalStorage()) { - S.Diag(Attr.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; + S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; return; } - VD->addAttr(::new (S.Context) ThreadAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ThreadAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleAbiTagAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SmallVector<StringRef, 4> Tags; - for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef Tag; - if (!S.checkStringLiteralArgumentAttr(Attr, I, Tag)) + if (!S.checkStringLiteralArgumentAttr(AL, I, Tag)) return; Tags.push_back(Tag); } if (const auto *NS = dyn_cast<NamespaceDecl>(D)) { if (!NS->isInline()) { - S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 0; + S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 0; return; } if (NS->isAnonymousNamespace()) { - S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; + S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; return; } - if (Attr.getNumArgs() == 0) + if (AL.getNumArgs() == 0) Tags.push_back(NS->getName()); - } else if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + } else if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; // Store tags sorted and without duplicates. - std::sort(Tags.begin(), Tags.end()); + llvm::sort(Tags.begin(), Tags.end()); Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); D->addAttr(::new (S.Context) - AbiTagAttr(Attr.getRange(), S.Context, Tags.data(), Tags.size(), - Attr.getAttributeSpellingListIndex())); + AbiTagAttr(AL.getRange(), S.Context, Tags.data(), Tags.size(), + AL.getAttributeSpellingListIndex())); } -static void handleARMInterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) + << AL.getName() << 1; return; } StringRef Str; SourceLocation ArgLoc; - if (Attr.getNumArgs() == 0) + if (AL.getNumArgs() == 0) Str = ""; - else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) + else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; ARMInterruptAttr::InterruptType Kind; if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << Str << ArgLoc; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << Str << ArgLoc; return; } - unsigned Index = Attr.getAttributeSpellingListIndex(); + unsigned Index = AL.getAttributeSpellingListIndex(); D->addAttr(::new (S.Context) - ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index)); + ARMInterruptAttr(AL.getLoc(), S.Context, Kind, Index)); } -static void handleMSP430InterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) +static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeNumArgs(S, AL, 1)) return; - if (!Attr.isArgExpr(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() + if (!AL.isArgExpr(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL.getName() << AANT_ArgumentIntegerConstant; - return; + return; } // FIXME: Check for decl - it should be void ()(void). - Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); + Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); llvm::APSInt NumParams(32); if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentIntegerConstant << NumParamsExpr->getSourceRange(); return; } unsigned Num = NumParams.getLimitedValue(255); if ((Num & 1) || Num > 30) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << (int)NumParams.getSExtValue() + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << (int)NumParams.getSExtValue() << NumParamsExpr->getSourceRange(); return; } D->addAttr(::new (S.Context) - MSP430InterruptAttr(Attr.getLoc(), S.Context, Num, - Attr.getAttributeSpellingListIndex())); + MSP430InterruptAttr(AL.getLoc(), S.Context, Num, + AL.getAttributeSpellingListIndex())); D->addAttr(UsedAttr::CreateImplicit(S.Context)); } -static void handleMipsInterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Only one optional argument permitted. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) + << AL.getName() << 1; return; } StringRef Str; SourceLocation ArgLoc; - if (Attr.getNumArgs() == 0) + if (AL.getNumArgs() == 0) Str = ""; - else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) + else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; // Semantic checks for a function with the 'interrupt' attribute for MIPS: @@ -5327,23 +5267,22 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, return; } - if (checkAttrMutualExclusion<Mips16Attr>(S, D, Attr.getRange(), - Attr.getName())) + if (checkAttrMutualExclusion<Mips16Attr>(S, D, AL.getRange(), + AL.getName())) return; MipsInterruptAttr::InterruptType Kind; if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << "'" + std::string(Str) + "'"; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << "'" + std::string(Str) + "'"; return; } D->addAttr(::new (S.Context) MipsInterruptAttr( - Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex())); + AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex())); } -static void handleAnyX86InterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Semantic checks for a function with the 'interrupt' attribute. // a) Must be a function. // b) Must have the 'void' return type. @@ -5353,8 +5292,8 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) || CXXMethodDecl::isStaticOverloadedOperator( cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionWithProtoType; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionWithProtoType; return; } // Interrupt handler must have void return type. @@ -5404,182 +5343,241 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, return; } D->addAttr(::new (S.Context) AnyX86InterruptAttr( - Attr.getLoc(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getLoc(), S.Context, AL.getAttributeSpellingListIndex())); D->addAttr(UsedAttr::CreateImplicit(S.Context)); } -static void handleAVRInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << "'interrupt'" << ExpectedFunction; return; } - if (!checkAttributeNumArgs(S, Attr, 0)) + if (!checkAttributeNumArgs(S, AL, 0)) return; - handleSimpleAttribute<AVRInterruptAttr>(S, D, Attr); + handleSimpleAttribute<AVRInterruptAttr>(S, D, AL); } -static void handleAVRSignalAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << "'signal'" << ExpectedFunction; return; } - if (!checkAttributeNumArgs(S, Attr, 0)) + if (!checkAttributeNumArgs(S, AL, 0)) return; - handleSimpleAttribute<AVRSignalAttr>(S, D, Attr); + handleSimpleAttribute<AVRSignalAttr>(S, D, AL); } -static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { + +static void handleRISCVInterruptAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + // Warn about repeated attributes. + if (const auto *A = D->getAttr<RISCVInterruptAttr>()) { + S.Diag(AL.getRange().getBegin(), + diag::warn_riscv_repeated_interrupt_attribute); + S.Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute); + return; + } + + // Check the attribute argument. Argument is optional. + if (!checkAttributeAtMostNumArgs(S, AL, 1)) + return; + + StringRef Str; + SourceLocation ArgLoc; + + // 'machine'is the default interrupt mode. + if (AL.getNumArgs() == 0) + Str = "machine"; + else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + // Semantic checks for a function with the 'interrupt' attribute: + // - Must be a function. + // - Must have no parameters. + // - Must have the 'void' return type. + // - The attribute itself must either have no argument or one of the + // valid interrupt types, see [RISCVInterruptDocs]. + + if (D->getFunctionType() == nullptr) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'interrupt'" << ExpectedFunction; + return; + } + + if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { + S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 0; + return; + } + + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 1; + return; + } + + RISCVInterruptAttr::InterruptType Kind; + if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << Str << ArgLoc; + return; + } + + D->addAttr(::new (S.Context) RISCVInterruptAttr( + AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex())); +} + +static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Dispatch the interrupt attribute based on the current target. switch (S.Context.getTargetInfo().getTriple().getArch()) { case llvm::Triple::msp430: - handleMSP430InterruptAttr(S, D, Attr); + handleMSP430InterruptAttr(S, D, AL); break; case llvm::Triple::mipsel: case llvm::Triple::mips: - handleMipsInterruptAttr(S, D, Attr); + handleMipsInterruptAttr(S, D, AL); break; case llvm::Triple::x86: case llvm::Triple::x86_64: - handleAnyX86InterruptAttr(S, D, Attr); + handleAnyX86InterruptAttr(S, D, AL); break; case llvm::Triple::avr: - handleAVRInterruptAttr(S, D, Attr); + handleAVRInterruptAttr(S, D, AL); + break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + handleRISCVInterruptAttr(S, D, AL); break; default: - handleARMInterruptAttr(S, D, Attr); + handleARMInterruptAttr(S, D, AL); break; } } static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { uint32_t Min = 0; - Expr *MinExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, MinExpr, Min)) + Expr *MinExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, MinExpr, Min)) return; uint32_t Max = 0; - Expr *MaxExpr = Attr.getArgAsExpr(1); - if (!checkUInt32Argument(S, Attr, MaxExpr, Max)) + Expr *MaxExpr = AL.getArgAsExpr(1); + if (!checkUInt32Argument(S, AL, MaxExpr, Max)) return; if (Min == 0 && Max != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 0; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 0; return; } if (Min > Max) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 1; return; } D->addAttr(::new (S.Context) - AMDGPUFlatWorkGroupSizeAttr(Attr.getLoc(), S.Context, Min, Max, - Attr.getAttributeSpellingListIndex())); + AMDGPUFlatWorkGroupSizeAttr(AL.getLoc(), S.Context, Min, Max, + AL.getAttributeSpellingListIndex())); } -static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t Min = 0; - Expr *MinExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, MinExpr, Min)) + Expr *MinExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, MinExpr, Min)) return; uint32_t Max = 0; - if (Attr.getNumArgs() == 2) { - Expr *MaxExpr = Attr.getArgAsExpr(1); - if (!checkUInt32Argument(S, Attr, MaxExpr, Max)) + if (AL.getNumArgs() == 2) { + Expr *MaxExpr = AL.getArgAsExpr(1); + if (!checkUInt32Argument(S, AL, MaxExpr, Max)) return; } if (Min == 0 && Max != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 0; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 0; return; } if (Max != 0 && Min > Max) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 1; return; } D->addAttr(::new (S.Context) - AMDGPUWavesPerEUAttr(Attr.getLoc(), S.Context, Min, Max, - Attr.getAttributeSpellingListIndex())); + AMDGPUWavesPerEUAttr(AL.getLoc(), S.Context, Min, Max, + AL.getAttributeSpellingListIndex())); } -static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t NumSGPR = 0; - Expr *NumSGPRExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, NumSGPRExpr, NumSGPR)) + Expr *NumSGPRExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR)) return; D->addAttr(::new (S.Context) - AMDGPUNumSGPRAttr(Attr.getLoc(), S.Context, NumSGPR, - Attr.getAttributeSpellingListIndex())); + AMDGPUNumSGPRAttr(AL.getLoc(), S.Context, NumSGPR, + AL.getAttributeSpellingListIndex())); } -static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t NumVGPR = 0; - Expr *NumVGPRExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, NumVGPRExpr, NumVGPR)) + Expr *NumVGPRExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR)) return; D->addAttr(::new (S.Context) - AMDGPUNumVGPRAttr(Attr.getLoc(), S.Context, NumVGPR, - Attr.getAttributeSpellingListIndex())); + AMDGPUNumVGPRAttr(AL.getLoc(), S.Context, NumVGPR, + AL.getAttributeSpellingListIndex())); } static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, - const AttributeList& Attr) { + const ParsedAttr &AL) { // If we try to apply it to a function pointer, don't warn, but don't // do anything, either. It doesn't matter anyway, because there's nothing // special about calling a force_align_arg_pointer function. - ValueDecl *VD = dyn_cast<ValueDecl>(D); + const auto *VD = dyn_cast<ValueDecl>(D); if (VD && VD->getType()->isFunctionPointerType()) return; // Also don't warn on function pointer typedefs. - TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); + const auto *TD = dyn_cast<TypedefNameDecl>(D); if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || TD->getUnderlyingType()->isFunctionType())) return; // Attribute can only be applied to function types. if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << /* function */0; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunction; return; } D->addAttr(::new (S.Context) - X86ForceAlignArgPointerAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + X86ForceAlignArgPointerAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleLayoutVersion(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t Version; - Expr *VersionExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); - if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), Version)) + Expr *VersionExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); + if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Version)) return; // TODO: Investigate what happens with the next major version of MSVC. if (Version != LangOptions::MSVC2015) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << Version << VersionExpr->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << Version << VersionExpr->getSourceRange(); return; } D->addAttr(::new (S.Context) - LayoutVersionAttr(Attr.getRange(), S.Context, Version, - Attr.getAttributeSpellingListIndex())); + LayoutVersionAttr(AL.getRange(), S.Context, Version, + AL.getAttributeSpellingListIndex())); } DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, @@ -5608,7 +5606,7 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, return ::new (Context) DLLExportAttr(Range, Context, AttrSpellingListIndex); } -static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { +static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (isa<ClassTemplatePartialSpecializationDecl>(D) && S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) @@ -5616,8 +5614,8 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { return; } - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - if (FD->isInlined() && A.getKind() == AttributeList::AT_DLLImport && + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isInlined() && A.getKind() == ParsedAttr::AT_DLLImport && !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { // MinGW doesn't allow dllimport on inline functions. S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline) @@ -5626,7 +5624,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { } } - if (auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && MD->getParent()->isLambda()) { S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A.getName(); @@ -5635,7 +5633,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { } unsigned Index = A.getAttributeSpellingListIndex(); - Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport + Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index) : (Attr *)S.mergeDLLImportAttr(D, A.getRange(), Index); if (NewAttr) @@ -5655,7 +5653,7 @@ Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, D->dropAttr<MSInheritanceAttr>(); } - CXXRecordDecl *RD = cast<CXXRecordDecl>(D); + auto *RD = cast<CXXRecordDecl>(D); if (RD->hasDefinition()) { if (checkMSInheritanceAttrOnDefinition(RD, Range, BestCase, SemanticSpelling)) { @@ -5678,7 +5676,7 @@ Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, MSInheritanceAttr(Range, Context, BestCase, AttrSpellingListIndex); } -static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // The capability attributes take a single string parameter for the name of // the capability they represent. The lockable attribute does not take any // parameters. However, semantically, both attributes represent the same @@ -5689,8 +5687,8 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { // literal will be considered a "mutex." StringRef N("mutex"); SourceLocation LiteralLoc; - if (Attr.getKind() == AttributeList::AT_Capability && - !S.checkStringLiteralArgumentAttr(Attr, 0, N, &LiteralLoc)) + if (AL.getKind() == ParsedAttr::AT_Capability && + !S.checkStringLiteralArgumentAttr(AL, 0, N, &LiteralLoc)) return; // Currently, there are only two names allowed for a capability: role and @@ -5698,80 +5696,79 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!N.equals_lower("mutex") && !N.equals_lower("role")) S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N; - D->addAttr(::new (S.Context) CapabilityAttr(Attr.getRange(), S.Context, N, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CapabilityAttr(AL.getRange(), S.Context, N, + AL.getAttributeSpellingListIndex())); } -static void handleAssertCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) AssertCapabilityAttr(Attr.getRange(), S.Context, + D->addAttr(::new (S.Context) AssertCapabilityAttr(AL.getRange(), S.Context, Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleAcquireCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) AcquireCapabilityAttr(Attr.getRange(), + D->addAttr(::new (S.Context) AcquireCapabilityAttr(AL.getRange(), S.Context, Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 2> Args; - if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(Attr.getRange(), + D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(AL.getRange(), S.Context, - Attr.getArgAsExpr(0), + AL.getArgAsExpr(0), Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleReleaseCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { // Check that all arguments are lockable objects. SmallVector<Expr *, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, true); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, true); D->addAttr(::new (S.Context) ReleaseCapabilityAttr( - Attr.getRange(), S.Context, Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Args.data(), Args.size(), + AL.getAttributeSpellingListIndex())); } static void handleRequiresCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; // check that all arguments are lockable objects SmallVector<Expr*, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); if (Args.empty()) return; RequiresCapabilityAttr *RCA = ::new (S.Context) - RequiresCapabilityAttr(Attr.getRange(), S.Context, Args.data(), - Args.size(), Attr.getAttributeSpellingListIndex()); + RequiresCapabilityAttr(AL.getRange(), S.Context, Args.data(), + Args.size(), AL.getAttributeSpellingListIndex()); D->addAttr(RCA); } -static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (auto *NSD = dyn_cast<NamespaceDecl>(D)) { +static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *NSD = dyn_cast<NamespaceDecl>(D)) { if (NSD->isAnonymousNamespace()) { - S.Diag(Attr.getLoc(), diag::warn_deprecated_anonymous_namespace); + S.Diag(AL.getLoc(), diag::warn_deprecated_anonymous_namespace); // Do not want to attach the attribute to the namespace because that will // cause confusing diagnostic reports for uses of declarations within the // namespace. @@ -5781,25 +5778,25 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Handle the cases where the attribute has a text message. StringRef Str, Replacement; - if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0) && - !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (AL.isArgExpr(0) && AL.getArgAsExpr(0) && + !S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; // Only support a single optional message for Declspec and CXX11. - if (Attr.isDeclspecAttribute() || Attr.isCXX11Attribute()) - checkAttributeAtMostNumArgs(S, Attr, 1); - else if (Attr.isArgExpr(1) && Attr.getArgAsExpr(1) && - !S.checkStringLiteralArgumentAttr(Attr, 1, Replacement)) + if (AL.isDeclspecAttribute() || AL.isCXX11Attribute()) + checkAttributeAtMostNumArgs(S, AL, 1); + else if (AL.isArgExpr(1) && AL.getArgAsExpr(1) && + !S.checkStringLiteralArgumentAttr(AL, 1, Replacement)) return; if (!S.getLangOpts().CPlusPlus14) - if (Attr.isCXX11Attribute() && - !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu"))) - S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName(); + if (AL.isCXX11Attribute() && + !(AL.hasScope() && AL.getScopeName()->isStr("gnu"))) + S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL.getName(); D->addAttr(::new (S.Context) - DeprecatedAttr(Attr.getRange(), S.Context, Str, Replacement, - Attr.getAttributeSpellingListIndex())); + DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement, + AL.getAttributeSpellingListIndex())); } static bool isGlobalVar(const Decl *D) { @@ -5808,35 +5805,35 @@ static bool isGlobalVar(const Decl *D) { return false; } -static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; std::vector<StringRef> Sanitizers; - for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef SanitizerName; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, I, SanitizerName, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, I, SanitizerName, &LiteralLoc)) return; if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0) S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; else if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; + << AL.getName() << ExpectedFunctionOrMethod; Sanitizers.push_back(SanitizerName); } D->addAttr(::new (S.Context) NoSanitizeAttr( - Attr.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(), - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(), + AL.getAttributeSpellingListIndex())); } static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - StringRef AttrName = Attr.getName()->getName(); + const ParsedAttr &AL) { + StringRef AttrName = AL.getName()->getName(); normalizeName(AttrName); StringRef SanitizerName = llvm::StringSwitch<StringRef>(AttrName) .Case("no_address_safety_analysis", "address") @@ -5845,77 +5842,78 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, .Case("no_sanitize_memory", "memory"); if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; + << AL.getName() << ExpectedFunction; D->addAttr(::new (S.Context) - NoSanitizeAttr(Attr.getRange(), S.Context, &SanitizerName, 1, - Attr.getAttributeSpellingListIndex())); + NoSanitizeAttr(AL.getRange(), S.Context, &SanitizerName, 1, + AL.getAttributeSpellingListIndex())); } -static void handleInternalLinkageAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (InternalLinkageAttr *Internal = - S.mergeInternalLinkageAttr(D, Attr.getRange(), Attr.getName(), - Attr.getAttributeSpellingListIndex())) + S.mergeInternalLinkageAttr(D, AL.getRange(), AL.getName(), + AL.getAttributeSpellingListIndex())) D->addAttr(Internal); } -static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (S.LangOpts.OpenCLVersion != 200) - S.Diag(Attr.getLoc(), diag::err_attribute_requires_opencl_version) - << Attr.getName() << "2.0" << 0; + S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version) + << AL.getName() << "2.0" << 0; else - S.Diag(Attr.getLoc(), diag::warn_opencl_attr_deprecated_ignored) - << Attr.getName() << "2.0"; + S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) + << AL.getName() << "2.0"; } /// Handles semantic checking for features that are common to all attributes, /// such as checking whether a parameter was properly specified, or the correct /// number of arguments were passed, etc. -static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, - const AttributeList &Attr) { +static bool handleCommonAttributeFeatures(Sema &S, Decl *D, + const ParsedAttr &AL) { // Several attributes carry different semantics than the parsing requires, so // those are opted out of the common argument checks. // // We also bail on unknown and ignored attributes because those are handled // as part of the target-specific handling logic. - if (Attr.getKind() == AttributeList::UnknownAttribute) + if (AL.getKind() == ParsedAttr::UnknownAttribute) return false; // Check whether the attribute requires specific language extensions to be // enabled. - if (!Attr.diagnoseLangOpts(S)) + if (!AL.diagnoseLangOpts(S)) return true; // Check whether the attribute appertains to the given subject. - if (!Attr.diagnoseAppertainsTo(S, D)) + if (!AL.diagnoseAppertainsTo(S, D)) return true; - if (Attr.hasCustomParsing()) + if (AL.hasCustomParsing()) return false; - if (Attr.getMinArgs() == Attr.getMaxArgs()) { + if (AL.getMinArgs() == AL.getMaxArgs()) { // If there are no optional arguments, then checking for the argument count // is trivial. - if (!checkAttributeNumArgs(S, Attr, Attr.getMinArgs())) + if (!checkAttributeNumArgs(S, AL, AL.getMinArgs())) return true; } else { // There are optional arguments, so checking is slightly more involved. - if (Attr.getMinArgs() && - !checkAttributeAtLeastNumArgs(S, Attr, Attr.getMinArgs())) + if (AL.getMinArgs() && + !checkAttributeAtLeastNumArgs(S, AL, AL.getMinArgs())) return true; - else if (!Attr.hasVariadicArg() && Attr.getMaxArgs() && - !checkAttributeAtMostNumArgs(S, Attr, Attr.getMaxArgs())) + else if (!AL.hasVariadicArg() && AL.getMaxArgs() && + !checkAttributeAtMostNumArgs(S, AL, AL.getMaxArgs())) return true; } + if (S.CheckAttrTarget(AL)) + return true; + return false; } -static void handleOpenCLAccessAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->isInvalidDecl()) return; // Check if there is only one access qualifier. if (D->hasAttr<OpenCLAccessAttr>()) { - S.Diag(Attr.getLoc(), diag::err_opencl_multiple_access_qualifiers) + S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers) << D->getSourceRange(); D->setInvalidDecl(true); return; @@ -5926,12 +5924,12 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, // OpenCL v2.0 s6.13.6 - A kernel cannot read from and write to the same pipe // object. Using the read_write (or __read_write) qualifier with the pipe // qualifier is a compilation error. - if (const ParmVarDecl *PDecl = dyn_cast<ParmVarDecl>(D)) { + if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) { const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); - if (Attr.getName()->getName().find("read_write") != StringRef::npos) { + if (AL.getName()->getName().find("read_write") != StringRef::npos) { if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) { - S.Diag(Attr.getLoc(), diag::err_opencl_invalid_read_write) - << Attr.getName() << PDecl->getType() << DeclTy->isImageType(); + S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) + << AL.getName() << PDecl->getType() << DeclTy->isImageType(); D->setInvalidDecl(true); return; } @@ -5939,7 +5937,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) OpenCLAccessAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// @@ -5950,633 +5948,662 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, /// the attribute applies to decls. If the attribute is a type attribute, just /// silently ignore it if a GNU attribute. static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, - const AttributeList &Attr, + const ParsedAttr &AL, bool IncludeCXX11Attributes) { - if (Attr.isInvalid() || Attr.getKind() == AttributeList::IgnoredAttribute) + if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) return; // Ignore C++11 attributes on declarator chunks: they appertain to the type // instead. - if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes) + if (AL.isCXX11Attribute() && !IncludeCXX11Attributes) return; // Unknown attributes are automatically warned on. Target-specific attributes // which do not apply to the current target architecture are treated as // though they were unknown attributes. - if (Attr.getKind() == AttributeList::UnknownAttribute || - !Attr.existsInTarget(S.Context.getTargetInfo())) { - S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() - ? diag::warn_unhandled_ms_attribute_ignored - : diag::warn_unknown_attribute_ignored) - << Attr.getName(); + if (AL.getKind() == ParsedAttr::UnknownAttribute || + !AL.existsInTarget(S.Context.getTargetInfo())) { + S.Diag(AL.getLoc(), AL.isDeclspecAttribute() + ? diag::warn_unhandled_ms_attribute_ignored + : diag::warn_unknown_attribute_ignored) + << AL.getName(); return; } - if (handleCommonAttributeFeatures(S, scope, D, Attr)) + if (handleCommonAttributeFeatures(S, D, AL)) return; - switch (Attr.getKind()) { + switch (AL.getKind()) { default: - if (!Attr.isStmtAttr()) { + if (!AL.isStmtAttr()) { // Type attributes are handled elsewhere; silently move on. - assert(Attr.isTypeAttr() && "Non-type attribute not handled"); + assert(AL.isTypeAttr() && "Non-type attribute not handled"); break; } - S.Diag(Attr.getLoc(), diag::err_stmt_attribute_invalid_on_decl) - << Attr.getName() << D->getLocation(); + S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl) + << AL.getName() << D->getLocation(); break; - case AttributeList::AT_Interrupt: - handleInterruptAttr(S, D, Attr); + case ParsedAttr::AT_Interrupt: + handleInterruptAttr(S, D, AL); break; - case AttributeList::AT_X86ForceAlignArgPointer: - handleX86ForceAlignArgPointerAttr(S, D, Attr); + case ParsedAttr::AT_X86ForceAlignArgPointer: + handleX86ForceAlignArgPointerAttr(S, D, AL); break; - case AttributeList::AT_DLLExport: - case AttributeList::AT_DLLImport: - handleDLLAttr(S, D, Attr); + case ParsedAttr::AT_DLLExport: + case ParsedAttr::AT_DLLImport: + handleDLLAttr(S, D, AL); break; - case AttributeList::AT_Mips16: + case ParsedAttr::AT_Mips16: handleSimpleAttributeWithExclusions<Mips16Attr, MicroMipsAttr, - MipsInterruptAttr>(S, D, Attr); + MipsInterruptAttr>(S, D, AL); break; - case AttributeList::AT_NoMips16: - handleSimpleAttribute<NoMips16Attr>(S, D, Attr); + case ParsedAttr::AT_NoMips16: + handleSimpleAttribute<NoMips16Attr>(S, D, AL); break; - case AttributeList::AT_MicroMips: - handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, Attr); + case ParsedAttr::AT_MicroMips: + handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, AL); break; - case AttributeList::AT_NoMicroMips: - handleSimpleAttribute<NoMicroMipsAttr>(S, D, Attr); + case ParsedAttr::AT_NoMicroMips: + handleSimpleAttribute<NoMicroMipsAttr>(S, D, AL); break; - case AttributeList::AT_MipsLongCall: + case ParsedAttr::AT_MipsLongCall: handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>( - S, D, Attr); + S, D, AL); break; - case AttributeList::AT_MipsShortCall: + case ParsedAttr::AT_MipsShortCall: handleSimpleAttributeWithExclusions<MipsShortCallAttr, MipsLongCallAttr>( - S, D, Attr); + S, D, AL); + break; + case ParsedAttr::AT_AMDGPUFlatWorkGroupSize: + handleAMDGPUFlatWorkGroupSizeAttr(S, D, AL); + break; + case ParsedAttr::AT_AMDGPUWavesPerEU: + handleAMDGPUWavesPerEUAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUFlatWorkGroupSize: - handleAMDGPUFlatWorkGroupSizeAttr(S, D, Attr); + case ParsedAttr::AT_AMDGPUNumSGPR: + handleAMDGPUNumSGPRAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUWavesPerEU: - handleAMDGPUWavesPerEUAttr(S, D, Attr); + case ParsedAttr::AT_AMDGPUNumVGPR: + handleAMDGPUNumVGPRAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUNumSGPR: - handleAMDGPUNumSGPRAttr(S, D, Attr); + case ParsedAttr::AT_AVRSignal: + handleAVRSignalAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUNumVGPR: - handleAMDGPUNumVGPRAttr(S, D, Attr); + case ParsedAttr::AT_IBAction: + handleSimpleAttribute<IBActionAttr>(S, D, AL); break; - case AttributeList::AT_AVRSignal: - handleAVRSignalAttr(S, D, Attr); + case ParsedAttr::AT_IBOutlet: + handleIBOutlet(S, D, AL); break; - case AttributeList::AT_IBAction: - handleSimpleAttribute<IBActionAttr>(S, D, Attr); + case ParsedAttr::AT_IBOutletCollection: + handleIBOutletCollection(S, D, AL); break; - case AttributeList::AT_IBOutlet: - handleIBOutlet(S, D, Attr); + case ParsedAttr::AT_IFunc: + handleIFuncAttr(S, D, AL); break; - case AttributeList::AT_IBOutletCollection: - handleIBOutletCollection(S, D, Attr); + case ParsedAttr::AT_Alias: + handleAliasAttr(S, D, AL); break; - case AttributeList::AT_IFunc: - handleIFuncAttr(S, D, Attr); + case ParsedAttr::AT_Aligned: + handleAlignedAttr(S, D, AL); break; - case AttributeList::AT_Alias: - handleAliasAttr(S, D, Attr); + case ParsedAttr::AT_AlignValue: + handleAlignValueAttr(S, D, AL); break; - case AttributeList::AT_Aligned: - handleAlignedAttr(S, D, Attr); + case ParsedAttr::AT_AllocSize: + handleAllocSizeAttr(S, D, AL); break; - case AttributeList::AT_AlignValue: - handleAlignValueAttr(S, D, Attr); + case ParsedAttr::AT_AlwaysInline: + handleAlwaysInlineAttr(S, D, AL); break; - case AttributeList::AT_AllocSize: - handleAllocSizeAttr(S, D, Attr); + case ParsedAttr::AT_Artificial: + handleSimpleAttribute<ArtificialAttr>(S, D, AL); break; - case AttributeList::AT_AlwaysInline: - handleAlwaysInlineAttr(S, D, Attr); + case ParsedAttr::AT_AnalyzerNoReturn: + handleAnalyzerNoReturnAttr(S, D, AL); break; - case AttributeList::AT_AnalyzerNoReturn: - handleAnalyzerNoReturnAttr(S, D, Attr); + case ParsedAttr::AT_TLSModel: + handleTLSModelAttr(S, D, AL); break; - case AttributeList::AT_TLSModel: - handleTLSModelAttr(S, D, Attr); + case ParsedAttr::AT_Annotate: + handleAnnotateAttr(S, D, AL); break; - case AttributeList::AT_Annotate: - handleAnnotateAttr(S, D, Attr); + case ParsedAttr::AT_Availability: + handleAvailabilityAttr(S, D, AL); break; - case AttributeList::AT_Availability: - handleAvailabilityAttr(S, D, Attr); + case ParsedAttr::AT_CarriesDependency: + handleDependencyAttr(S, scope, D, AL); break; - case AttributeList::AT_CarriesDependency: - handleDependencyAttr(S, scope, D, Attr); + case ParsedAttr::AT_CPUDispatch: + case ParsedAttr::AT_CPUSpecific: + handleCPUSpecificAttr(S, D, AL); break; - case AttributeList::AT_Common: - handleCommonAttr(S, D, Attr); + case ParsedAttr::AT_Common: + handleCommonAttr(S, D, AL); break; - case AttributeList::AT_CUDAConstant: - handleConstantAttr(S, D, Attr); + case ParsedAttr::AT_CUDAConstant: + handleConstantAttr(S, D, AL); break; - case AttributeList::AT_PassObjectSize: - handlePassObjectSizeAttr(S, D, Attr); + case ParsedAttr::AT_PassObjectSize: + handlePassObjectSizeAttr(S, D, AL); break; - case AttributeList::AT_Constructor: - handleConstructorAttr(S, D, Attr); + case ParsedAttr::AT_Constructor: + handleConstructorAttr(S, D, AL); break; - case AttributeList::AT_CXX11NoReturn: - handleSimpleAttribute<CXX11NoReturnAttr>(S, D, Attr); + case ParsedAttr::AT_CXX11NoReturn: + handleSimpleAttribute<CXX11NoReturnAttr>(S, D, AL); break; - case AttributeList::AT_Deprecated: - handleDeprecatedAttr(S, D, Attr); + case ParsedAttr::AT_Deprecated: + handleDeprecatedAttr(S, D, AL); break; - case AttributeList::AT_Destructor: - handleDestructorAttr(S, D, Attr); + case ParsedAttr::AT_Destructor: + handleDestructorAttr(S, D, AL); break; - case AttributeList::AT_EnableIf: - handleEnableIfAttr(S, D, Attr); + case ParsedAttr::AT_EnableIf: + handleEnableIfAttr(S, D, AL); break; - case AttributeList::AT_DiagnoseIf: - handleDiagnoseIfAttr(S, D, Attr); + case ParsedAttr::AT_DiagnoseIf: + handleDiagnoseIfAttr(S, D, AL); break; - case AttributeList::AT_ExtVectorType: - handleExtVectorTypeAttr(S, scope, D, Attr); + case ParsedAttr::AT_ExtVectorType: + handleExtVectorTypeAttr(S, D, AL); break; - case AttributeList::AT_ExternalSourceSymbol: - handleExternalSourceSymbolAttr(S, D, Attr); + case ParsedAttr::AT_ExternalSourceSymbol: + handleExternalSourceSymbolAttr(S, D, AL); break; - case AttributeList::AT_MinSize: - handleMinSizeAttr(S, D, Attr); + case ParsedAttr::AT_MinSize: + handleMinSizeAttr(S, D, AL); break; - case AttributeList::AT_OptimizeNone: - handleOptimizeNoneAttr(S, D, Attr); + case ParsedAttr::AT_OptimizeNone: + handleOptimizeNoneAttr(S, D, AL); break; - case AttributeList::AT_FlagEnum: - handleSimpleAttribute<FlagEnumAttr>(S, D, Attr); + case ParsedAttr::AT_FlagEnum: + handleSimpleAttribute<FlagEnumAttr>(S, D, AL); break; - case AttributeList::AT_EnumExtensibility: - handleEnumExtensibilityAttr(S, D, Attr); + case ParsedAttr::AT_EnumExtensibility: + handleEnumExtensibilityAttr(S, D, AL); break; - case AttributeList::AT_Flatten: - handleSimpleAttribute<FlattenAttr>(S, D, Attr); + case ParsedAttr::AT_Flatten: + handleSimpleAttribute<FlattenAttr>(S, D, AL); break; - case AttributeList::AT_Format: - handleFormatAttr(S, D, Attr); + case ParsedAttr::AT_Format: + handleFormatAttr(S, D, AL); break; - case AttributeList::AT_FormatArg: - handleFormatArgAttr(S, D, Attr); + case ParsedAttr::AT_FormatArg: + handleFormatArgAttr(S, D, AL); break; - case AttributeList::AT_CUDAGlobal: - handleGlobalAttr(S, D, Attr); + case ParsedAttr::AT_CUDAGlobal: + handleGlobalAttr(S, D, AL); break; - case AttributeList::AT_CUDADevice: + case ParsedAttr::AT_CUDADevice: handleSimpleAttributeWithExclusions<CUDADeviceAttr, CUDAGlobalAttr>(S, D, - Attr); + AL); break; - case AttributeList::AT_CUDAHost: - handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, - Attr); + case ParsedAttr::AT_CUDAHost: + handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, AL); break; - case AttributeList::AT_GNUInline: - handleGNUInlineAttr(S, D, Attr); + case ParsedAttr::AT_GNUInline: + handleGNUInlineAttr(S, D, AL); break; - case AttributeList::AT_CUDALaunchBounds: - handleLaunchBoundsAttr(S, D, Attr); + case ParsedAttr::AT_CUDALaunchBounds: + handleLaunchBoundsAttr(S, D, AL); break; - case AttributeList::AT_Restrict: - handleRestrictAttr(S, D, Attr); + case ParsedAttr::AT_Restrict: + handleRestrictAttr(S, D, AL); break; - case AttributeList::AT_MayAlias: - handleSimpleAttribute<MayAliasAttr>(S, D, Attr); + case ParsedAttr::AT_LifetimeBound: + handleSimpleAttribute<LifetimeBoundAttr>(S, D, AL); break; - case AttributeList::AT_Mode: - handleModeAttr(S, D, Attr); + case ParsedAttr::AT_MayAlias: + handleSimpleAttribute<MayAliasAttr>(S, D, AL); break; - case AttributeList::AT_NoAlias: - handleSimpleAttribute<NoAliasAttr>(S, D, Attr); + case ParsedAttr::AT_Mode: + handleModeAttr(S, D, AL); break; - case AttributeList::AT_NoCommon: - handleSimpleAttribute<NoCommonAttr>(S, D, Attr); + case ParsedAttr::AT_NoAlias: + handleSimpleAttribute<NoAliasAttr>(S, D, AL); break; - case AttributeList::AT_NoSplitStack: - handleSimpleAttribute<NoSplitStackAttr>(S, D, Attr); + case ParsedAttr::AT_NoCommon: + handleSimpleAttribute<NoCommonAttr>(S, D, AL); break; - case AttributeList::AT_NonNull: - if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D)) - handleNonNullAttrParameter(S, PVD, Attr); + case ParsedAttr::AT_NoSplitStack: + handleSimpleAttribute<NoSplitStackAttr>(S, D, AL); + break; + case ParsedAttr::AT_NonNull: + if (auto *PVD = dyn_cast<ParmVarDecl>(D)) + handleNonNullAttrParameter(S, PVD, AL); else - handleNonNullAttr(S, D, Attr); + handleNonNullAttr(S, D, AL); + break; + case ParsedAttr::AT_ReturnsNonNull: + handleReturnsNonNullAttr(S, D, AL); + break; + case ParsedAttr::AT_NoEscape: + handleNoEscapeAttr(S, D, AL); + break; + case ParsedAttr::AT_AssumeAligned: + handleAssumeAlignedAttr(S, D, AL); + break; + case ParsedAttr::AT_AllocAlign: + handleAllocAlignAttr(S, D, AL); break; - case AttributeList::AT_ReturnsNonNull: - handleReturnsNonNullAttr(S, D, Attr); + case ParsedAttr::AT_Overloadable: + handleSimpleAttribute<OverloadableAttr>(S, D, AL); break; - case AttributeList::AT_NoEscape: - handleNoEscapeAttr(S, D, Attr); + case ParsedAttr::AT_Ownership: + handleOwnershipAttr(S, D, AL); break; - case AttributeList::AT_AssumeAligned: - handleAssumeAlignedAttr(S, D, Attr); + case ParsedAttr::AT_Cold: + handleSimpleAttributeWithExclusions<ColdAttr, HotAttr>(S, D, AL); break; - case AttributeList::AT_AllocAlign: - handleAllocAlignAttr(S, D, Attr); + case ParsedAttr::AT_Hot: + handleSimpleAttributeWithExclusions<HotAttr, ColdAttr>(S, D, AL); break; - case AttributeList::AT_Overloadable: - handleSimpleAttribute<OverloadableAttr>(S, D, Attr); + case ParsedAttr::AT_Naked: + handleNakedAttr(S, D, AL); break; - case AttributeList::AT_Ownership: - handleOwnershipAttr(S, D, Attr); + case ParsedAttr::AT_NoReturn: + handleNoReturnAttr(S, D, AL); break; - case AttributeList::AT_Cold: - handleColdAttr(S, D, Attr); + case ParsedAttr::AT_AnyX86NoCfCheck: + handleNoCfCheckAttr(S, D, AL); break; - case AttributeList::AT_Hot: - handleHotAttr(S, D, Attr); + case ParsedAttr::AT_NoThrow: + handleSimpleAttribute<NoThrowAttr>(S, D, AL); break; - case AttributeList::AT_Naked: - handleNakedAttr(S, D, Attr); + case ParsedAttr::AT_CUDAShared: + handleSharedAttr(S, D, AL); break; - case AttributeList::AT_NoReturn: - handleNoReturnAttr(S, D, Attr); + case ParsedAttr::AT_VecReturn: + handleVecReturnAttr(S, D, AL); break; - case AttributeList::AT_NoThrow: - handleSimpleAttribute<NoThrowAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCOwnership: + handleObjCOwnershipAttr(S, D, AL); break; - case AttributeList::AT_CUDAShared: - handleSharedAttr(S, D, Attr); + case ParsedAttr::AT_ObjCPreciseLifetime: + handleObjCPreciseLifetimeAttr(S, D, AL); break; - case AttributeList::AT_VecReturn: - handleVecReturnAttr(S, D, Attr); + case ParsedAttr::AT_ObjCReturnsInnerPointer: + handleObjCReturnsInnerPointerAttr(S, D, AL); break; - case AttributeList::AT_ObjCOwnership: - handleObjCOwnershipAttr(S, D, Attr); + case ParsedAttr::AT_ObjCRequiresSuper: + handleObjCRequiresSuperAttr(S, D, AL); break; - case AttributeList::AT_ObjCPreciseLifetime: - handleObjCPreciseLifetimeAttr(S, D, Attr); + case ParsedAttr::AT_ObjCBridge: + handleObjCBridgeAttr(S, D, AL); break; - case AttributeList::AT_ObjCReturnsInnerPointer: - handleObjCReturnsInnerPointerAttr(S, D, Attr); + case ParsedAttr::AT_ObjCBridgeMutable: + handleObjCBridgeMutableAttr(S, D, AL); break; - case AttributeList::AT_ObjCRequiresSuper: - handleObjCRequiresSuperAttr(S, D, Attr); + case ParsedAttr::AT_ObjCBridgeRelated: + handleObjCBridgeRelatedAttr(S, D, AL); break; - case AttributeList::AT_ObjCBridge: - handleObjCBridgeAttr(S, scope, D, Attr); + case ParsedAttr::AT_ObjCDesignatedInitializer: + handleObjCDesignatedInitializer(S, D, AL); break; - case AttributeList::AT_ObjCBridgeMutable: - handleObjCBridgeMutableAttr(S, scope, D, Attr); + case ParsedAttr::AT_ObjCRuntimeName: + handleObjCRuntimeName(S, D, AL); break; - case AttributeList::AT_ObjCBridgeRelated: - handleObjCBridgeRelatedAttr(S, scope, D, Attr); + case ParsedAttr::AT_ObjCRuntimeVisible: + handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, AL); break; - case AttributeList::AT_ObjCDesignatedInitializer: - handleObjCDesignatedInitializer(S, D, Attr); + case ParsedAttr::AT_ObjCBoxable: + handleObjCBoxable(S, D, AL); break; - case AttributeList::AT_ObjCRuntimeName: - handleObjCRuntimeName(S, D, Attr); + case ParsedAttr::AT_CFAuditedTransfer: + handleSimpleAttributeWithExclusions<CFAuditedTransferAttr, + CFUnknownTransferAttr>(S, D, AL); break; - case AttributeList::AT_ObjCRuntimeVisible: - handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, Attr); + case ParsedAttr::AT_CFUnknownTransfer: + handleSimpleAttributeWithExclusions<CFUnknownTransferAttr, + CFAuditedTransferAttr>(S, D, AL); break; - case AttributeList::AT_ObjCBoxable: - handleObjCBoxable(S, D, Attr); + case ParsedAttr::AT_CFConsumed: + case ParsedAttr::AT_NSConsumed: + handleNSConsumedAttr(S, D, AL); break; - case AttributeList::AT_CFAuditedTransfer: - handleCFAuditedTransferAttr(S, D, Attr); + case ParsedAttr::AT_NSConsumesSelf: + handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL); break; - case AttributeList::AT_CFUnknownTransfer: - handleCFUnknownTransferAttr(S, D, Attr); + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_CFReturnsRetained: + handleNSReturnsRetainedAttr(S, D, AL); break; - case AttributeList::AT_CFConsumed: - case AttributeList::AT_NSConsumed: - handleNSConsumedAttr(S, D, Attr); + case ParsedAttr::AT_WorkGroupSizeHint: + handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, AL); break; - case AttributeList::AT_NSConsumesSelf: - handleSimpleAttribute<NSConsumesSelfAttr>(S, D, Attr); + case ParsedAttr::AT_ReqdWorkGroupSize: + handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, AL); break; - case AttributeList::AT_NSReturnsAutoreleased: - case AttributeList::AT_NSReturnsNotRetained: - case AttributeList::AT_CFReturnsNotRetained: - case AttributeList::AT_NSReturnsRetained: - case AttributeList::AT_CFReturnsRetained: - handleNSReturnsRetainedAttr(S, D, Attr); + case ParsedAttr::AT_OpenCLIntelReqdSubGroupSize: + handleSubGroupSize(S, D, AL); break; - case AttributeList::AT_WorkGroupSizeHint: - handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, Attr); + case ParsedAttr::AT_VecTypeHint: + handleVecTypeHint(S, D, AL); break; - case AttributeList::AT_ReqdWorkGroupSize: - handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, Attr); + case ParsedAttr::AT_RequireConstantInit: + handleSimpleAttribute<RequireConstantInitAttr>(S, D, AL); break; - case AttributeList::AT_OpenCLIntelReqdSubGroupSize: - handleSubGroupSize(S, D, Attr); + case ParsedAttr::AT_InitPriority: + handleInitPriorityAttr(S, D, AL); break; - case AttributeList::AT_VecTypeHint: - handleVecTypeHint(S, D, Attr); + case ParsedAttr::AT_Packed: + handlePackedAttr(S, D, AL); break; - case AttributeList::AT_RequireConstantInit: - handleSimpleAttribute<RequireConstantInitAttr>(S, D, Attr); + case ParsedAttr::AT_Section: + handleSectionAttr(S, D, AL); break; - case AttributeList::AT_InitPriority: - handleInitPriorityAttr(S, D, Attr); + case ParsedAttr::AT_CodeSeg: + handleCodeSegAttr(S, D, AL); break; - case AttributeList::AT_Packed: - handlePackedAttr(S, D, Attr); + case ParsedAttr::AT_Target: + handleTargetAttr(S, D, AL); break; - case AttributeList::AT_Section: - handleSectionAttr(S, D, Attr); + case ParsedAttr::AT_MinVectorWidth: + handleMinVectorWidthAttr(S, D, AL); break; - case AttributeList::AT_Target: - handleTargetAttr(S, D, Attr); + case ParsedAttr::AT_Unavailable: + handleAttrWithMessage<UnavailableAttr>(S, D, AL); break; - case AttributeList::AT_Unavailable: - handleAttrWithMessage<UnavailableAttr>(S, D, Attr); + case ParsedAttr::AT_ArcWeakrefUnavailable: + handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, AL); break; - case AttributeList::AT_ArcWeakrefUnavailable: - handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCRootClass: + handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL); break; - case AttributeList::AT_ObjCRootClass: - handleSimpleAttribute<ObjCRootClassAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCSubclassingRestricted: + handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL); break; - case AttributeList::AT_ObjCSubclassingRestricted: - handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCExplicitProtocolImpl: + handleObjCSuppresProtocolAttr(S, D, AL); break; - case AttributeList::AT_ObjCExplicitProtocolImpl: - handleObjCSuppresProtocolAttr(S, D, Attr); + case ParsedAttr::AT_ObjCRequiresPropertyDefs: + handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, AL); break; - case AttributeList::AT_ObjCRequiresPropertyDefs: - handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr); + case ParsedAttr::AT_Unused: + handleUnusedAttr(S, D, AL); break; - case AttributeList::AT_Unused: - handleUnusedAttr(S, D, Attr); + case ParsedAttr::AT_ReturnsTwice: + handleSimpleAttribute<ReturnsTwiceAttr>(S, D, AL); break; - case AttributeList::AT_ReturnsTwice: - handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr); + case ParsedAttr::AT_NotTailCalled: + handleSimpleAttributeWithExclusions<NotTailCalledAttr, AlwaysInlineAttr>( + S, D, AL); break; - case AttributeList::AT_NotTailCalled: - handleNotTailCalledAttr(S, D, Attr); + case ParsedAttr::AT_DisableTailCalls: + handleSimpleAttributeWithExclusions<DisableTailCallsAttr, NakedAttr>(S, D, + AL); break; - case AttributeList::AT_DisableTailCalls: - handleDisableTailCallsAttr(S, D, Attr); + case ParsedAttr::AT_Used: + handleSimpleAttribute<UsedAttr>(S, D, AL); break; - case AttributeList::AT_Used: - handleUsedAttr(S, D, Attr); + case ParsedAttr::AT_Visibility: + handleVisibilityAttr(S, D, AL, false); break; - case AttributeList::AT_Visibility: - handleVisibilityAttr(S, D, Attr, false); + case ParsedAttr::AT_TypeVisibility: + handleVisibilityAttr(S, D, AL, true); break; - case AttributeList::AT_TypeVisibility: - handleVisibilityAttr(S, D, Attr, true); + case ParsedAttr::AT_WarnUnused: + handleSimpleAttribute<WarnUnusedAttr>(S, D, AL); break; - case AttributeList::AT_WarnUnused: - handleSimpleAttribute<WarnUnusedAttr>(S, D, Attr); + case ParsedAttr::AT_WarnUnusedResult: + handleWarnUnusedResult(S, D, AL); break; - case AttributeList::AT_WarnUnusedResult: - handleWarnUnusedResult(S, D, Attr); + case ParsedAttr::AT_Weak: + handleSimpleAttribute<WeakAttr>(S, D, AL); break; - case AttributeList::AT_Weak: - handleSimpleAttribute<WeakAttr>(S, D, Attr); + case ParsedAttr::AT_WeakRef: + handleWeakRefAttr(S, D, AL); break; - case AttributeList::AT_WeakRef: - handleWeakRefAttr(S, D, Attr); + case ParsedAttr::AT_WeakImport: + handleWeakImportAttr(S, D, AL); break; - case AttributeList::AT_WeakImport: - handleWeakImportAttr(S, D, Attr); + case ParsedAttr::AT_TransparentUnion: + handleTransparentUnionAttr(S, D, AL); break; - case AttributeList::AT_TransparentUnion: - handleTransparentUnionAttr(S, D, Attr); + case ParsedAttr::AT_ObjCException: + handleSimpleAttribute<ObjCExceptionAttr>(S, D, AL); break; - case AttributeList::AT_ObjCException: - handleSimpleAttribute<ObjCExceptionAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCMethodFamily: + handleObjCMethodFamilyAttr(S, D, AL); break; - case AttributeList::AT_ObjCMethodFamily: - handleObjCMethodFamilyAttr(S, D, Attr); + case ParsedAttr::AT_ObjCNSObject: + handleObjCNSObject(S, D, AL); break; - case AttributeList::AT_ObjCNSObject: - handleObjCNSObject(S, D, Attr); + case ParsedAttr::AT_ObjCIndependentClass: + handleObjCIndependentClass(S, D, AL); break; - case AttributeList::AT_ObjCIndependentClass: - handleObjCIndependentClass(S, D, Attr); + case ParsedAttr::AT_Blocks: + handleBlocksAttr(S, D, AL); break; - case AttributeList::AT_Blocks: - handleBlocksAttr(S, D, Attr); + case ParsedAttr::AT_Sentinel: + handleSentinelAttr(S, D, AL); break; - case AttributeList::AT_Sentinel: - handleSentinelAttr(S, D, Attr); + case ParsedAttr::AT_Const: + handleSimpleAttribute<ConstAttr>(S, D, AL); break; - case AttributeList::AT_Const: - handleSimpleAttribute<ConstAttr>(S, D, Attr); + case ParsedAttr::AT_Pure: + handleSimpleAttribute<PureAttr>(S, D, AL); break; - case AttributeList::AT_Pure: - handleSimpleAttribute<PureAttr>(S, D, Attr); + case ParsedAttr::AT_Cleanup: + handleCleanupAttr(S, D, AL); break; - case AttributeList::AT_Cleanup: - handleCleanupAttr(S, D, Attr); + case ParsedAttr::AT_NoDebug: + handleNoDebugAttr(S, D, AL); break; - case AttributeList::AT_NoDebug: - handleNoDebugAttr(S, D, Attr); + case ParsedAttr::AT_NoDuplicate: + handleSimpleAttribute<NoDuplicateAttr>(S, D, AL); break; - case AttributeList::AT_NoDuplicate: - handleSimpleAttribute<NoDuplicateAttr>(S, D, Attr); + case ParsedAttr::AT_Convergent: + handleSimpleAttribute<ConvergentAttr>(S, D, AL); break; - case AttributeList::AT_Convergent: - handleSimpleAttribute<ConvergentAttr>(S, D, Attr); + case ParsedAttr::AT_NoInline: + handleSimpleAttribute<NoInlineAttr>(S, D, AL); break; - case AttributeList::AT_NoInline: - handleSimpleAttribute<NoInlineAttr>(S, D, Attr); + case ParsedAttr::AT_NoInstrumentFunction: // Interacts with -pg. + handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, AL); break; - case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg. - handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, Attr); + case ParsedAttr::AT_NoStackProtector: + // Interacts with -fstack-protector options. + handleSimpleAttribute<NoStackProtectorAttr>(S, D, AL); break; - case AttributeList::AT_StdCall: - case AttributeList::AT_CDecl: - case AttributeList::AT_FastCall: - case AttributeList::AT_ThisCall: - case AttributeList::AT_Pascal: - case AttributeList::AT_RegCall: - case AttributeList::AT_SwiftCall: - case AttributeList::AT_VectorCall: - case AttributeList::AT_MSABI: - case AttributeList::AT_SysVABI: - case AttributeList::AT_Pcs: - case AttributeList::AT_IntelOclBicc: - case AttributeList::AT_PreserveMost: - case AttributeList::AT_PreserveAll: - handleCallConvAttr(S, D, Attr); + case ParsedAttr::AT_StdCall: + case ParsedAttr::AT_CDecl: + case ParsedAttr::AT_FastCall: + case ParsedAttr::AT_ThisCall: + case ParsedAttr::AT_Pascal: + case ParsedAttr::AT_RegCall: + case ParsedAttr::AT_SwiftCall: + case ParsedAttr::AT_VectorCall: + case ParsedAttr::AT_MSABI: + case ParsedAttr::AT_SysVABI: + case ParsedAttr::AT_Pcs: + case ParsedAttr::AT_IntelOclBicc: + case ParsedAttr::AT_PreserveMost: + case ParsedAttr::AT_PreserveAll: + handleCallConvAttr(S, D, AL); break; - case AttributeList::AT_Suppress: - handleSuppressAttr(S, D, Attr); + case ParsedAttr::AT_Suppress: + handleSuppressAttr(S, D, AL); break; - case AttributeList::AT_OpenCLKernel: - handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr); + case ParsedAttr::AT_OpenCLKernel: + handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL); break; - case AttributeList::AT_OpenCLAccess: - handleOpenCLAccessAttr(S, D, Attr); + case ParsedAttr::AT_OpenCLAccess: + handleOpenCLAccessAttr(S, D, AL); break; - case AttributeList::AT_OpenCLNoSVM: - handleOpenCLNoSVMAttr(S, D, Attr); + case ParsedAttr::AT_OpenCLNoSVM: + handleOpenCLNoSVMAttr(S, D, AL); break; - case AttributeList::AT_SwiftContext: - handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftContext); + case ParsedAttr::AT_SwiftContext: + handleParameterABIAttr(S, D, AL, ParameterABI::SwiftContext); break; - case AttributeList::AT_SwiftErrorResult: - handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftErrorResult); + case ParsedAttr::AT_SwiftErrorResult: + handleParameterABIAttr(S, D, AL, ParameterABI::SwiftErrorResult); break; - case AttributeList::AT_SwiftIndirectResult: - handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftIndirectResult); + case ParsedAttr::AT_SwiftIndirectResult: + handleParameterABIAttr(S, D, AL, ParameterABI::SwiftIndirectResult); break; - case AttributeList::AT_InternalLinkage: - handleInternalLinkageAttr(S, D, Attr); + case ParsedAttr::AT_InternalLinkage: + handleInternalLinkageAttr(S, D, AL); break; - case AttributeList::AT_LTOVisibilityPublic: - handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, Attr); + case ParsedAttr::AT_LTOVisibilityPublic: + handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, AL); break; // Microsoft attributes: - case AttributeList::AT_EmptyBases: - handleSimpleAttribute<EmptyBasesAttr>(S, D, Attr); + case ParsedAttr::AT_EmptyBases: + handleSimpleAttribute<EmptyBasesAttr>(S, D, AL); break; - case AttributeList::AT_LayoutVersion: - handleLayoutVersion(S, D, Attr); + case ParsedAttr::AT_LayoutVersion: + handleLayoutVersion(S, D, AL); break; - case AttributeList::AT_MSNoVTable: - handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr); + case ParsedAttr::AT_TrivialABI: + handleSimpleAttribute<TrivialABIAttr>(S, D, AL); break; - case AttributeList::AT_MSStruct: - handleSimpleAttribute<MSStructAttr>(S, D, Attr); + case ParsedAttr::AT_MSNoVTable: + handleSimpleAttribute<MSNoVTableAttr>(S, D, AL); break; - case AttributeList::AT_Uuid: - handleUuidAttr(S, D, Attr); + case ParsedAttr::AT_MSStruct: + handleSimpleAttribute<MSStructAttr>(S, D, AL); break; - case AttributeList::AT_MSInheritance: - handleMSInheritanceAttr(S, D, Attr); + case ParsedAttr::AT_Uuid: + handleUuidAttr(S, D, AL); break; - case AttributeList::AT_SelectAny: - handleSimpleAttribute<SelectAnyAttr>(S, D, Attr); + case ParsedAttr::AT_MSInheritance: + handleMSInheritanceAttr(S, D, AL); break; - case AttributeList::AT_Thread: - handleDeclspecThreadAttr(S, D, Attr); + case ParsedAttr::AT_SelectAny: + handleSimpleAttribute<SelectAnyAttr>(S, D, AL); + break; + case ParsedAttr::AT_Thread: + handleDeclspecThreadAttr(S, D, AL); break; - case AttributeList::AT_AbiTag: - handleAbiTagAttr(S, D, Attr); + case ParsedAttr::AT_AbiTag: + handleAbiTagAttr(S, D, AL); break; // Thread safety attributes: - case AttributeList::AT_AssertExclusiveLock: - handleAssertExclusiveLockAttr(S, D, Attr); + case ParsedAttr::AT_AssertExclusiveLock: + handleAssertExclusiveLockAttr(S, D, AL); break; - case AttributeList::AT_AssertSharedLock: - handleAssertSharedLockAttr(S, D, Attr); + case ParsedAttr::AT_AssertSharedLock: + handleAssertSharedLockAttr(S, D, AL); break; - case AttributeList::AT_GuardedVar: - handleSimpleAttribute<GuardedVarAttr>(S, D, Attr); + case ParsedAttr::AT_GuardedVar: + handleSimpleAttribute<GuardedVarAttr>(S, D, AL); break; - case AttributeList::AT_PtGuardedVar: - handlePtGuardedVarAttr(S, D, Attr); + case ParsedAttr::AT_PtGuardedVar: + handlePtGuardedVarAttr(S, D, AL); break; - case AttributeList::AT_ScopedLockable: - handleSimpleAttribute<ScopedLockableAttr>(S, D, Attr); + case ParsedAttr::AT_ScopedLockable: + handleSimpleAttribute<ScopedLockableAttr>(S, D, AL); break; - case AttributeList::AT_NoSanitize: - handleNoSanitizeAttr(S, D, Attr); + case ParsedAttr::AT_NoSanitize: + handleNoSanitizeAttr(S, D, AL); break; - case AttributeList::AT_NoSanitizeSpecific: - handleNoSanitizeSpecificAttr(S, D, Attr); + case ParsedAttr::AT_NoSanitizeSpecific: + handleNoSanitizeSpecificAttr(S, D, AL); break; - case AttributeList::AT_NoThreadSafetyAnalysis: - handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, Attr); + case ParsedAttr::AT_NoThreadSafetyAnalysis: + handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, AL); break; - case AttributeList::AT_GuardedBy: - handleGuardedByAttr(S, D, Attr); + case ParsedAttr::AT_GuardedBy: + handleGuardedByAttr(S, D, AL); break; - case AttributeList::AT_PtGuardedBy: - handlePtGuardedByAttr(S, D, Attr); + case ParsedAttr::AT_PtGuardedBy: + handlePtGuardedByAttr(S, D, AL); break; - case AttributeList::AT_ExclusiveTrylockFunction: - handleExclusiveTrylockFunctionAttr(S, D, Attr); + case ParsedAttr::AT_ExclusiveTrylockFunction: + handleExclusiveTrylockFunctionAttr(S, D, AL); break; - case AttributeList::AT_LockReturned: - handleLockReturnedAttr(S, D, Attr); + case ParsedAttr::AT_LockReturned: + handleLockReturnedAttr(S, D, AL); break; - case AttributeList::AT_LocksExcluded: - handleLocksExcludedAttr(S, D, Attr); + case ParsedAttr::AT_LocksExcluded: + handleLocksExcludedAttr(S, D, AL); break; - case AttributeList::AT_SharedTrylockFunction: - handleSharedTrylockFunctionAttr(S, D, Attr); + case ParsedAttr::AT_SharedTrylockFunction: + handleSharedTrylockFunctionAttr(S, D, AL); break; - case AttributeList::AT_AcquiredBefore: - handleAcquiredBeforeAttr(S, D, Attr); + case ParsedAttr::AT_AcquiredBefore: + handleAcquiredBeforeAttr(S, D, AL); break; - case AttributeList::AT_AcquiredAfter: - handleAcquiredAfterAttr(S, D, Attr); + case ParsedAttr::AT_AcquiredAfter: + handleAcquiredAfterAttr(S, D, AL); break; // Capability analysis attributes. - case AttributeList::AT_Capability: - case AttributeList::AT_Lockable: - handleCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_Capability: + case ParsedAttr::AT_Lockable: + handleCapabilityAttr(S, D, AL); break; - case AttributeList::AT_RequiresCapability: - handleRequiresCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_RequiresCapability: + handleRequiresCapabilityAttr(S, D, AL); break; - case AttributeList::AT_AssertCapability: - handleAssertCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_AssertCapability: + handleAssertCapabilityAttr(S, D, AL); break; - case AttributeList::AT_AcquireCapability: - handleAcquireCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_AcquireCapability: + handleAcquireCapabilityAttr(S, D, AL); break; - case AttributeList::AT_ReleaseCapability: - handleReleaseCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_ReleaseCapability: + handleReleaseCapabilityAttr(S, D, AL); break; - case AttributeList::AT_TryAcquireCapability: - handleTryAcquireCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_TryAcquireCapability: + handleTryAcquireCapabilityAttr(S, D, AL); break; // Consumed analysis attributes. - case AttributeList::AT_Consumable: - handleConsumableAttr(S, D, Attr); + case ParsedAttr::AT_Consumable: + handleConsumableAttr(S, D, AL); break; - case AttributeList::AT_ConsumableAutoCast: - handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, Attr); + case ParsedAttr::AT_ConsumableAutoCast: + handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, AL); break; - case AttributeList::AT_ConsumableSetOnRead: - handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, Attr); + case ParsedAttr::AT_ConsumableSetOnRead: + handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, AL); break; - case AttributeList::AT_CallableWhen: - handleCallableWhenAttr(S, D, Attr); + case ParsedAttr::AT_CallableWhen: + handleCallableWhenAttr(S, D, AL); break; - case AttributeList::AT_ParamTypestate: - handleParamTypestateAttr(S, D, Attr); + case ParsedAttr::AT_ParamTypestate: + handleParamTypestateAttr(S, D, AL); break; - case AttributeList::AT_ReturnTypestate: - handleReturnTypestateAttr(S, D, Attr); + case ParsedAttr::AT_ReturnTypestate: + handleReturnTypestateAttr(S, D, AL); break; - case AttributeList::AT_SetTypestate: - handleSetTypestateAttr(S, D, Attr); + case ParsedAttr::AT_SetTypestate: + handleSetTypestateAttr(S, D, AL); break; - case AttributeList::AT_TestTypestate: - handleTestTypestateAttr(S, D, Attr); + case ParsedAttr::AT_TestTypestate: + handleTestTypestateAttr(S, D, AL); break; // Type safety attributes. - case AttributeList::AT_ArgumentWithTypeTag: - handleArgumentWithTypeTagAttr(S, D, Attr); + case ParsedAttr::AT_ArgumentWithTypeTag: + handleArgumentWithTypeTagAttr(S, D, AL); break; - case AttributeList::AT_TypeTagForDatatype: - handleTypeTagForDatatypeAttr(S, D, Attr); + case ParsedAttr::AT_TypeTagForDatatype: + handleTypeTagForDatatypeAttr(S, D, AL); break; - case AttributeList::AT_AnyX86NoCallerSavedRegisters: - handleNoCallerSavedRegsAttr(S, D, Attr); + case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: + handleSimpleAttribute<AnyX86NoCallerSavedRegistersAttr>(S, D, AL); break; - case AttributeList::AT_RenderScriptKernel: - handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr); + case ParsedAttr::AT_RenderScriptKernel: + handleSimpleAttribute<RenderScriptKernelAttr>(S, D, AL); break; // XRay attributes. - case AttributeList::AT_XRayInstrument: - handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr); + case ParsedAttr::AT_XRayInstrument: + handleSimpleAttribute<XRayInstrumentAttr>(S, D, AL); break; - case AttributeList::AT_XRayLogArgs: - handleXRayLogArgsAttr(S, D, Attr); + case ParsedAttr::AT_XRayLogArgs: + handleXRayLogArgsAttr(S, D, AL); break; } } @@ -6584,18 +6611,21 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, /// ProcessDeclAttributeList - Apply all the decl attributes in the specified /// attribute list to the specified decl, ignoring any type attributes. void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, - const AttributeList *AttrList, + const ParsedAttributesView &AttrList, bool IncludeCXX11Attributes) { - for (const AttributeList* l = AttrList; l; l = l->getNext()) - ProcessDeclAttribute(*this, S, D, *l, IncludeCXX11Attributes); + if (AttrList.empty()) + return; + + for (const ParsedAttr &AL : AttrList) + ProcessDeclAttribute(*this, S, D, AL, IncludeCXX11Attributes); // FIXME: We should be able to handle these cases in TableGen. // GCC accepts // static int a9 __attribute__((weakref)); // but that looks really pointless. We reject it. if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { - Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) - << cast<NamedDecl>(D); + Diag(AttrList.begin()->getLoc(), diag::err_attribute_weakref_without_alias) + << cast<NamedDecl>(D); D->dropAttr<WeakRefAttr>(); return; } @@ -6606,79 +6636,83 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, // attribute must never appear as a group" for attributes like cold and hot. if (!D->hasAttr<OpenCLKernelAttr>()) { // These attributes cannot be applied to a non-kernel function. - if (Attr *A = D->getAttr<ReqdWorkGroupSizeAttr>()) { + if (const auto *A = D->getAttr<ReqdWorkGroupSizeAttr>()) { // FIXME: This emits a different error message than // diag::err_attribute_wrong_decl_type + ExpectedKernelFunction. Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) { + } else if (const auto *A = D->getAttr<WorkGroupSizeHintAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<VecTypeHintAttr>()) { + } else if (const auto *A = D->getAttr<VecTypeHintAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) { - Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; - D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUWavesPerEUAttr>()) { - Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; - D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUNumSGPRAttr>()) { - Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; - D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUNumVGPRAttr>()) { - Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; - D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) { + } else if (const auto *A = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); + } else if (!D->hasAttr<CUDAGlobalAttr>()) { + if (const auto *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (const auto *A = D->getAttr<AMDGPUWavesPerEUAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (const auto *A = D->getAttr<AMDGPUNumSGPRAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (const auto *A = D->getAttr<AMDGPUNumVGPRAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } } } } // Helper for delayed processing TransparentUnion attribute. -void Sema::ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList) { - for (const AttributeList *Attr = AttrList; Attr; Attr = Attr->getNext()) - if (Attr->getKind() == AttributeList::AT_TransparentUnion) { - handleTransparentUnionAttr(*this, D, *Attr); +void Sema::ProcessDeclAttributeDelayed(Decl *D, + const ParsedAttributesView &AttrList) { + for (const ParsedAttr &AL : AttrList) + if (AL.getKind() == ParsedAttr::AT_TransparentUnion) { + handleTransparentUnionAttr(*this, D, AL); break; } } // Annotation attributes are the only attributes allowed after an access // specifier. -bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, - const AttributeList *AttrList) { - for (const AttributeList* l = AttrList; l; l = l->getNext()) { - if (l->getKind() == AttributeList::AT_Annotate) { - ProcessDeclAttribute(*this, nullptr, ASDecl, *l, l->isCXX11Attribute()); +bool Sema::ProcessAccessDeclAttributeList( + AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) { + for (const ParsedAttr &AL : AttrList) { + if (AL.getKind() == ParsedAttr::AT_Annotate) { + ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute()); } else { - Diag(l->getLoc(), diag::err_only_annotate_after_access_spec); + Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec); return true; } } - return false; } /// checkUnusedDeclAttributes - Check a list of attributes to see if it /// contains any decl attributes that we should warn about. -static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { - for ( ; A; A = A->getNext()) { +static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) { + for (const ParsedAttr &AL : A) { // Only warn if the attribute is an unignored, non-type attribute. - if (A->isUsedAsTypeAttr() || A->isInvalid()) continue; - if (A->getKind() == AttributeList::IgnoredAttribute) continue; + if (AL.isUsedAsTypeAttr() || AL.isInvalid()) + continue; + if (AL.getKind() == ParsedAttr::IgnoredAttribute) + continue; - if (A->getKind() == AttributeList::UnknownAttribute) { - S.Diag(A->getLoc(), diag::warn_unknown_attribute_ignored) - << A->getName() << A->getRange(); + if (AL.getKind() == ParsedAttr::UnknownAttribute) { + S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + << AL.getName() << AL.getRange(); } else { - S.Diag(A->getLoc(), diag::warn_attribute_not_on_decl) - << A->getName() << A->getRange(); + S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) + << AL.getName() << AL.getRange(); } } } @@ -6687,7 +6721,7 @@ static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { /// used to build a declaration, complain about any decl attributes /// which might be lying around on it. void Sema::checkUnusedDeclAttributes(Declarator &D) { - ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes().getList()); + ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes()); ::checkUnusedDeclAttributes(*this, D.getAttributes()); for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) ::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs()); @@ -6699,7 +6733,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, SourceLocation Loc) { assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND)); NamedDecl *NewD = nullptr; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + if (auto *FD = dyn_cast<FunctionDecl>(ND)) { FunctionDecl *NewFD; // FIXME: Missing call to CheckFunctionDeclaration(). // FIXME: Mangling? @@ -6719,7 +6753,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, // Fake up parameter variables; they are declared as if this were // a typedef. QualType FDTy = FD->getType(); - if (const FunctionProtoType *FT = FDTy->getAs<FunctionProtoType>()) { + if (const auto *FT = FDTy->getAs<FunctionProtoType>()) { SmallVector<ParmVarDecl*, 16> Params; for (const auto &AI : FT->param_types()) { ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, AI); @@ -6728,15 +6762,13 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, } NewFD->setParams(Params); } - } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { + } else if (auto *VD = dyn_cast<VarDecl>(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getInnerLocStart(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass()); - if (VD->getQualifier()) { - VarDecl *NewVD = cast<VarDecl>(NewD); - NewVD->setQualifierInfo(VD->getQualifierLoc()); - } + if (VD->getQualifier()) + cast<VarDecl>(NewD)->setQualifierInfo(VD->getQualifierLoc()); } return NewD; } @@ -6772,10 +6804,10 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) { LoadExternalWeakUndeclaredIdentifiers(); if (!WeakUndeclaredIdentifiers.empty()) { NamedDecl *ND = nullptr; - if (VarDecl *VD = dyn_cast<VarDecl>(D)) + if (auto *VD = dyn_cast<VarDecl>(D)) if (VD->isExternC()) ND = VD; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (auto *FD = dyn_cast<FunctionDecl>(D)) if (FD->isExternC()) ND = FD; if (ND) { @@ -6796,20 +6828,19 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) { /// specified in many different places, and we need to find and apply them all. void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { // Apply decl attributes from the DeclSpec if present. - if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList()) - ProcessDeclAttributeList(S, D, Attrs); + if (!PD.getDeclSpec().getAttributes().empty()) + ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes()); // Walk the declarator structure, applying decl attributes that were in a type // position to the decl itself. This handles cases like: // int *__attr__(x)** D; // when X is a decl attribute. for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) - if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs()) - ProcessDeclAttributeList(S, D, Attrs, /*IncludeCXX11Attributes=*/false); + ProcessDeclAttributeList(S, D, PD.getTypeObject(i).getAttrs(), + /*IncludeCXX11Attributes=*/false); // Finally, apply any attributes on the decl itself. - if (const AttributeList *Attrs = PD.getAttributes()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, PD.getAttributes()); // Apply additional attributes specified by '#pragma clang attribute'. AddPragmaAttributes(S, D); @@ -6818,14 +6849,14 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { /// Is the given declaration allowed to use a forbidden type? /// If so, it'll still be annotated with an attribute that makes it /// illegal to actually use. -static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, +static bool isForbiddenTypeAllowed(Sema &S, Decl *D, const DelayedDiagnostic &diag, UnavailableAttr::ImplicitReason &reason) { // Private ivars are always okay. Unfortunately, people don't // always properly make their ivars private, even in system headers. // Plus we need to make fields okay, too. - if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl) && - !isa<FunctionDecl>(decl)) + if (!isa<FieldDecl>(D) && !isa<ObjCPropertyDecl>(D) && + !isa<FunctionDecl>(D)) return false; // Silently accept unsupported uses of __weak in both user and system @@ -6833,7 +6864,7 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, // -fno-objc-arc files. We do have to take some care against attempts // to define such things; for now, we've only done that for ivars // and properties. - if ((isa<ObjCIvarDecl>(decl) || isa<ObjCPropertyDecl>(decl))) { + if ((isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) { if (diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_disabled || diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_no_runtime) { reason = UnavailableAttr::IR_ForbiddenWeak; @@ -6842,7 +6873,7 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, } // Allow all sorts of things in system headers. - if (S.Context.getSourceManager().isInSystemHeader(decl->getLocation())) { + if (S.Context.getSourceManager().isInSystemHeader(D->getLocation())) { // Currently, all the failures dealt with this way are due to ARC // restrictions. reason = UnavailableAttr::IR_ARCForbiddenType; @@ -6853,30 +6884,29 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, } /// Handle a delayed forbidden-type diagnostic. -static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, - Decl *decl) { - auto reason = UnavailableAttr::IR_None; - if (decl && isForbiddenTypeAllowed(S, decl, diag, reason)) { - assert(reason && "didn't set reason?"); - decl->addAttr(UnavailableAttr::CreateImplicit(S.Context, "", reason, - diag.Loc)); +static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &DD, + Decl *D) { + auto Reason = UnavailableAttr::IR_None; + if (D && isForbiddenTypeAllowed(S, D, DD, Reason)) { + assert(Reason && "didn't set reason?"); + D->addAttr(UnavailableAttr::CreateImplicit(S.Context, "", Reason, DD.Loc)); return; } if (S.getLangOpts().ObjCAutoRefCount) - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { // FIXME: we may want to suppress diagnostics for all - // kind of forbidden type messages on unavailable functions. + // kind of forbidden type messages on unavailable functions. if (FD->hasAttr<UnavailableAttr>() && - diag.getForbiddenTypeDiagnostic() == - diag::err_arc_array_param_no_ownership) { - diag.Triggered = true; + DD.getForbiddenTypeDiagnostic() == + diag::err_arc_array_param_no_ownership) { + DD.Triggered = true; return; } } - S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) - << diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument(); - diag.Triggered = true; + S.Diag(DD.Loc, DD.getForbiddenTypeDiagnostic()) + << DD.getForbiddenTypeOperand() << DD.getForbiddenTypeArgument(); + DD.Triggered = true; } static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, @@ -6919,9 +6949,9 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { // For typedefs, if the typedef declaration appears available look // to the underlying type to see if it is more restrictive. - while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { + while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { if (Result == AR_Available) { - if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { + if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) { D = TT->getDecl(); Result = D->getAvailability(Message); continue; @@ -6931,7 +6961,7 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { } // Forward class declarations get their attributes from their definition. - if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { + if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); Result = D->getAvailability(Message); @@ -6951,7 +6981,7 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { } -/// \brief whether we should emit a diagnostic for \c K and \c DeclVersion in +/// whether we should emit a diagnostic for \c K and \c DeclVersion in /// the context of \c Ctx. For example, we should emit an unavailable diagnostic /// in a deprecated context, but not the other way around. static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, @@ -6974,40 +7004,24 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, return false; }; - // FIXME: This is a temporary workaround! Some existing Apple headers depends - // on nested declarations in an @interface having the availability of the - // interface when they really shouldn't: they are members of the enclosing - // context, and can referenced from there. - if (S.OriginalLexicalContext && cast<Decl>(S.OriginalLexicalContext) != Ctx) { - auto *OrigCtx = cast<Decl>(S.OriginalLexicalContext); - if (CheckContext(OrigCtx)) - return false; - - // An implementation implicitly has the availability of the interface. - if (auto *CatOrImpl = dyn_cast<ObjCImplDecl>(OrigCtx)) { - if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) - if (CheckContext(Interface)) - return false; - } - // A category implicitly has the availability of the interface. - else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(OrigCtx)) - if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) - if (CheckContext(Interface)) - return false; - } - do { if (CheckContext(Ctx)) return false; // An implementation implicitly has the availability of the interface. - if (auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { + // Unless it is "+load" method. + if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx)) + if (MethodD->isClassMethod() && + MethodD->getSelector().getAsString() == "load") + return true; + + if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) if (CheckContext(Interface)) return false; } // A category implicitly has the availability of the interface. - else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) + else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) if (CheckContext(Interface)) return false; @@ -7077,6 +7091,45 @@ struct AttributeInsertion { } // end anonymous namespace +/// Tries to parse a string as ObjC method name. +/// +/// \param Name The string to parse. Expected to originate from availability +/// attribute argument. +/// \param SlotNames The vector that will be populated with slot names. In case +/// of unsuccessful parsing can contain invalid data. +/// \returns A number of method parameters if parsing was successful, None +/// otherwise. +static Optional<unsigned> +tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, + const LangOptions &LangOpts) { + // Accept replacements starting with - or + as valid ObjC method names. + if (!Name.empty() && (Name.front() == '-' || Name.front() == '+')) + Name = Name.drop_front(1); + if (Name.empty()) + return None; + Name.split(SlotNames, ':'); + unsigned NumParams; + if (Name.back() == ':') { + // Remove an empty string at the end that doesn't represent any slot. + SlotNames.pop_back(); + NumParams = SlotNames.size(); + } else { + if (SlotNames.size() != 1) + // Not a valid method name, just a colon-separated string. + return None; + NumParams = 0; + } + // Verify all slot names are valid. + bool AllowDollar = LangOpts.DollarIdents; + for (StringRef S : SlotNames) { + if (S.empty()) + continue; + if (!isValidIdentifier(S, AllowDollar)) + return None; + } + return NumParams; +} + /// Returns a source location in which it's appropriate to insert a new /// attribute for the given declaration \D. static Optional<AttributeInsertion> @@ -7106,14 +7159,15 @@ createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, /// \param Ctx The context that the reference occurred in /// \param ReferringDecl The exact declaration that was referenced. /// \param OffendingDecl A related decl to \c ReferringDecl that has an -/// availability attribute corrisponding to \c K attached to it. Note that this +/// availability attribute corresponding to \c K attached to it. Note that this /// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and /// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl /// and OffendingDecl is the EnumDecl. static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, - StringRef Message, SourceLocation Loc, + StringRef Message, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { @@ -7135,6 +7189,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) return; + SourceLocation Loc = Locs.front(); + // The declaration can have multiple availability attributes, we are looking // at one of them. const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); @@ -7178,7 +7234,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, << OffendingDecl << /* partial */ 3; if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { - if (auto *TD = dyn_cast<TagDecl>(Enclosing)) + if (const auto *TD = dyn_cast<TagDecl>(Enclosing)) if (TD->getDeclName().isEmpty()) { S.Diag(TD->getLocation(), diag::note_decl_unguarded_availability_silence) @@ -7219,8 +7275,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; property_note_select = /* deprecated */ 0; available_here_select_kind = /* deprecated */ 2; - if (const auto *Attr = OffendingDecl->getAttr<DeprecatedAttr>()) - NoteLocation = Attr->getLocation(); + if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>()) + NoteLocation = AL->getLocation(); break; case AR_Unavailable: @@ -7231,8 +7287,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, property_note_select = /* unavailable */ 1; available_here_select_kind = /* unavailable */ 0; - if (auto Attr = OffendingDecl->getAttr<UnavailableAttr>()) { - if (Attr->isImplicit() && Attr->getImplicitReason()) { + if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) { + if (AL->isImplicit() && AL->getImplicitReason()) { // Most of these failures are due to extra restrictions in ARC; // reflect that in the primary diagnostic when applicable. auto flagARCError = [&] { @@ -7242,7 +7298,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag = diag::err_unavailable_in_arc; }; - switch (Attr->getImplicitReason()) { + switch (AL->getImplicitReason()) { case UnavailableAttr::IR_None: break; case UnavailableAttr::IR_ARCForbiddenType: @@ -7280,37 +7336,55 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, llvm_unreachable("Warning for availability of available declaration?"); } - CharSourceRange UseRange; - StringRef Replacement; + SmallVector<FixItHint, 12> FixIts; if (K == AR_Deprecated) { - if (auto Attr = OffendingDecl->getAttr<DeprecatedAttr>()) - Replacement = Attr->getReplacement(); - if (auto Attr = getAttrForPlatform(S.Context, OffendingDecl)) - Replacement = Attr->getReplacement(); + StringRef Replacement; + if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>()) + Replacement = AL->getReplacement(); + if (auto AL = getAttrForPlatform(S.Context, OffendingDecl)) + Replacement = AL->getReplacement(); + CharSourceRange UseRange; if (!Replacement.empty()) UseRange = CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + if (UseRange.isValid()) { + if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) { + Selector Sel = MethodDecl->getSelector(); + SmallVector<StringRef, 12> SelectorSlotNames; + Optional<unsigned> NumParams = tryParseObjCMethodName( + Replacement, SelectorSlotNames, S.getLangOpts()); + if (NumParams && NumParams.getValue() == Sel.getNumArgs()) { + assert(SelectorSlotNames.size() == Locs.size()); + for (unsigned I = 0; I < Locs.size(); ++I) { + if (!Sel.getNameForSlot(I).empty()) { + CharSourceRange NameRange = CharSourceRange::getCharRange( + Locs[I], S.getLocForEndOfToken(Locs[I])); + FixIts.push_back(FixItHint::CreateReplacement( + NameRange, SelectorSlotNames[I])); + } else + FixIts.push_back( + FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I])); + } + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } } if (!Message.empty()) { - S.Diag(Loc, diag_message) << ReferringDecl << Message - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << ReferringDecl - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag) << ReferringDecl << FixIts; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << ReferringDecl - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts; S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } @@ -7326,8 +7400,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, DD.Triggered = true; DoEmitAvailabilityWarning( S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(), - DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc, - DD.getUnknownObjCClass(), DD.getObjCProperty(), false); + DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), + DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(), + DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -7388,7 +7463,8 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, - StringRef Message, SourceLocation Loc, + StringRef Message, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { @@ -7396,14 +7472,14 @@ static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { S.DelayedDiagnostics.add( DelayedDiagnostic::makeAvailability( - AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass, + AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast<Decl>(S.getCurLexicalContext()); DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl, - Message, Loc, UnknownObjCClass, ObjCProperty, + Message, Locs, UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } @@ -7472,7 +7548,7 @@ public: } }; -/// \brief This class implements -Wunguarded-availability. +/// This class implements -Wunguarded-availability. /// /// This is done with a traversal of the AST of a function that makes reference /// to a partially available declaration. Whenever we encounter an \c if of the @@ -7643,7 +7719,7 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( SourceLocation StmtEndLoc = SM.getExpansionRange( (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getLocEnd()) - .second; + .getEnd(); if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc)) return; @@ -7682,11 +7758,11 @@ bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) { if (Range.isInvalid()) return true; - if (const TagType *TT = dyn_cast<TagType>(TyPtr)) { + if (const auto *TT = dyn_cast<TagType>(TyPtr)) { TagDecl *TD = TT->getDecl(); DiagnoseDeclAvailability(TD, Range); - } else if (const TypedefType *TD = dyn_cast<TypedefType>(TyPtr)) { + } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) { TypedefNameDecl *D = TD->getDecl(); DiagnoseDeclAvailability(D, Range); @@ -7741,7 +7817,8 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) { DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body); } -void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, +void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks) { @@ -7770,7 +7847,7 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, } const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = PD->getAvailability(nullptr); if (PDeclResult == Result) @@ -7778,6 +7855,6 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, } } - EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Loc, + EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs, UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess); } diff --git a/gnu/llvm/tools/lld/ELF/Config.h b/gnu/llvm/tools/lld/ELF/Config.h index c7b58cf5b86..81c141ca011 100644 --- a/gnu/llvm/tools/lld/ELF/Config.h +++ b/gnu/llvm/tools/lld/ELF/Config.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_CONFIG_H #define LLD_ELF_CONFIG_H +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" @@ -17,13 +18,13 @@ #include "llvm/Support/CachePruning.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Endian.h" - #include <vector> namespace lld { namespace elf { class InputFile; +class InputSectionBase; enum ELFKind { ELFNoneKind, @@ -39,6 +40,9 @@ enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; // For --discard-{all,locals,none}. enum class DiscardPolicy { Default, All, Locals, None }; +// For --icf={none,safe,all}. +enum class ICFLevel { None, Safe, All }; + // For --strip-{all,debug}. enum class StripPolicy { None, All, Debug }; @@ -54,6 +58,9 @@ enum class SortSectionPolicy { Default, None, Alignment, Name, Priority }; // For --target2 enum class Target2Policy { Abs, Rel, GotRel }; +// For tracking ARM Float Argument PCS +enum class ARMVFPArgKind { Default, Base, VFP, ToolChain }; + struct SymbolVersion { llvm::StringRef Name; bool IsExternCpp; @@ -79,21 +86,27 @@ struct Configuration { llvm::StringMap<uint64_t> SectionStartMap; llvm::StringRef Chroot; llvm::StringRef DynamicLinker; + llvm::StringRef DwoDir; llvm::StringRef Entry; llvm::StringRef Emulation; llvm::StringRef Fini; llvm::StringRef Init; llvm::StringRef LTOAAPipeline; llvm::StringRef LTONewPmPasses; + llvm::StringRef LTOObjPath; + llvm::StringRef LTOSampleProfile; llvm::StringRef MapFile; llvm::StringRef OutputFile; llvm::StringRef OptRemarksFilename; + llvm::StringRef ProgName; llvm::StringRef SoName; llvm::StringRef Sysroot; llvm::StringRef ThinLTOCacheDir; + llvm::StringRef ThinLTOIndexOnlyArg; + std::pair<llvm::StringRef, llvm::StringRef> ThinLTOObjectSuffixReplace; + std::pair<llvm::StringRef, llvm::StringRef> ThinLTOPrefixReplace; std::string Rpath; std::vector<VersionDefinition> VersionDefinitions; - std::vector<llvm::StringRef> Argv; std::vector<llvm::StringRef> AuxiliaryList; std::vector<llvm::StringRef> FilterList; std::vector<llvm::StringRef> SearchPaths; @@ -103,34 +116,41 @@ struct Configuration { std::vector<SymbolVersion> VersionScriptGlobals; std::vector<SymbolVersion> VersionScriptLocals; std::vector<uint8_t> BuildIdVector; + llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>, + uint64_t> + CallGraphProfile; bool AllowMultipleDefinition; - bool AndroidPackDynRelocs = false; + bool AndroidPackDynRelocs; bool ARMHasBlx = false; bool ARMHasMovtMovw = false; bool ARMJ1J2BranchEncoding = false; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; + bool CheckSections; bool CompressDebugSections; + bool Cref; bool DefineCommon; bool Demangle = true; bool DisableVerify; bool EhFrameHdr; bool EmitRelocs; bool EnableNewDtags; + bool ExecuteOnly; bool ExportDynamic; bool FixCortexA53Errata843419; bool GcSections; bool GdbIndex; bool GnuHash = false; + bool GnuUnique; bool HasDynamicList = false; bool HasDynSymTab; - bool ICF; - bool ICFData; + bool IgnoreDataAddressEquality; + bool IgnoreFunctionAddressEquality; + bool LTODebugPassManager; + bool LTONewPassManager; bool MergeArmExidx; bool MipsN32Abi = false; - bool NoGnuUnique; - bool NoUndefinedVersion; bool NoinhibitExec; bool Nostdlib; bool OFormatBinary; @@ -138,7 +158,9 @@ struct Configuration { bool OptRemarksWithHotness; bool Pie; bool PrintGcSections; + bool PrintIcfSections; bool Relocatable; + bool RelrPackDynRelocs; bool SaveTemps; bool SingleRoRx; bool Shared; @@ -146,13 +168,22 @@ struct Configuration { bool SysvHash = false; bool Target1Rel; bool Trace; - bool Verbose; + bool ThinLTOEmitImportsFiles; + bool ThinLTOIndexOnly; + bool UndefinedVersion; + bool UseAndroidRelrTags = false; + bool WarnBackrefs; bool WarnCommon; bool WarnMissingEntry; + bool WarnSymbolOrdering; + bool WriteAddends; bool ZCombreloc; + bool ZCopyreloc; bool ZExecstack; + bool ZHazardplt; bool ZInitfirst; - bool ZNocopyreloc; + bool ZInterpose; + bool ZKeepTextSectionPrefix; bool ZNodelete; bool ZNodlopen; bool ZNow; @@ -161,20 +192,22 @@ struct Configuration { bool ZRodynamic; bool ZText; bool ZRetpolineplt; - bool ExitEarly; bool ZWxneeded; DiscardPolicy Discard; + ICFLevel ICF; OrphanHandlingPolicy OrphanHandling; SortSectionPolicy SortSection; StripPolicy Strip; UnresolvedPolicy UnresolvedSymbols; Target2Policy Target2; + ARMVFPArgKind ARMVFPArgs = ARMVFPArgKind::Default; BuildIdKind BuildId = BuildIdKind::None; ELFKind EKind = ELFNoneKind; uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; llvm::Optional<uint64_t> ImageBase; uint64_t MaxPageSize; + uint64_t MipsGotSize; uint64_t ZStackSize; unsigned LTOPartitions; unsigned LTOO; @@ -240,6 +273,12 @@ struct Configuration { // The only instance of Configuration struct. extern Configuration *Config; +static inline void errorOrWarn(const Twine &Msg) { + if (!Config->NoinhibitExec) + error(Msg); + else + warn(Msg); +} } // namespace elf } // namespace lld diff --git a/gnu/llvm/tools/lld/ELF/Driver.cpp b/gnu/llvm/tools/lld/ELF/Driver.cpp index 602c72058c4..5d8e5d84a37 100644 --- a/gnu/llvm/tools/lld/ELF/Driver.cpp +++ b/gnu/llvm/tools/lld/ELF/Driver.cpp @@ -30,9 +30,9 @@ #include "InputFiles.h" #include "InputSection.h" #include "LinkerScript.h" +#include "MarkLive.h" #include "OutputSections.h" #include "ScriptParser.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" @@ -42,12 +42,16 @@ #include "lld/Common/Driver.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" +#include "lld/Common/TargetOptionsCommandFlags.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" @@ -66,16 +70,18 @@ using namespace lld::elf; Configuration *elf::Config; LinkerDriver *elf::Driver; -static void setConfigs(); +static void setConfigs(opt::InputArgList &Args); bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Error) { - errorHandler().LogName = Args[0]; + errorHandler().LogName = sys::path::filename(Args[0]); errorHandler().ErrorLimitExceededMsg = "too many errors emitted, stopping now (use " "-error-limit=0 to see all errors)"; errorHandler().ErrorOS = &Error; + errorHandler().ExitEarly = CanExitEarly; errorHandler().ColorDiagnostics = Error.has_colors(); + InputSections.clear(); OutputSections.clear(); Tar = nullptr; @@ -88,14 +94,14 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, Driver = make<LinkerDriver>(); Script = make<LinkerScript>(); Symtab = make<SymbolTable>(); - Config->Argv = {Args.begin(), Args.end()}; + Config->ProgName = Args[0]; - Driver->main(Args, CanExitEarly); + Driver->main(Args); // Exit immediately if we don't need to return to the caller. // This saves time because the overhead of calling destructors // for all globally-allocated objects is not negligible. - if (Config->ExitEarly) + if (CanExitEarly) exitLld(errorCount() ? 1 : 0); freeArena(); @@ -113,7 +119,8 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { std::pair<ELFKind, uint16_t> Ret = StringSwitch<std::pair<ELFKind, uint16_t>>(S) - .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) + .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec", + {ELF64LEKind, EM_AARCH64}) .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) @@ -122,6 +129,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) + .Case("elf64lppc", {ELF64LEKind, EM_PPC64}) .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) .Case("elf_i386", {ELF32LEKind, EM_386}) .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) @@ -228,11 +236,15 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { Files.push_back( createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path)); return; - default: + case file_magic::bitcode: + case file_magic::elf_relocatable: if (InLib) Files.push_back(make<LazyObjFile>(MBRef, "", 0)); else Files.push_back(createObjectFile(MBRef)); + break; + default: + error(Path + ": unknown file type"); } } @@ -248,18 +260,11 @@ void LinkerDriver::addLibrary(StringRef Name) { // LTO calls LLVM functions to compile bitcode files to native code. // Technically this can be delayed until we read bitcode files, but // we don't bother to do lazily because the initialization is fast. -static void initLLVM(opt::InputArgList &Args) { +static void initLLVM() { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); - - // Parse and evaluate -mllvm options. - std::vector<const char *> V; - V.push_back("lld (LLVM option parsing)"); - for (auto *Arg : Args.filtered(OPT_mllvm)) - V.push_back(Arg->getValue()); - cl::ParseCommandLineOptions(V.size(), V.data()); } // Some command line options or some combinations of them are not allowed. @@ -290,11 +295,21 @@ static void checkOptions(opt::InputArgList &Args) { error("-r and -shared may not be used together"); if (Config->GcSections) error("-r and --gc-sections may not be used together"); - if (Config->ICF) + if (Config->GdbIndex) + error("-r and --gdb-index may not be used together"); + if (Config->ICF != ICFLevel::None) error("-r and --icf may not be used together"); if (Config->Pie) error("-r and -pie may not be used together"); } + + if (Config->ExecuteOnly) { + if (Config->EMachine != EM_AARCH64) + error("-execute-only is only supported on AArch64 targets"); + + if (Config->SingleRoRx && !Script->HasSectionsCommand) + error("-execute-only and -no-rosegment cannot be used together"); + } } static const char *getReproduceOption(opt::InputArgList &Args) { @@ -310,7 +325,38 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) { return false; } -void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { +static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2, + bool Default) { + for (auto *Arg : Args.filtered_reverse(OPT_z)) { + if (K1 == Arg->getValue()) + return true; + if (K2 == Arg->getValue()) + return false; + } + return Default; +} + +static bool isKnown(StringRef S) { + return S == "combreloc" || S == "copyreloc" || S == "defs" || + S == "execstack" || S == "hazardplt" || S == "initfirst" || + S == "interpose" || + S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" || + S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" || + S == "nodlopen" || S == "noexecstack" || + S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" || + S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" || + S == "rodynamic" || S == "text" || S == "wxneeded" || + S.startswith("max-page-size=") || S.startswith("stack-size="); +} + +// Report an error for an unknown -z option. +static void checkZOptions(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered(OPT_z)) + if (!isKnown(Arg->getValue())) + error("unknown -z value: " + StringRef(Arg->getValue())); +} + +void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { ELFOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); @@ -319,7 +365,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { // Handle -help if (Args.hasArg(OPT_help)) { - printHelp(ArgsArr[0]); + printHelp(); return; } @@ -348,9 +394,6 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { if (Args.hasArg(OPT_version)) return; - Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); - errorHandler().ExitEarly = Config->ExitEarly; - if (const char *Path = getReproduceOption(Args)) { // Note that --reproduce is a debug option so you can ignore it // if you are trying to understand the whole picture of the code. @@ -368,10 +411,14 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { } readConfigs(Args); - initLLVM(Args); + checkZOptions(Args); + initLLVM(); createFiles(Args); + if (errorCount()) + return; + inferMachineType(); - setConfigs(); + setConfigs(Args); checkOptions(Args); if (errorCount()) return; @@ -455,6 +502,8 @@ static bool isOutputFormatBinary(opt::InputArgList &Args) { StringRef S = Arg->getValue(); if (S == "binary") return true; + if (S.startswith("elf")) + return false; error("unknown --oformat value: " + S); } return false; @@ -482,6 +531,15 @@ static StringRef getDynamicLinker(opt::InputArgList &Args) { return Arg->getValue(); } +static ICFLevel getICF(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all); + if (!Arg || Arg->getOption().getID() == OPT_icf_none) + return ICFLevel::None; + if (Arg->getOption().getID() == OPT_icf_safe) + return ICFLevel::Safe; + return ICFLevel::All; +} + static StripPolicy getStrip(opt::InputArgList &Args) { if (Args.hasArg(OPT_relocatable)) return StripPolicy::None; @@ -556,6 +614,8 @@ getBuildId(opt::InputArgList &Args) { return {BuildIdKind::Fast, {}}; StringRef S = Arg->getValue(); + if (S == "fast") + return {BuildIdKind::Fast, {}}; if (S == "md5") return {BuildIdKind::Md5, {}}; if (S == "sha1" || S == "tree") @@ -570,6 +630,57 @@ getBuildId(opt::InputArgList &Args) { return {BuildIdKind::None, {}}; } +static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_pack_dyn_relocs, "none"); + if (S == "android") + return {true, false}; + if (S == "relr") + return {false, true}; + if (S == "android+relr") + return {true, true}; + + if (S != "none") + error("unknown -pack-dyn-relocs format: " + S); + return {false, false}; +} + +static void readCallGraph(MemoryBufferRef MB) { + // Build a map from symbol name to section + DenseMap<StringRef, const Symbol *> SymbolNameToSymbol; + for (InputFile *File : ObjectFiles) + for (Symbol *Sym : File->getSymbols()) + SymbolNameToSymbol[Sym->getName()] = Sym; + + for (StringRef L : args::getLines(MB)) { + SmallVector<StringRef, 3> Fields; + L.split(Fields, ' '); + uint64_t Count; + if (Fields.size() != 3 || !to_integer(Fields[2], Count)) + fatal(MB.getBufferIdentifier() + ": parse error"); + const Symbol *FromSym = SymbolNameToSymbol.lookup(Fields[0]); + const Symbol *ToSym = SymbolNameToSymbol.lookup(Fields[1]); + if (Config->WarnSymbolOrdering) { + if (!FromSym) + warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[0]); + if (!ToSym) + warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[1]); + } + if (!FromSym || !ToSym || Count == 0) + continue; + warnUnorderableSymbol(FromSym); + warnUnorderableSymbol(ToSym); + const Defined *FromSymD = dyn_cast<Defined>(FromSym); + const Defined *ToSymD = dyn_cast<Defined>(ToSym); + if (!FromSymD || !ToSymD) + continue; + const auto *FromSB = dyn_cast_or_null<InputSectionBase>(FromSymD->Section); + const auto *ToSB = dyn_cast_or_null<InputSectionBase>(ToSymD->Section); + if (!FromSB || !ToSB) + continue; + Config->CallGraphProfile[std::make_pair(FromSB, ToSB)] += Count; + } +} + static bool getCompressDebugSections(opt::InputArgList &Args) { StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none"); if (S == "none") @@ -581,54 +692,101 @@ static bool getCompressDebugSections(opt::InputArgList &Args) { return true; } -static int parseInt(StringRef S, opt::Arg *Arg) { - int V = 0; - if (!to_integer(S, V, 10)) - error(Arg->getSpelling() + ": number expected, but got '" + S + "'"); - return V; +static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &Args, + unsigned Id) { + auto *Arg = Args.getLastArg(Id); + if (!Arg) + return {"", ""}; + + StringRef S = Arg->getValue(); + std::pair<StringRef, StringRef> Ret = S.split(';'); + if (Ret.second.empty()) + error(Arg->getSpelling() + " expects 'old;new' format, but got " + S); + return Ret; +} + +// Parse the symbol ordering file and warn for any duplicate entries. +static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef MB) { + SetVector<StringRef> Names; + for (StringRef S : args::getLines(MB)) + if (!Names.insert(S) && Config->WarnSymbolOrdering) + warn(MB.getBufferIdentifier() + ": duplicate ordered symbol: " + S); + + return Names.takeVector(); +} + +static void parseClangOption(StringRef Opt, const Twine &Msg) { + std::string Err; + raw_string_ostream OS(Err); + + const char *Argv[] = {Config->ProgName.data(), Opt.data()}; + if (cl::ParseCommandLineOptions(2, Argv, "", &OS)) + return; + OS.flush(); + error(Msg + ": " + StringRef(Err).trim()); } // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { + errorHandler().Verbose = Args.hasArg(OPT_verbose); + errorHandler().FatalWarnings = + Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); + ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); + Config->AllowMultipleDefinition = - Args.hasArg(OPT_allow_multiple_definition) || hasZOption(Args, "muldefs"); + Args.hasFlag(OPT_allow_multiple_definition, + OPT_no_allow_multiple_definition, false) || + hasZOption(Args, "muldefs"); Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); + Config->CheckSections = + Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); Config->Chroot = Args.getLastArgValue(OPT_chroot); Config->CompressDebugSections = getCompressDebugSections(Args); + Config->Cref = Args.hasFlag(OPT_cref, OPT_no_cref, false); Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common, !Args.hasArg(OPT_relocatable)); Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); Config->DisableVerify = Args.hasArg(OPT_disable_verify); Config->Discard = getDiscard(Args); + Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq); Config->DynamicLinker = getDynamicLinker(Args); Config->EhFrameHdr = Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false); Config->EmitRelocs = Args.hasArg(OPT_emit_relocs); - Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags); + Config->EnableNewDtags = + Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true); Config->Entry = Args.getLastArgValue(OPT_entry); + Config->ExecuteOnly = + Args.hasFlag(OPT_execute_only, OPT_no_execute_only, false); Config->ExportDynamic = Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); - errorHandler().FatalWarnings = - Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); Config->FilterList = args::getStrings(Args, OPT_filter); Config->Fini = Args.getLastArgValue(OPT_fini, "_fini"); Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419); Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); + Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true); Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); - Config->ICF = Args.hasFlag(OPT_icf_all, OPT_icf_none, false); - Config->ICFData = Args.hasArg(OPT_icf_data); + Config->ICF = getICF(Args); + Config->IgnoreDataAddressEquality = + Args.hasArg(OPT_ignore_data_address_equality); + Config->IgnoreFunctionAddressEquality = + Args.hasFlag(OPT_ignore_function_address_equality, + OPT_no_ignore_function_address_equality, true); Config->Init = Args.getLastArgValue(OPT_init, "_init"); Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline); + Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager); + Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager); Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes); Config->LTOO = args::getInteger(Args, OPT_lto_O, 2); + Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq); Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); + Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile); Config->MapFile = Args.getLastArgValue(OPT_Map); - Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique); + Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0); Config->MergeArmExidx = Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); - Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version); Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec); Config->Nostdlib = Args.hasArg(OPT_nostdlib); Config->OFormatBinary = isOutputFormatBinary(Args); @@ -639,11 +797,13 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->OrphanHandling = getOrphanHandling(Args); Config->OutputFile = Args.getLastArgValue(OPT_o); #ifdef __OpenBSD__ - Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, + Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, !Args.hasArg(OPT_shared) && !Args.hasArg(OPT_relocatable)); #else - Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false); + Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false); #endif + Config->PrintIcfSections = + Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false); Config->PrintGcSections = Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); Config->Rpath = getRpath(Args); @@ -663,48 +823,59 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->ThinLTOCachePolicy = CHECK( parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)), "--thinlto-cache-policy: invalid cache policy"); + Config->ThinLTOEmitImportsFiles = + Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files); + Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) || + Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq); + Config->ThinLTOIndexOnlyArg = + Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq); Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u); - ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); + Config->ThinLTOObjectSuffixReplace = + getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq); + Config->ThinLTOPrefixReplace = + getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq); Config->Trace = Args.hasArg(OPT_trace); Config->Undefined = args::getStrings(Args, OPT_undefined); + Config->UndefinedVersion = + Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true); + Config->UseAndroidRelrTags = Args.hasFlag( + OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false); Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args); - Config->Verbose = Args.hasArg(OPT_verbose); - errorHandler().Verbose = Config->Verbose; - Config->WarnCommon = Args.hasArg(OPT_warn_common); - Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); - Config->ZExecstack = hasZOption(Args, "execstack"); + Config->WarnBackrefs = + Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); + Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); + Config->WarnSymbolOrdering = + Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); + Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true); + Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true); + Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false); + Config->ZHazardplt = hasZOption(Args, "hazardplt"); Config->ZInitfirst = hasZOption(Args, "initfirst"); - Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc"); + Config->ZInterpose = hasZOption(Args, "interpose"); + Config->ZKeepTextSectionPrefix = getZFlag( + Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); Config->ZNodelete = hasZOption(Args, "nodelete"); Config->ZNodlopen = hasZOption(Args, "nodlopen"); - Config->ZNow = hasZOption(Args, "now"); + Config->ZNow = getZFlag(Args, "now", "lazy", false); Config->ZOrigin = hasZOption(Args, "origin"); - Config->ZRelro = !hasZOption(Args, "norelro"); + Config->ZRelro = getZFlag(Args, "relro", "norelro", true); Config->ZRetpolineplt = hasZOption(Args, "retpolineplt"); Config->ZRodynamic = hasZOption(Args, "rodynamic"); Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0); - Config->ZText = !hasZOption(Args, "notext"); + Config->ZText = getZFlag(Args, "text", "notext", true); Config->ZWxneeded = hasZOption(Args, "wxneeded"); - // Parse LTO plugin-related options for compatibility with gold. - for (auto *Arg : Args.filtered(OPT_plugin_opt, OPT_plugin_opt_eq)) { - StringRef S = Arg->getValue(); - if (S == "disable-verify") - Config->DisableVerify = true; - else if (S == "save-temps") - Config->SaveTemps = true; - else if (S.startswith("O")) - Config->LTOO = parseInt(S.substr(1), Arg); - else if (S.startswith("lto-partitions=")) - Config->LTOPartitions = parseInt(S.substr(15), Arg); - else if (S.startswith("jobs=")) - Config->ThinLTOJobs = parseInt(S.substr(5), Arg); - else if (!S.startswith("/") && !S.startswith("-fresolution=") && - !S.startswith("-pass-through=") && !S.startswith("mcpu=") && - !S.startswith("thinlto") && S != "-function-sections" && - S != "-data-sections") - error(Arg->getSpelling() + ": unknown option: " + S); - } + // Parse LTO options. + if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq)) + parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())), + Arg->getSpelling()); + + for (auto *Arg : Args.filtered(OPT_plugin_opt)) + parseClangOption(Arg->getValue(), Arg->getSpelling()); + + // Parse -mllvm options. + for (auto *Arg : Args.filtered(OPT_mllvm)) + parseClangOption(Arg->getValue(), Arg->getSpelling()); if (Config->LTOO > 3) error("invalid optimization level for LTO: " + Twine(Config->LTOO)); @@ -747,17 +918,12 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args); - if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs_eq)) { - StringRef S = Arg->getValue(); - if (S == "android") - Config->AndroidPackDynRelocs = true; - else if (S != "none") - error("unknown -pack-dyn-relocs format: " + S); - } + std::tie(Config->AndroidPackDynRelocs, Config->RelrPackDynRelocs) = + getPackDynRelocs(Args); if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) - Config->SymbolOrderingFile = args::getLines(*Buffer); + Config->SymbolOrderingFile = getSymbolOrderingFile(*Buffer); // If --retain-symbol-file is used, we'll keep only the symbols listed in // the file and discard all others. @@ -785,32 +951,67 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); } + // If --export-dynamic-symbol=foo is given and symbol foo is defined in + // an object file in an archive file, that object file should be pulled + // out and linked. (It doesn't have to behave like that from technical + // point of view, but this is needed for compatibility with GNU.) + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) + Config->Undefined.push_back(Arg->getValue()); + for (auto *Arg : Args.filtered(OPT_version_script)) - if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) - readVersionScript(*Buffer); + if (Optional<std::string> Path = searchScript(Arg->getValue())) { + if (Optional<MemoryBufferRef> Buffer = readFile(*Path)) + readVersionScript(*Buffer); + } else { + error(Twine("cannot find version script ") + Arg->getValue()); + } } // Some Config members do not directly correspond to any particular // command line options, but computed based on other Config values. // This function initialize such members. See Config.h for the details // of these values. -static void setConfigs() { +static void setConfigs(opt::InputArgList &Args) { ELFKind Kind = Config->EKind; uint16_t Machine = Config->EMachine; - // There is an ILP32 ABI for x86-64, although it's not very popular. - // It is called the x32 ABI. - bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64); - Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs); Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind); Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind); Config->Endianness = Config->IsLE ? support::endianness::little : support::endianness::big; Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS); - Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi; Config->Pic = Config->Pie || Config->Shared; Config->Wordsize = Config->Is64 ? 8 : 4; + + // There is an ILP32 ABI for x86-64, although it's not very popular. + // It is called the x32 ABI. + bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64); + + // ELF defines two different ways to store relocation addends as shown below: + // + // Rel: Addends are stored to the location where relocations are applied. + // Rela: Addends are stored as part of relocation entry. + // + // In other words, Rela makes it easy to read addends at the price of extra + // 4 or 8 byte for each relocation entry. We don't know why ELF defined two + // different mechanisms in the first place, but this is how the spec is + // defined. + // + // You cannot choose which one, Rel or Rela, you want to use. Instead each + // ABI defines which one you need to use. The following expression expresses + // that. + Config->IsRela = + (Config->Is64 || IsX32 || Machine == EM_PPC) && Machine != EM_MIPS; + + // If the output uses REL relocations we must store the dynamic relocation + // addends to the output sections. We also store addends for RELA relocations + // if --apply-dynamic-relocs is used. + // We default to not writing the addends when using RELA relocations since + // any standard conforming tool can find it in r_addend. + Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs, + OPT_no_apply_dynamic_relocs, false) || + !Config->IsRela; } // Returns a value of "-format" option. @@ -825,6 +1026,10 @@ static bool getBinaryOption(StringRef S) { } void LinkerDriver::createFiles(opt::InputArgList &Args) { + // For --{push,pop}-state. + std::vector<std::tuple<bool, bool, bool>> Stack; + + // Iterate over argv to process input files and positional arguments. for (auto *Arg : Args) { switch (Arg->getOption().getUnaliasedOption().getID()) { case OPT_library: @@ -833,8 +1038,15 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { case OPT_INPUT: addFile(Arg->getValue(), /*WithLOption=*/false); break; + case OPT_defsym: { + StringRef From; + StringRef To; + std::tie(From, To) = StringRef(Arg->getValue()).split('='); + readDefsym(From, MemoryBufferRef(To, "-defsym")); + break; + } case OPT_script: - if (Optional<std::string> Path = searchLinkerScript(Arg->getValue())) { + if (Optional<std::string> Path = searchScript(Arg->getValue())) { if (Optional<MemoryBufferRef> MB = readFile(*Path)) readLinkerScript(*MB); break; @@ -862,11 +1074,48 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { case OPT_no_whole_archive: InWholeArchive = false; break; + case OPT_just_symbols: + if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) { + Files.push_back(createObjectFile(*MB)); + Files.back()->JustSymbols = true; + } + break; + case OPT_start_group: + if (InputFile::IsInGroup) + error("nested --start-group"); + InputFile::IsInGroup = true; + break; + case OPT_end_group: + if (!InputFile::IsInGroup) + error("stray --end-group"); + InputFile::IsInGroup = false; + ++InputFile::NextGroupId; + break; case OPT_start_lib: + if (InLib) + error("nested --start-lib"); + if (InputFile::IsInGroup) + error("may not nest --start-lib in --start-group"); InLib = true; + InputFile::IsInGroup = true; break; case OPT_end_lib: + if (!InLib) + error("stray --end-lib"); InLib = false; + InputFile::IsInGroup = false; + ++InputFile::NextGroupId; + break; + case OPT_push_state: + Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive); + break; + case OPT_pop_state: + if (Stack.empty()) { + error("unbalanced --push-state/--pop-state"); + break; + } + std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back(); + Stack.pop_back(); break; } } @@ -939,14 +1188,6 @@ static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) { return Ret; } -static Optional<StringRef> getArchiveName(InputFile *File) { - if (isa<ArchiveFile>(File)) - return File->getName(); - if (!File->ArchiveName.empty()) - return File->ArchiveName; - return None; -} - // Handles the -exclude-libs option. If a static library file is specified // by the -exclude-libs option, all public symbols from the archive become // private unless otherwise specified by version scripts or something. @@ -954,18 +1195,140 @@ static Optional<StringRef> getArchiveName(InputFile *File) { // // This is not a popular option, but some programs such as bionic libc use it. template <class ELFT> -static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) { +static void excludeLibs(opt::InputArgList &Args) { DenseSet<StringRef> Libs = getExcludeLibs(Args); bool All = Libs.count("ALL"); - for (InputFile *File : Files) - if (Optional<StringRef> Archive = getArchiveName(File)) - if (All || Libs.count(path::filename(*Archive))) + auto Visit = [&](InputFile *File) { + if (!File->ArchiveName.empty()) + if (All || Libs.count(path::filename(File->ArchiveName))) for (Symbol *Sym : File->getSymbols()) if (!Sym->isLocal() && Sym->File == File) Sym->VersionId = VER_NDX_LOCAL; + }; + + for (InputFile *File : ObjectFiles) + Visit(File); + + for (BitcodeFile *File : BitcodeFiles) + Visit(File); +} + +// Force Sym to be entered in the output. Used for -u or equivalent. +template <class ELFT> static void handleUndefined(StringRef Name) { + Symbol *Sym = Symtab->find(Name); + if (!Sym) + return; + + // Since symbol S may not be used inside the program, LTO may + // eliminate it. Mark the symbol as "used" to prevent it. + Sym->IsUsedInRegularObj = true; + + if (Sym->isLazy()) + Symtab->fetchLazy<ELFT>(Sym); +} + +template <class ELFT> static bool shouldDemote(Symbol &Sym) { + // If all references to a DSO happen to be weak, the DSO is not added to + // DT_NEEDED. If that happens, we need to eliminate shared symbols created + // from the DSO. Otherwise, they become dangling references that point to a + // non-existent DSO. + if (auto *S = dyn_cast<SharedSymbol>(&Sym)) + return !S->getFile<ELFT>().IsNeeded; + + // We are done processing archives, so lazy symbols that were used but not + // found can be converted to undefined. We could also just delete the other + // lazy symbols, but that seems to be more work than it is worth. + return Sym.isLazy() && Sym.IsUsedInRegularObj; } +// Some files, such as .so or files between -{start,end}-lib may be removed +// after their symbols are added to the symbol table. If that happens, we +// need to remove symbols that refer files that no longer exist, so that +// they won't appear in the symbol table of the output file. +// +// We remove symbols by demoting them to undefined symbol. +template <class ELFT> static void demoteSymbols() { + for (Symbol *Sym : Symtab->getSymbols()) { + if (shouldDemote<ELFT>(*Sym)) { + bool Used = Sym->Used; + replaceSymbol<Undefined>(Sym, nullptr, Sym->getName(), Sym->Binding, + Sym->StOther, Sym->Type); + Sym->Used = Used; + } + } +} + +// The section referred to by S is considered address-significant. Set the +// KeepUnique flag on the section if appropriate. +static void markAddrsig(Symbol *S) { + if (auto *D = dyn_cast_or_null<Defined>(S)) + if (D->Section) + // We don't need to keep text sections unique under --icf=all even if they + // are address-significant. + if (Config->ICF == ICFLevel::Safe || !(D->Section->Flags & SHF_EXECINSTR)) + D->Section->KeepUnique = true; +} + +// Record sections that define symbols mentioned in --keep-unique <symbol> +// and symbols referred to by address-significance tables. These sections are +// ineligible for ICF. +template <class ELFT> +static void findKeepUniqueSections(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered(OPT_keep_unique)) { + StringRef Name = Arg->getValue(); + auto *D = dyn_cast_or_null<Defined>(Symtab->find(Name)); + if (!D || !D->Section) { + warn("could not find symbol " + Name + " to keep unique"); + continue; + } + D->Section->KeepUnique = true; + } + + // --icf=all --ignore-data-address-equality means that we can ignore + // the dynsym and address-significance tables entirely. + if (Config->ICF == ICFLevel::All && Config->IgnoreDataAddressEquality) + return; + + // Symbols in the dynsym could be address-significant in other executables + // or DSOs, so we conservatively mark them as address-significant. + for (Symbol *S : Symtab->getSymbols()) + if (S->includeInDynsym()) + markAddrsig(S); + + // Visit the address-significance table in each object file and mark each + // referenced symbol as address-significant. + for (InputFile *F : ObjectFiles) { + auto *Obj = cast<ObjFile<ELFT>>(F); + ArrayRef<Symbol *> Syms = Obj->getSymbols(); + if (Obj->AddrsigSec) { + ArrayRef<uint8_t> Contents = + check(Obj->getObj().getSectionContents(Obj->AddrsigSec)); + const uint8_t *Cur = Contents.begin(); + while (Cur != Contents.end()) { + unsigned Size; + const char *Err; + uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); + if (Err) + fatal(toString(F) + ": could not decode addrsig section: " + Err); + markAddrsig(Syms[SymIndex]); + Cur += Size; + } + } else { + // If an object file does not have an address-significance table, + // conservatively mark all of its symbols as address-significant. + for (Symbol *S : Syms) + markAddrsig(S); + } + } +} + +static const char *LibcallRoutineNames[] = { +#define HANDLE_LIBCALL(code, name) name, +#include "llvm/IR/RuntimeLibcalls.def" +#undef HANDLE_LIBCALL +}; + // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { @@ -1014,14 +1377,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { for (InputFile *F : Files) Symtab->addFile<ELFT>(F); - // Process -defsym option. - for (auto *Arg : Args.filtered(OPT_defsym)) { - StringRef From; - StringRef To; - std::tie(From, To) = StringRef(Arg->getValue()).split('='); - readDefsym(From, MemoryBufferRef(To, "-defsym")); - } - // Now that we have every file, we can decide if we will need a // dynamic symbol table. // We need one if we were asked to export dynamic symbols or if we are @@ -1038,24 +1393,39 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // Handle the `--undefined <sym>` options. for (StringRef S : Config->Undefined) - Symtab->fetchIfLazy<ELFT>(S); + handleUndefined<ELFT>(S); - // If an entry symbol is in a static archive, pull out that file now - // to complete the symbol table. After this, no new names except a - // few linker-synthesized ones will be added to the symbol table. - Symtab->fetchIfLazy<ELFT>(Config->Entry); + // If an entry symbol is in a static archive, pull out that file now. + handleUndefined<ELFT>(Config->Entry); + + // If any of our inputs are bitcode files, the LTO code generator may create + // references to certain library functions that might not be explicit in the + // bitcode file's symbol table. If any of those library functions are defined + // in a bitcode file in an archive member, we need to arrange to use LTO to + // compile those archive members by adding them to the link beforehand. + // + // With this the symbol table should be complete. After this, no new names + // except a few linker-synthesized ones will be added to the symbol table. + if (!BitcodeFiles.empty()) + for (const char *S : LibcallRoutineNames) + handleUndefined<ELFT>(S); // Return if there were name resolution errors. if (errorCount()) return; - // Handle undefined symbols in DSOs. - if (!Config->Shared) - Symtab->scanShlibUndefined<ELFT>(); + // Now when we read all script files, we want to finalize order of linker + // script commands, which can be not yet final because of INSERT commands. + Script->processInsertCommands(); + + // We want to declare linker script's symbols early, + // so that we can version them. + // They also might be exported if referenced by DSOs. + Script->declareSymbols(); // Handle the -exclude-libs option. if (Args.hasArg(OPT_exclude_libs)) - excludeLibs<ELFT>(Args, Files); + excludeLibs<ELFT>(Args); // Create ElfHeader early. We need a dummy section in // addReservedSymbols to mark the created symbols as not absolute. @@ -1078,10 +1448,18 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_wrap)) Symtab->addSymbolWrap<ELFT>(Arg->getValue()); + // Do link-time optimization if given files are LLVM bitcode files. + // This compiles bitcode files into real object files. Symtab->addCombinedLTOObject<ELFT>(); if (errorCount()) return; + // If -thinlto-index-only is given, we should create only "index + // files" and not object files. Index file creation is already done + // in addCombinedLTOObject, so we are done if that's the case. + if (Config->ThinLTOIndexOnly) + return; + // Apply symbol renames for -wrap. Symtab->applySymbolWrap(); @@ -1128,11 +1506,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // Do size optimizations: garbage collection, merging of SHF_MERGE sections // and identical code folding. - markLive<ELFT>(); decompressSections(); + splitSections<ELFT>(); + markLive<ELFT>(); + demoteSymbols<ELFT>(); mergeSections(); - if (Config->ICF) + if (Config->ICF != ICFLevel::None) { + findKeepUniqueSections<ELFT>(Args); doIcf<ELFT>(); + } + + // Read the callgraph now that we know what was gced or icfed + if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file)) + if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) + readCallGraph(*Buffer); // Write the result to the file. writeResult<ELFT>(); diff --git a/gnu/llvm/tools/lld/ELF/DriverUtils.cpp b/gnu/llvm/tools/lld/ELF/DriverUtils.cpp index ddb1977a992..c9273ff1fca 100644 --- a/gnu/llvm/tools/lld/ELF/DriverUtils.cpp +++ b/gnu/llvm/tools/lld/ELF/DriverUtils.cpp @@ -29,6 +29,7 @@ using namespace llvm; using namespace llvm::sys; +using namespace llvm::opt; using namespace lld; using namespace lld::elf; @@ -58,18 +59,18 @@ static void handleColorDiagnostics(opt::InputArgList &Args) { OPT_no_color_diagnostics); if (!Arg) return; - else if (Arg->getOption().getID() == OPT_color_diagnostics) + if (Arg->getOption().getID() == OPT_color_diagnostics) { errorHandler().ColorDiagnostics = true; - else if (Arg->getOption().getID() == OPT_no_color_diagnostics) + } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { errorHandler().ColorDiagnostics = false; - else { + } else { StringRef S = Arg->getValue(); if (S == "always") errorHandler().ColorDiagnostics = true; else if (S == "never") errorHandler().ColorDiagnostics = false; else if (S != "auto") - error("unknown option: -color-diagnostics=" + S); + error("unknown option: --color-diagnostics=" + S); } } @@ -87,6 +88,29 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { return cl::TokenizeGNUCommandLine; } +// Gold LTO plugin takes a `--plugin-opt foo=bar` option as an alias for +// `--plugin-opt=foo=bar`. We want to handle `--plugin-opt=foo=` as an +// option name and `bar` as a value. Unfortunately, OptParser cannot +// handle an option with a space in it. +// +// In this function, we concatenate command line arguments so that +// `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a +// bit hacky, but looks like it is still better than handling --plugin-opt +// options by hand. +static void concatLTOPluginOptions(SmallVectorImpl<const char *> &Args) { + SmallVector<const char *, 256> V; + for (size_t I = 0, E = Args.size(); I != E; ++I) { + StringRef S = Args[I]; + if ((S == "-plugin-opt" || S == "--plugin-opt") && I + 1 != E) { + V.push_back(Saver.save(S + "=" + Args[I + 1]).data()); + ++I; + } else { + V.push_back(Args[I]); + } + } + Args = std::move(V); +} + // Parses a given list of options. opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { // Make InputArgList from string vectors. @@ -102,6 +126,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { // Expand response files (arguments in the form of @<filename>) // and then parse the argument again. cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); + concatLTOPluginOptions(Vec); Args = this->ParseArgs(Vec, MissingIndex, MissingCount); handleColorDiagnostics(Args); @@ -113,9 +138,9 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { return Args; } -void elf::printHelp(const char *Argv0) { - ELFOptTable().PrintHelp(outs(), Argv0, "lld", false /*ShowHidden*/, - true /*ShowAllAliases*/); +void elf::printHelp() { + ELFOptTable().PrintHelp(outs(), Config->ProgName.data(), "lld", + false /*ShowHidden*/, true /*ShowAllAliases*/); outs() << "\n"; // Scripts generated by Libtool versions up to at least 2.4.6 (the most @@ -123,13 +148,7 @@ void elf::printHelp(const char *Argv0) { // in a message for the -help option. If it doesn't match, the scripts // assume that the linker doesn't support very basic features such as // shared libraries. Therefore, we need to print out at least "elf". - // Here, we print out all the targets that we support. - outs() << Argv0 << ": supported targets: " - << "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips " - << "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips " - << "elf32-tradlittlemips elf32-x86-64 " - << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips " - << "elf64-tradlittlemips elf64-x86-64\n"; + outs() << Config->ProgName << ": supported targets: elf\n"; } // Reconstructs command line arguments so that so that you can re-run @@ -208,7 +227,7 @@ Optional<std::string> elf::searchLibrary(StringRef Name) { int MaxMaj = -1, MaxMin = -1; std::error_code EC; for (fs::directory_iterator LI(Dir, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { + LI != LE; LI = LI.increment(EC)) { StringRef FilePath = LI->path(); StringRef FileName = path::filename(FilePath); if (!(FileName.startswith(LibName))) @@ -234,10 +253,10 @@ Optional<std::string> elf::searchLibrary(StringRef Name) { return None; } -// If a linker script doesn't exist in the current directory, we also look for -// the script in the '-L' search paths. This matches the behaviour of both '-T' -// and linker script INPUT() directives in ld.bfd. -Optional<std::string> elf::searchLinkerScript(StringRef Name) { +// If a linker/version script doesn't exist in the current directory, we also +// look for the script in the '-L' search paths. This matches the behaviour of +// '-T', --version-script=, and linker script INPUT() command in ld.bfd. +Optional<std::string> elf::searchScript(StringRef Name) { if (fs::exists(Name)) return Name.str(); return findFromSearchPaths(Name); diff --git a/gnu/llvm/tools/lld/ELF/LinkerScript.cpp b/gnu/llvm/tools/lld/ELF/LinkerScript.cpp index 57f4adc5156..42ad9396fab 100644 --- a/gnu/llvm/tools/lld/ELF/LinkerScript.cpp +++ b/gnu/llvm/tools/lld/ELF/LinkerScript.cpp @@ -15,13 +15,13 @@ #include "Config.h" #include "InputSection.h" #include "OutputSections.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" @@ -74,7 +74,7 @@ uint64_t ExprValue::getSectionOffset() const { // If the alignment is trivial, we don't have to compute the full // value to know the offset. This allows this function to succeed in // cases where the output section is not yet known. - if (Alignment == 1) + if (Alignment == 1 && (!Sec || !Sec->getOutputSection())) return Val; return getValue() - getSecAddr(); } @@ -102,28 +102,68 @@ OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) { return CmdRef; } +// Expands the memory region by the specified size. +static void expandMemoryRegion(MemoryRegion *MemRegion, uint64_t Size, + StringRef RegionName, StringRef SecName) { + MemRegion->CurPos += Size; + uint64_t NewSize = MemRegion->CurPos - MemRegion->Origin; + if (NewSize > MemRegion->Length) + error("section '" + SecName + "' will not fit in region '" + RegionName + + "': overflowed by " + Twine(NewSize - MemRegion->Length) + " bytes"); +} + +void LinkerScript::expandMemoryRegions(uint64_t Size) { + if (Ctx->MemRegion) + expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name, + Ctx->OutSec->Name); + // Only expand the LMARegion if it is different from MemRegion. + if (Ctx->LMARegion && Ctx->MemRegion != Ctx->LMARegion) + expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name, + Ctx->OutSec->Name); +} + +void LinkerScript::expandOutputSection(uint64_t Size) { + Ctx->OutSec->Size += Size; + expandMemoryRegions(Size); +} + void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); if (Val < Dot && InSec) error(Loc + ": unable to move location counter backward for: " + Ctx->OutSec->Name); - Dot = Val; // Update to location counter means update to section size. if (InSec) - Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; + expandOutputSection(Val - Dot); + else + expandMemoryRegions(Val - Dot); + + Dot = Val; } -// This function is called from processSectionCommands, -// while we are fixing the output section layout. -void LinkerScript::addSymbol(SymbolAssignment *Cmd) { +// Used for handling linker symbol assignments, for both finalizing +// their values and doing early declarations. Returns true if symbol +// should be defined from linker script. +static bool shouldDefineSym(SymbolAssignment *Cmd) { if (Cmd->Name == ".") - return; + return false; - // If a symbol was in PROVIDE(), we need to define it only when - // it is a referenced undefined symbol. + if (!Cmd->Provide) + return true; + + // If a symbol was in PROVIDE(), we need to define it only + // when it is a referenced undefined symbol. Symbol *B = Symtab->find(Cmd->Name); - if (Cmd->Provide && (!B || B->isDefined())) + if (B && !B->isDefined()) + return true; + return false; +} + +// This function is called from processSectionCommands, +// while we are fixing the output section layout. +void LinkerScript::addSymbol(SymbolAssignment *Cmd) { + if (!shouldDefineSym(Cmd)) return; // Define a symbol. @@ -153,6 +193,76 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) { Cmd->Sym = cast<Defined>(Sym); } +// This function is called from LinkerScript::declareSymbols. +// It creates a placeholder symbol if needed. +static void declareSymbol(SymbolAssignment *Cmd) { + if (!shouldDefineSym(Cmd)) + return; + + // We can't calculate final value right now. + Symbol *Sym; + uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; + std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility, + /*CanOmitFromDynSym*/ false, + /*File*/ nullptr); + replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility, + STT_NOTYPE, 0, 0, nullptr); + Cmd->Sym = cast<Defined>(Sym); + Cmd->Provide = false; +} + +// This method is used to handle INSERT AFTER statement. Here we rebuild +// the list of script commands to mix sections inserted into. +void LinkerScript::processInsertCommands() { + std::vector<BaseCommand *> V; + auto Insert = [&](std::vector<BaseCommand *> &From) { + V.insert(V.end(), From.begin(), From.end()); + From.clear(); + }; + + for (BaseCommand *Base : SectionCommands) { + if (auto *OS = dyn_cast<OutputSection>(Base)) { + Insert(InsertBeforeCommands[OS->Name]); + V.push_back(Base); + Insert(InsertAfterCommands[OS->Name]); + continue; + } + V.push_back(Base); + } + + for (auto &Cmds : {InsertBeforeCommands, InsertAfterCommands}) + for (const std::pair<StringRef, std::vector<BaseCommand *>> &P : Cmds) + if (!P.second.empty()) + error("unable to INSERT AFTER/BEFORE " + P.first + + ": section not defined"); + + SectionCommands = std::move(V); +} + +// Symbols defined in script should not be inlined by LTO. At the same time +// we don't know their final values until late stages of link. Here we scan +// over symbol assignment commands and create placeholder symbols if needed. +void LinkerScript::declareSymbols() { + assert(!Ctx); + for (BaseCommand *Base : SectionCommands) { + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { + declareSymbol(Cmd); + continue; + } + + // If the output section directive has constraints, + // we can't say for sure if it is going to be included or not. + // Skip such sections for now. Improve the checks if we ever + // need symbols from that sections to be declared early. + auto *Sec = cast<OutputSection>(Base); + if (Sec->Constraint != ConstraintKind::NoConstraint) + continue; + for (BaseCommand *Base2 : Sec->SectionCommands) + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base2)) + declareSymbol(Cmd); + } +} + // This function is called from assignAddresses, while we are // fixing the output section addresses. This function is supposed // to set the final value for a given symbol assignment. @@ -249,23 +359,11 @@ static void sortSections(MutableArrayRef<InputSection *> Vec, // --sort-section is handled as an inner SORT command. // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. // 4. If no SORT command is given, sort according to --sort-section. -// 5. If no SORT commands are given and --sort-section is not specified, -// apply sorting provided by --symbol-ordering-file if any exist. -static void sortInputSections( - MutableArrayRef<InputSection *> Vec, const SectionPattern &Pat, - const DenseMap<SectionBase *, int> &Order) { +static void sortInputSections(MutableArrayRef<InputSection *> Vec, + const SectionPattern &Pat) { if (Pat.SortOuter == SortSectionPolicy::None) return; - if (Pat.SortOuter == SortSectionPolicy::Default && - Config->SortSection == SortSectionPolicy::Default) { - // If -symbol-ordering-file was given, sort accordingly. - // Usually, Order is empty. - if (!Order.empty()) - sortByOrder(Vec, [&](InputSectionBase *S) { return Order.lookup(S); }); - return; - } - if (Pat.SortInner == SortSectionPolicy::Default) sortSections(Vec, Config->SortSection); else @@ -275,8 +373,7 @@ static void sortInputSections( // Compute and remember which sections the InputSectionDescription matches. std::vector<InputSection *> -LinkerScript::computeInputSections(const InputSectionDescription *Cmd, - const DenseMap<SectionBase *, int> &Order) { +LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { std::vector<InputSection *> Ret; // Collects all sections that satisfy constraints of Cmd. @@ -290,8 +387,11 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd, // For -emit-relocs we have to ignore entries like // .rela.dyn : { *(.rela.data) } // which are common because they are in the default bfd script. - if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) - continue; + // We do not ignore SHT_REL[A] linker-synthesized sections here because + // want to support scripts that do custom layout for them. + if (auto *IS = dyn_cast<InputSection>(Sec)) + if (IS->getRelocatedSection()) + continue; std::string Filename = getFilename(Sec->File); if (!Cmd->FilePat.match(Filename) || @@ -307,7 +407,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd, } sortInputSections(MutableArrayRef<InputSection *>(Ret).slice(SizeBefore), - Pat, Order); + Pat); } return Ret; } @@ -315,22 +415,31 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd, void LinkerScript::discard(ArrayRef<InputSection *> V) { for (InputSection *S : V) { if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab || - S == InX::DynStrTab) + S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn || + S == InX::RelrDyn) error("discarding " + S->Name + " section is not allowed"); + // You can discard .hash and .gnu.hash sections by linker scripts. Since + // they are synthesized sections, we need to handle them differently than + // other regular sections. + if (S == InX::GnuHashTab) + InX::GnuHashTab = nullptr; + if (S == InX::HashTab) + InX::HashTab = nullptr; + S->Assigned = false; S->Live = false; discard(S->DependentSections); } } -std::vector<InputSection *> LinkerScript::createInputSectionList( - OutputSection &OutCmd, const DenseMap<SectionBase *, int> &Order) { +std::vector<InputSection *> +LinkerScript::createInputSectionList(OutputSection &OutCmd) { std::vector<InputSection *> Ret; for (BaseCommand *Base : OutCmd.SectionCommands) { if (auto *Cmd = dyn_cast<InputSectionDescription>(Base)) { - Cmd->Sections = computeInputSections(Cmd, Order); + Cmd->Sections = computeInputSections(Cmd); Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); } } @@ -359,7 +468,6 @@ void LinkerScript::processSectionCommands() { Ctx->OutSec = Aether; size_t I = 0; - DenseMap<SectionBase *, int> Order = buildSectionOrder(); // Add input sections to output sections. for (BaseCommand *Base : SectionCommands) { // Handle symbol assignments outside of any output section. @@ -369,12 +477,13 @@ void LinkerScript::processSectionCommands() { } if (auto *Sec = dyn_cast<OutputSection>(Base)) { - std::vector<InputSection *> V = createInputSectionList(*Sec, Order); + std::vector<InputSection *> V = createInputSectionList(*Sec); // The output section name `/DISCARD/' is special. // Any input section assigned to it is discarded. if (Sec->Name == "/DISCARD/") { discard(V); + Sec->SectionCommands.clear(); continue; } @@ -414,6 +523,8 @@ void LinkerScript::processSectionCommands() { Sec->SectionIndex = I++; if (Sec->Noload) Sec->Type = SHT_NOBITS; + if (Sec->NonAlloc) + Sec->Flags &= ~(uint64_t)SHF_ALLOC; } } Ctx = nullptr; @@ -484,7 +595,7 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map, // ignored. We should not have two output .text sections just because one was // in a group and another was not for example. // - // It also seems that that wording was a late addition and didn't get the + // It also seems that wording was a late addition and didn't get the // necessary scrutiny. // // Merging sections with different flags is expected by some users. One @@ -529,11 +640,11 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map, void LinkerScript::addOrphanSections() { unsigned End = SectionCommands.size(); StringMap<OutputSection *> Map; - std::vector<OutputSection *> V; - for (InputSectionBase *S : InputSections) { + + auto Add = [&](InputSectionBase *S) { if (!S->Live || S->Parent) - continue; + return; StringRef Name = getOutputSectionName(S); @@ -545,12 +656,24 @@ void LinkerScript::addOrphanSections() { if (OutputSection *Sec = findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) { Sec->addSection(cast<InputSection>(S)); - continue; + return; } if (OutputSection *OS = addInputSec(Map, S, Name)) V.push_back(OS); - assert(S->getOutputSection()->SectionIndex == INT_MAX); + assert(S->getOutputSection()->SectionIndex == UINT32_MAX); + }; + + // For futher --emit-reloc handling code we need target output section + // to be created before we create relocation output section, so we want + // to create target sections first. We do not want priority handling + // for synthetic sections because them are special. + for (InputSectionBase *IS : InputSections) { + if (auto *Sec = dyn_cast<InputSection>(IS)) + if (InputSectionBase *Rel = Sec->getRelocatedSection()) + if (auto *RelIS = dyn_cast_or_null<InputSectionBase>(Rel->Parent)) + Add(RelIS); + Add(IS); } // If no SECTIONS command was given, we should insert sections commands @@ -585,33 +708,15 @@ void LinkerScript::output(InputSection *S) { // Update output section size after adding each section. This is so that // SIZEOF works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } - Ctx->OutSec->Size = Pos - Ctx->OutSec->Addr; - - // If there is a memory region associated with this input section, then - // place the section in that region and update the region index. - if (Ctx->LMARegion) - Ctx->LMARegion->CurPos += Pos - Before; - // FIXME: should we also produce overflow errors for LMARegion? - - if (Ctx->MemRegion) { - uint64_t &CurOffset = Ctx->MemRegion->CurPos; - CurOffset += Pos - Before; - uint64_t CurSize = CurOffset - Ctx->MemRegion->Origin; - if (CurSize > Ctx->MemRegion->Length) { - uint64_t OverflowAmt = CurSize - Ctx->MemRegion->Length; - error("section '" + Ctx->OutSec->Name + "' will not fit in region '" + - Ctx->MemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + - " bytes"); - } - } + expandOutputSection(Pos - Before); } void LinkerScript::switchTo(OutputSection *Sec) { - if (Ctx->OutSec == Sec) - return; - Ctx->OutSec = Sec; + + uint64_t Before = advance(0, 1); Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment); + expandMemoryRegions(Ctx->OutSec->Addr - Before); } // This function searches for a memory region to place the given output @@ -646,6 +751,13 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) { return nullptr; } +static OutputSection *findFirstSection(PhdrEntry *Load) { + for (OutputSection *Sec : OutputSections) + if (Sec->PtLoad == Load) + return Sec; + return nullptr; +} + // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). void LinkerScript::assignOffsets(OutputSection *Sec) { @@ -659,24 +771,26 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { if (Ctx->MemRegion) Dot = Ctx->MemRegion->CurPos; - switchTo(Sec); - if (Sec->LMAExpr) Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot; if (MemoryRegion *MR = Sec->LMARegion) Ctx->LMAOffset = MR->CurPos - Dot; + switchTo(Sec); + // If neither AT nor AT> is specified for an allocatable section, the linker // will set the LMA such that the difference between VMA and LMA for the // section is the same as the preceding output section in the same region // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html + // This, however, should only be done by the first "non-header" section + // in the segment. if (PhdrEntry *L = Ctx->OutSec->PtLoad) - L->LMAOffset = Ctx->LMAOffset; + if (Sec == findFirstSection(L)) + L->LMAOffset = Ctx->LMAOffset; - // The Size previously denoted how many InputSections had been added to this - // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to - // compute the actual size value. + // We can call this method multiple times during the creation of + // thunks and want to start over calculation each time. Sec->Size = 0; // We visited SectionsCommands from processSectionCommands to @@ -685,7 +799,9 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { for (BaseCommand *Base : Sec->SectionCommands) { // This handles the assignments to symbol or to the dot. if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { + Cmd->Addr = Dot; assignSymbol(Cmd, true); + Cmd->Size = Dot - Cmd->Addr; continue; } @@ -693,17 +809,7 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { if (auto *Cmd = dyn_cast<ByteCommand>(Base)) { Cmd->Offset = Dot - Ctx->OutSec->Addr; Dot += Cmd->Size; - if (Ctx->MemRegion) - Ctx->MemRegion->CurPos += Cmd->Size; - if (Ctx->LMARegion) - Ctx->LMARegion->CurPos += Cmd->Size; - Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; - continue; - } - - // Handle ASSERT(). - if (auto *Cmd = dyn_cast<AssertCommand>(Base)) { - Cmd->Expression(); + expandOutputSection(Cmd->Size); continue; } @@ -728,24 +834,28 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { } } -void LinkerScript::removeEmptyCommands() { - // It is common practice to use very generic linker scripts. So for any - // given run some of the output sections in the script will be empty. - // We could create corresponding empty output sections, but that would - // clutter the output. - // We instead remove trivially empty sections. The bfd linker seems even - // more aggressive at removing them. - llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { - if (auto *Sec = dyn_cast<OutputSection>(Base)) - return !Sec->Live; +static bool isDiscardable(OutputSection &Sec) { + // We do not remove empty sections that are explicitly + // assigned to any segment. + if (!Sec.Phdrs.empty()) return false; - }); -} -static bool isAllSectionDescription(const OutputSection &Cmd) { - for (BaseCommand *Base : Cmd.SectionCommands) + // We do not want to remove sections that reference symbols in address and + // other expressions. We add script symbols as undefined, and want to ensure + // all of them are defined in the output, hence have to keep them. + if (Sec.ExpressionsUseSymbols) + return false; + + for (BaseCommand *Base : Sec.SectionCommands) { + if (auto Cmd = dyn_cast<SymbolAssignment>(Base)) + // Don't create empty output sections just for unreferenced PROVIDE + // symbols. + if (Cmd->Name != "." && !Cmd->Sym) + continue; + if (!isa<InputSectionDescription>(*Base)) return false; + } return true; } @@ -761,7 +871,7 @@ void LinkerScript::adjustSectionsBeforeSorting() { // Given that we want to create the section, we have to worry what impact // it will have on the link. For example, if we just create a section with // 0 for flags, it would change which PT_LOADs are created. - // We could remember that that particular section is dummy and ignore it in + // We could remember that particular section is dummy and ignore it in // other parts of the linker, but unfortunately there are quite a few places // that would need to change: // * The program header creation. @@ -772,7 +882,7 @@ void LinkerScript::adjustSectionsBeforeSorting() { // the previous sections. Only a few flags are needed to keep the impact low. uint64_t Flags = SHF_ALLOC; - for (BaseCommand *Cmd : SectionCommands) { + for (BaseCommand *&Cmd : SectionCommands) { auto *Sec = dyn_cast<OutputSection>(Cmd); if (!Sec) continue; @@ -782,25 +892,37 @@ void LinkerScript::adjustSectionsBeforeSorting() { Sec->Alignment = std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue()); - if (Sec->Live) { - Flags = Sec->Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR); - continue; + // A live output section means that some input section was added to it. It + // might have been removed (if it was empty synthetic section), but we at + // least know the flags. + if (Sec->Live) + Flags = Sec->Flags; + + // We do not want to keep any special flags for output section + // in case it is empty. + bool IsEmpty = getInputSections(Sec).empty(); + if (IsEmpty) + Sec->Flags = Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR); + + if (IsEmpty && isDiscardable(*Sec)) { + Sec->Live = false; + Cmd = nullptr; } - - if (isAllSectionDescription(*Sec)) - continue; - - Sec->Live = true; - Sec->Flags = Flags; } + + // It is common practice to use very generic linker scripts. So for any + // given run some of the output sections in the script will be empty. + // We could create corresponding empty output sections, but that would + // clutter the output. + // We instead remove trivially empty sections. The bfd linker seems even + // more aggressive at removing them. + llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; }); } void LinkerScript::adjustSectionsAfterSorting() { // Try and find an appropriate memory region to assign offsets in. for (BaseCommand *Base : SectionCommands) { if (auto *Sec = dyn_cast<OutputSection>(Base)) { - if (!Sec->Live) - continue; if (!Sec->LMARegionName.empty()) { if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName)) Sec->LMARegion = M; @@ -818,9 +940,9 @@ void LinkerScript::adjustSectionsAfterSorting() { // PHDRS { seg PT_LOAD; } // SECTIONS { .aaa : { *(.aaa) } } std::vector<StringRef> DefPhdrs; - auto FirstPtLoad = - std::find_if(PhdrsCommands.begin(), PhdrsCommands.end(), - [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; }); + auto FirstPtLoad = llvm::find_if(PhdrsCommands, [](const PhdrsCommand &Cmd) { + return Cmd.Type == PT_LOAD; + }); if (FirstPtLoad != PhdrsCommands.end()) DefPhdrs.push_back(FirstPtLoad->Name); @@ -842,11 +964,13 @@ void LinkerScript::adjustSectionsAfterSorting() { } } -static OutputSection *findFirstSection(PhdrEntry *Load) { - for (OutputSection *Sec : OutputSections) - if (Sec->PtLoad == Load) - return Sec; - return nullptr; +static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) { + // If there is no SECTIONS or if the linkerscript is explicit about program + // headers, do our best to allocate them. + if (!Script->HasSectionsCommand || AllocateHeaders) + return 0; + // Otherwise only allocate program headers if that would not add a page. + return alignDown(Min, Config->MaxPageSize); } // Try to find an address for the file and program headers output sections, @@ -872,17 +996,22 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) { return; PhdrEntry *FirstPTLoad = *It; + bool HasExplicitHeaders = + llvm::any_of(PhdrsCommands, [](const PhdrsCommand &Cmd) { + return Cmd.HasPhdrs || Cmd.HasFilehdr; + }); uint64_t HeaderSize = getHeaderSize(); - // When linker script with SECTIONS is being used, don't output headers - // unless there's a space for them. - uint64_t Base = HasSectionsCommand ? alignDown(Min, Config->MaxPageSize) : 0; - if (HeaderSize <= Min - Base || Script->hasPhdrsCommands()) { + if (HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) { Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; return; } + // Error if we were explicitly asked to allocate headers. + if (HasExplicitHeaders) + error("could not allocate headers"); + Out::ElfHeader->PtLoad = nullptr; Out::ProgramHeaders->PtLoad = nullptr; FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad); @@ -926,15 +1055,11 @@ void LinkerScript::assignAddresses() { for (BaseCommand *Base : SectionCommands) { if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { + Cmd->Addr = Dot; assignSymbol(Cmd, false); + Cmd->Size = Dot - Cmd->Addr; continue; } - - if (auto *Cmd = dyn_cast<AssertCommand>(Base)) { - Cmd->Expression(); - continue; - } - assignOffsets(cast<OutputSection>(Base)); } Ctx = nullptr; @@ -998,9 +1123,9 @@ ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) { if (Symbol *Sym = Symtab->find(Name)) { if (auto *DS = dyn_cast<Defined>(Sym)) return {DS->Section, false, DS->Value, Loc}; - if (auto *SS = dyn_cast<SharedSymbol>(Sym)) - if (!ErrorOnMissingSection || SS->CopyRelSec) - return {SS->CopyRelSec, false, 0, Loc}; + if (isa<SharedSymbol>(Sym)) + if (!ErrorOnMissingSection) + return {nullptr, false, 0, Loc}; } error(Loc + ": symbol not found: " + Name); diff --git a/gnu/llvm/tools/lld/ELF/Options.td b/gnu/llvm/tools/lld/ELF/Options.td index affc0b8a4ae..068ad546db6 100644 --- a/gnu/llvm/tools/lld/ELF/Options.td +++ b/gnu/llvm/tools/lld/ELF/Options.td @@ -5,65 +5,90 @@ include "llvm/Option/OptParser.td" class F<string name>: Flag<["--", "-"], name>; class J<string name>: Joined<["--", "-"], name>; -multiclass Eq<string name> { - def "": Separate<["--", "-"], name>; - def _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>; +multiclass Eq<string name, string help> { + def NAME: Separate<["--", "-"], name>; + def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>, + HelpText<help>; } -defm auxiliary: Eq<"auxiliary">, - HelpText<"Set DT_AUXILIARY field to the specified name">; +multiclass B<string name, string help1, string help2> { + def NAME: Flag<["--", "-"], name>, HelpText<help1>; + def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>; +} + +defm auxiliary: Eq<"auxiliary", "Set DT_AUXILIARY field to the specified name">; def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">; def Bsymbolic_functions: F<"Bsymbolic-functions">, HelpText<"Bind defined function symbols locally">; -def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">; +def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">; def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; -def build_id: F<"build-id">, HelpText<"Generate build ID note">; +def build_id: F<"build-id">, HelpText<"Alias for --build-id=fast">; + +def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">, + MetaVarName<"[fast,md5,sha,uuid,0x<hexstring>]">; -def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">; +defm check_sections: B<"check-sections", + "Check section addresses for overlaps (default)", + "Do not check section addresses for overlaps">; -defm compress_debug_sections : Eq<"compress-debug-sections">, - HelpText<"Compress DWARF debug sections">; +defm compress_debug_sections: + Eq<"compress-debug-sections", "Compress DWARF debug sections">, + MetaVarName<"[none,zlib]">; -defm defsym: Eq<"defsym">, HelpText<"Define a symbol alias">; +defm defsym: Eq<"defsym", "Define a symbol alias">, MetaVarName<"<symbol>=<value>">; -defm library_path: Eq<"library-path">, - HelpText<"Add a directory to the library search path">, MetaVarName<"<dir>">; +defm library_path: + Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">; def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">; -defm Tbss: Eq<"Tbss">, - HelpText<"Same as --section-start with .bss as the sectionname">; +defm Tbss: Eq<"Tbss", "Same as --section-start with .bss as the sectionname">; -defm Tdata: Eq<"Tdata">, - HelpText<"Same as --section-start with .data as the sectionname">; +defm Tdata: Eq<"Tdata", "Same as --section-start with .data as the sectionname">; -defm Ttext: Eq<"Ttext">, - HelpText<"Same as --section-start with .text as the sectionname">; +defm Ttext: Eq<"Ttext", "Same as --section-start with .text as the sectionname">; -def allow_multiple_definition: F<"allow-multiple-definition">, - HelpText<"Allow multiple definitions">; +defm allow_multiple_definition: B<"allow-multiple-definition", + "Allow multiple definitions", + "Do not allow multiple definitions (default)">; -def as_needed: F<"as-needed">, - HelpText<"Only set DT_NEEDED for shared libraries if used">; +defm apply_dynamic_relocs: B<"apply-dynamic-relocs", + "Apply link-time values for dynamic relocations", + "Do not apply link-time values for dynamic relocations (default)">; + +defm as_needed: B<"as-needed", + "Only set DT_NEEDED for shared libraries if used", + "Always set DT_NEEDED for shared libraries (default)">; + +defm call_graph_ordering_file: + Eq<"call-graph-ordering-file", "Layout sections to optimize the given callgraph">; // -chroot doesn't have a help text because it is an internal option. -defm chroot: Eq<"chroot">; +def chroot: Separate<["--", "-"], "chroot">; def color_diagnostics: F<"color-diagnostics">, - HelpText<"Use colors in diagnostics">; + HelpText<"Alias for --color-diagnostics=always">; def color_diagnostics_eq: J<"color-diagnostics=">, - HelpText<"Use colors in diagnostics">; + HelpText<"Use colors in diagnostics">, + MetaVarName<"[auto,always,never]">; + +defm cref: B<"cref", + "Output cross reference table", + "Do not output cross reference table">; -def define_common: F<"define-common">, - HelpText<"Assign space to common symbols">; +defm define_common: B<"define-common", + "Assign space to common symbols", + "Do not assign space to common symbols">; -def demangle: F<"demangle">, HelpText<"Demangle symbol names">; +defm demangle: B<"demangle", + "Demangle symbol names (default)", + "Do not demangle symbol names">; def disable_new_dtags: F<"disable-new-dtags">, HelpText<"Disable new dynamic tags">; @@ -76,158 +101,131 @@ def discard_locals: F<"discard-locals">, def discard_none: F<"discard-none">, HelpText<"Keep all symbols in the symbol table">; -defm dynamic_linker: Eq<"dynamic-linker">, - HelpText<"Which dynamic linker to use">; +defm dynamic_linker: Eq<"dynamic-linker", "Which dynamic linker to use">; -defm dynamic_list: Eq<"dynamic-list">, - HelpText<"Read a list of dynamic symbols">; +defm dynamic_list: Eq<"dynamic-list", "Read a list of dynamic symbols">; -def eh_frame_hdr: F<"eh-frame-hdr">, - HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">; +defm eh_frame_hdr: B<"eh-frame-hdr", + "Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header", + "Do not create .eh_frame_hdr section">; def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">; def enable_new_dtags: F<"enable-new-dtags">, - HelpText<"Enable new dynamic tags">; + HelpText<"Enable new dynamic tags (default)">; + +def end_group: F<"end-group">, + HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">; def end_lib: F<"end-lib">, HelpText<"End a grouping of objects that should be treated as if they were together in an archive">; -defm entry: Eq<"entry">, HelpText<"Name of entry point symbol">, +defm entry: Eq<"entry", "Name of entry point symbol">, MetaVarName<"<entry>">; -defm error_limit: Eq<"error-limit">, - HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">; +defm error_limit: + Eq<"error-limit", "Maximum number of errors to emit before stopping (0 = no limit)">; def error_unresolved_symbols: F<"error-unresolved-symbols">, HelpText<"Report unresolved symbols as errors">; -defm exclude_libs: Eq<"exclude-libs">, - HelpText<"Exclude static libraries from automatic export">; +defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">; + +defm execute_only: B<"execute-only", + "Do not mark executable sections readable", + "Mark executable sections readable (default)">; -def export_dynamic: F<"export-dynamic">, - HelpText<"Put symbols in the dynamic symbol table">; +defm export_dynamic: B<"export-dynamic", + "Put symbols in the dynamic symbol table", + "Do not put symbols in the dynamic symbol table (default)">; -defm export_dynamic_symbol: Eq<"export-dynamic-symbol">, - HelpText<"Put a symbol in the dynamic symbol table">; +defm export_dynamic_symbol: + Eq<"export-dynamic-symbol", "Put a symbol in the dynamic symbol table">; -def fatal_warnings: F<"fatal-warnings">, - HelpText<"Treat warnings as errors">; +defm fatal_warnings: B<"fatal-warnings", + "Treat warnings as errors", + "Do not treat warnings as errors (default)">; -defm filter: Eq<"filter">, - HelpText<"Set DT_FILTER field to the specified name">; +defm filter: Eq<"filter", "Set DT_FILTER field to the specified name">; -defm fini: Eq<"fini">, - HelpText<"Specify a finalizer function">, MetaVarName<"<symbol>">; +defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">; def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">, HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">; -def full_shutdown : F<"full-shutdown">, - HelpText<"Perform a full shutdown instead of calling _exit">; +defm format: Eq<"format", "Change the input format of the inputs following this option">, + MetaVarName<"[default,elf,binary]">; -defm format: Eq<"format">, - HelpText<"Change the input format of the inputs following this option">, - MetaVarName<"<input-format>">; +defm gc_sections: B<"gc-sections", + "Enable garbage collection of unused sections", + "Disable garbage collection of unused sections (default)">; -def gc_sections: F<"gc-sections">, - HelpText<"Enable garbage collection of unused sections">; +defm gdb_index: B<"gdb-index", + "Generate .gdb_index section", + "Do not generate .gdb_index section (default)">; -def gdb_index: F<"gdb-index">, - HelpText<"Generate .gdb_index section">; +defm gnu_unique: B<"gnu-unique", + "Enable STB_GNU_UNIQUE symbol binding (default)", + "Disable STB_GNU_UNIQUE symbol binding">; -defm hash_style: Eq<"hash-style">, - HelpText<"Specify hash style (sysv, gnu or both)">; +defm hash_style: Eq<"hash-style", "Specify hash style (sysv, gnu or both)">; def help: F<"help">, HelpText<"Print option help">; def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">; -def icf_data: F<"icf-data">, - HelpText<"Enable ICF to also fold identical read only data">; +def icf_safe: F<"icf=safe">, HelpText<"Enable safe identical code folding">; + +def icf_none: F<"icf=none">, HelpText<"Disable identical code folding (default)">; -def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">; +defm ignore_function_address_equality: B<"ignore-function-address-equality", + "lld can break the address equality of functions", + "lld cannot break the address equality of functions">; -defm image_base : Eq<"image-base">, HelpText<"Set the base address">; +def ignore_data_address_equality: F<"ignore-data-address-equality">, + HelpText<"lld can break the address equality of data">; -defm init: Eq<"init">, HelpText<"Specify an initializer function">, +defm image_base: Eq<"image-base", "Set the base address">; + +defm init: Eq<"init", "Specify an initializer function">, MetaVarName<"<symbol>">; -defm library: Eq<"library">, HelpText<"Root name of library to use">, - MetaVarName<"<libName>">; +defm just_symbols: Eq<"just-symbols", "Just link symbols">; -def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, - HelpText<"Optimization level for LTO">; +defm keep_unique: Eq<"keep-unique", "Do not fold this symbol during ICF">; + +defm library: Eq<"library", "Root name of library to use">, + MetaVarName<"<libName>">; def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; -defm Map: Eq<"Map">, HelpText<"Print a link map to the specified file">; +defm Map: Eq<"Map", "Print a link map to the specified file">; -def merge_exidx_entries: F<"merge-exidx-entries">, - HelpText<"Enable merging .ARM.exidx entries">; +defm merge_exidx_entries: B<"merge-exidx-entries", + "Enable merging .ARM.exidx entries (default)", + "Disable merging .ARM.exidx entries">; def nostdlib: F<"nostdlib">, HelpText<"Only search directories specified on the command line">; -def no_as_needed: F<"no-as-needed">, - HelpText<"Always DT_NEEDED for shared libraries">; - def no_color_diagnostics: F<"no-color-diagnostics">, HelpText<"Do not use colors in diagnostics">; -def no_define_common: F<"no-define-common">, - HelpText<"Do not assign space to common symbols">; - -def no_demangle: F<"no-demangle">, - HelpText<"Do not demangle symbol names">; - def no_dynamic_linker: F<"no-dynamic-linker">, HelpText<"Inhibit output of .interp section">; -def no_eh_frame_hdr: F<"no-eh-frame-hdr">, - HelpText<"Do not create .eh_frame_hdr section">; - -def no_export_dynamic: F<"no-export-dynamic">; -def no_fatal_warnings: F<"no-fatal-warnings">; - -def no_gc_sections: F<"no-gc-sections">, - HelpText<"Disable garbage collection of unused sections">; - -def no_gdb_index: F<"no-gdb-index">, - HelpText<"Do not generate .gdb_index section">; - -def no_gnu_unique: F<"no-gnu-unique">, - HelpText<"Disable STB_GNU_UNIQUE symbol binding">; - -def no_merge_exidx_entries: F<"no-merge-exidx-entries">, - HelpText<"Disable merging .ARM.exidx entries">; - -def no_threads: F<"no-threads">, - HelpText<"Do not run the linker multi-threaded">; - -def no_whole_archive: F<"no-whole-archive">, - HelpText<"Restores the default behavior of loading archive members">; - def noinhibit_exec: F<"noinhibit-exec">, HelpText<"Retain the executable output file whenever it is still usable">; -def nopie: F<"nopie">, HelpText<"Do not create a position independent executable">; - -def no_omagic: Flag<["--"], "no-omagic">, MetaVarName<"<magic>">, +def no_omagic: F<"no-omagic">, MetaVarName<"<magic>">, HelpText<"Do not set the text data sections to be writable">; -def no_print_gc_sections: F<"no-print-gc-sections">, - HelpText<"Do not list removed unused sections">; - def no_rosegment: F<"no-rosegment">, HelpText<"Do not put read-only non-executable sections in their own segment">; def no_undefined: F<"no-undefined">, HelpText<"Report unresolved symbols even if the linker is creating a shared library">; -def no_undefined_version: F<"no-undefined-version">, - HelpText<"Report version scripts that refer undefined symbols">; - def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">, HelpText<"Path to file to write output">; @@ -237,42 +235,62 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">, def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">, HelpText<"Set the text and data sections to be readable and writable">; -defm orphan_handling: Eq<"orphan-handling">, - HelpText<"Control how orphan sections are handled when linker script used">; +defm orphan_handling: + Eq<"orphan-handling", "Control how orphan sections are handled when linker script used">; + +defm pack_dyn_relocs: + Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">, + MetaVarName<"[none,android,relr,android+relr]">; + +defm use_android_relr_tags: B<"use-android-relr-tags", + "Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*", + "Use SHT_RELR / DT_RELR* tags (default)">; + +defm pie: B<"pie", + "Create a position independent executable", + "Do not create a position independent executable (default)">; + +defm print_gc_sections: B<"print-gc-sections", + "List removed unused sections", + "Do not list removed unused sections (default)">; -def pack_dyn_relocs_eq: J<"pack-dyn-relocs=">, MetaVarName<"<format>">, - HelpText<"Pack dynamic relocations in the given format (none or android)">; +defm print_icf_sections: B<"print-icf-sections", + "List identical folded sections", + "Do not list identical folded sections (default)">; -def pie: F<"pie">, HelpText<"Create a position independent executable">; +def pop_state: F<"pop-state">, + HelpText<"Undo the effect of -push-state">; -def print_gc_sections: F<"print-gc-sections">, - HelpText<"List removed unused sections">; +def push_state: F<"push-state">, + HelpText<"Save the current state of -as-needed, -static and -whole-archive">; def print_map: F<"print-map">, HelpText<"Print a link map to the standard output">; -defm reproduce: Eq<"reproduce">, - HelpText<"Dump linker invocation and input files for debugging">; +defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">; -defm rpath: Eq<"rpath">, HelpText<"Add a DT_RUNPATH to the output">; +defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">; def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">; -defm retain_symbols_file: Eq<"retain-symbols-file">, - HelpText<"Retain only the symbols listed in the file">, +defm retain_symbols_file: + Eq<"retain-symbols-file", "Retain only the symbols listed in the file">, MetaVarName<"<file>">; -defm script: Eq<"script">, HelpText<"Read linker script">; +defm script: Eq<"script", "Read linker script">; -defm section_start: Eq<"section-start">, MetaVarName<"<address>">, - HelpText<"Set address of section">; +defm section_start: Eq<"section-start", "Set address of section">, + MetaVarName<"<address>">; def shared: F<"shared">, HelpText<"Build a shared object">; -defm soname: Eq<"soname">, HelpText<"Set DT_SONAME">; +defm soname: Eq<"soname", "Set DT_SONAME">; -defm sort_section: Eq<"sort-section">, - HelpText<"Specifies sections sorting rule when linkerscript is used">; +defm sort_section: + Eq<"sort-section", "Specifies sections sorting rule when linkerscript is used">; + +def start_group: F<"start-group">, + HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">; def start_lib: F<"start-lib">, HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">; @@ -281,33 +299,39 @@ def strip_all: F<"strip-all">, HelpText<"Strip all symbols">; def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; -defm symbol_ordering_file: Eq<"symbol-ordering-file">, - HelpText<"Layout sections in the order specified by symbol file">; +defm symbol_ordering_file: + Eq<"symbol-ordering-file", "Layout sections to place symbols in the order specified by symbol ordering file">; -defm sysroot: Eq<"sysroot">, HelpText<"Set the system root">; +defm sysroot: Eq<"sysroot", "Set the system root">; def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">; -def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">; +def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32 (default)">; -defm target2: Eq<"target2">, - HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">, +defm target2: + Eq<"target2", "Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">, MetaVarName<"<type>">; -def threads: F<"threads">, HelpText<"Run the linker multi-threaded">; +defm threads: B<"threads", + "Run the linker multi-threaded (default)", + "Do not run the linker multi-threaded">; def trace: F<"trace">, HelpText<"Print the names of the input files">; -defm trace_symbol : Eq<"trace-symbol">, HelpText<"Trace references to symbols">; +defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">; + +defm undefined: Eq<"undefined", "Force undefined symbol during linking">, + MetaVarName<"<symbol>">; -defm undefined: Eq<"undefined">, - HelpText<"Force undefined symbol during linking">; +defm unresolved_symbols: + Eq<"unresolved-symbols", "Determine how to handle unresolved symbols">; -defm unresolved_symbols: Eq<"unresolved-symbols">, - HelpText<"Determine how to handle unresolved symbols">; +defm undefined_version: B<"undefined-version", + "Allow unused version in version script (default)", + "Report version scripts that refer undefined symbols">; -defm rsp_quoting: Eq<"rsp-quoting">, - HelpText<"Quoting style for response files. Values supported: windows|posix">; +defm rsp_quoting: Eq<"rsp-quoting", "Quoting style for response files">, + MetaVarName<"[posix,windows]">; def v: Flag<["-"], "v">, HelpText<"Display the version number">; @@ -315,91 +339,124 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">; def version: F<"version">, HelpText<"Display the version number and exit">; -defm version_script: Eq<"version-script">, HelpText<"Read a version script">; +defm version_script: Eq<"version-script", "Read a version script">; + +defm warn_backrefs: B<"warn-backrefs", + "Warn about backward symbol references to fetch archive members", + "Do not warn about backward symbol references to fetch archive members (default)">; + +defm warn_common: B<"warn-common", + "Warn about duplicate common symbols", + "Do not warn about duplicate common symbols (default)">; -def warn_common: F<"warn-common">, - HelpText<"Warn about duplicate common symbols">; +defm warn_symbol_ordering: B<"warn-symbol-ordering", + "Warn about problems with the symbol ordering file (default)", + "Do not warn about problems with the symbol ordering file">; def warn_unresolved_symbols: F<"warn-unresolved-symbols">, HelpText<"Report unresolved symbols as warnings">; -def whole_archive: F<"whole-archive">, - HelpText<"Force load of all members in a static library">; +defm whole_archive: B<"whole-archive", + "Force load of all members in a static library", + "Do not force load of all members in a static library (default)">; -defm wrap: Eq<"wrap">, HelpText<"Use wrapper functions for symbol">, - MetaVarName<"<symbol>">; +defm wrap: Eq<"wrap", "Use wrapper functions for symbol">, + MetaVarName<"<symbol>=<symbol>">; def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, HelpText<"Linker option extensions">; // Aliases -def alias_auxiliary: Separate<["-"], "f">, Alias<auxiliary>; -def alias_Bdynamic_call_shared: F<"call_shared">, Alias<Bdynamic>; -def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>; -def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>; -def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>; -def alias_Bstatic_static: F<"static">, Alias<Bstatic>; -def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>; -def alias_define_common_dc: F<"dc">, Alias<define_common>; -def alias_define_common_dp: F<"dp">, Alias<define_common>; -def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>; -def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>; -def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>; -def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; -def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>; -def alias_filter: Separate<["-"], "F">, Alias<filter>; -def alias_format_b: Separate<["-"], "b">, Alias<format>; -def alias_library: JoinedOrSeparate<["-"], "l">, Alias<library>; -def alias_library_path: JoinedOrSeparate<["-"], "L">, Alias<library_path>; -def alias_omagic: Flag<["-"], "N">, Alias<omagic>; -def alias_o_output: Joined<["--"], "output=">, Alias<o>; -def alias_o_output2 : Separate<["--"], "output">, Alias<o>; -def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>; -def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>; -def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>; -def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>; -def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>; -def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>; -def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>; -def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>; -def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>; -def alias_trace: Flag<["-"], "t">, Alias<trace>; -def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>; -def alias_Ttext_segment: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>; -def alias_Ttext_segment_eq: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>; -def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>; -def alias_version_V: Flag<["-"], "V">, Alias<version>; - -// Our symbol resolution algorithm handles symbols in archive files differently -// than traditional linkers, so we don't need --start-group and --end-group. -// These options are recongized for compatibility but ignored. -def end_group: F<"end-group">; -def end_group_paren: Flag<["-"], ")">; -def start_group: F<"start-group">; -def start_group_paren: Flag<["-"], "(">; +def: Separate<["-"], "f">, Alias<auxiliary>, HelpText<"Alias for --auxiliary">; +def: F<"call_shared">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">; +def: F<"dy">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">; +def: F<"dn">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">; +def: F<"non_shared">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">; +def: F<"static">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">; +def: Flag<["-"], "d">, Alias<define_common>, HelpText<"Alias for --define-common">; +def: F<"dc">, Alias<define_common>, HelpText<"Alias for --define-common">; +def: F<"dp">, Alias<define_common>, HelpText<"Alias for --define-common">; +def: Flag<["-"], "x">, Alias<discard_all>, HelpText<"Alias for --discard-all">; +def: Flag<["-"], "X">, Alias<discard_locals>, HelpText<"Alias for --discard-locals">; +def: Flag<["-"], "q">, Alias<emit_relocs>, HelpText<"Alias for --emit-relocs">; +def: Flag<["-"], ")">, Alias<end_group>, HelpText<"Alias for --end-group">; +def: JoinedOrSeparate<["-"], "e">, Alias<entry>, HelpText<"Alias for --entry">; +def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">; +def: Separate<["-"], "F">, Alias<filter>, HelpText<"Alias for --filter">; +def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">; +def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">; +def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">; +def: F<"nopie">, Alias<no_pie>, HelpText<"Alias for --no-pie">; +def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">; +def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">; +def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">; +def: Separate<["--"], "output">, Alias<o>, HelpText<"Alias for -o">; +def: F<"pic-executable">, Alias<pie>, HelpText<"Alias for --pie">; +def: Flag<["-"], "M">, Alias<print_map>, HelpText<"Alias for --print-map">; +def: Flag<["-"], "r">, Alias<relocatable>, HelpText<"Alias for --relocatable">; +def: JoinedOrSeparate<["-"], "R">, Alias<rpath>, HelpText<"Alias for --rpath">; +def: JoinedOrSeparate<["-"], "T">, Alias<script>, HelpText<"Alias for --script">; +def: F<"Bshareable">, Alias<shared>, HelpText<"Alias for --shared">; +def: JoinedOrSeparate<["-"], "h">, Alias<soname>, HelpText<"Alias for --soname">; +def: Flag<["-"], "(">, Alias<start_group>, HelpText<"Alias for --start-group">; +def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">; +def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">; +def: Flag<["-"], "t">, Alias<trace>, HelpText<"Alias for --trace">; +def: JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>, HelpText<"Alias for --trace-symbol">; +def: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>, HelpText<"Alias for --Ttext">; +def: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>, HelpText<"Alias for --Ttext">; +def: JoinedOrSeparate<["-"], "u">, Alias<undefined>, HelpText<"Alias for --undefined">; +def: Flag<["-"], "V">, Alias<version>, HelpText<"Alias for --version">; // LTO-related options. def lto_aa_pipeline: J<"lto-aa-pipeline=">, HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">; +def lto_debug_pass_manager: F<"lto-debug-pass-manager">, + HelpText<"Debug new pass manager">; +def lto_new_pass_manager: F<"lto-new-pass-manager">, + HelpText<"Use new pass manager">; def lto_newpm_passes: J<"lto-newpm-passes=">, HelpText<"Passes to run during LTO">; +def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, + HelpText<"Optimization level for LTO">; def lto_partitions: J<"lto-partitions=">, HelpText<"Number of LTO codegen partitions">; +def lto_sample_profile: J<"lto-sample-profile=">, + HelpText<"Sample profile file path">; def disable_verify: F<"disable-verify">; -defm mllvm: Eq<"mllvm">; +defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">; def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">, HelpText<"YAML output file for optimization remarks">; def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">, - HelpText<"Include hotness informations in the optimization remarks file">; -defm plugin_opt: Eq<"plugin-opt">, - HelpText<"specifies LTO options for compatibility with GNU linkers">; + HelpText<"Include hotness information in the optimization remarks file">; +defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">; def save_temps: F<"save-temps">; def thinlto_cache_dir: J<"thinlto-cache-dir=">, HelpText<"Path to ThinLTO cached object file directory">; -defm thinlto_cache_policy: Eq<"thinlto-cache-policy">, - HelpText<"Pruning policy for the ThinLTO cache">; +defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">; def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; +def: J<"plugin-opt=O">, Alias<lto_O>, HelpText<"Alias for -lto-O">; +def: F<"plugin-opt=debug-pass-manager">, + Alias<lto_debug_pass_manager>, HelpText<"Alias for -lto-debug-pass-manager">; +def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, HelpText<"Alias for -disable-verify">; +def plugin_opt_dwo_dir_eq: J<"plugin-opt=dwo_dir=">, + HelpText<"Directory to store .dwo files when LTO and debug fission are used">; +def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for -thinlto-jobs">; +def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for -lto-partitions">; +def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">; +def: F<"plugin-opt=new-pass-manager">, + Alias<lto_new_pass_manager>, HelpText<"Alias for -lto-new-pass-manager">; +def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">; +def: J<"plugin-opt=sample-profile=">, + Alias<lto_sample_profile>, HelpText<"Alias for -lto-sample-profile">; +def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for -save-temps">; +def plugin_opt_thinlto_emit_imports_files: F<"plugin-opt=thinlto-emit-imports-files">; +def plugin_opt_thinlto_index_only: F<"plugin-opt=thinlto-index-only">; +def plugin_opt_thinlto_index_only_eq: J<"plugin-opt=thinlto-index-only=">; +def plugin_opt_thinlto_object_suffix_replace_eq: J<"plugin-opt=thinlto-object-suffix-replace=">; +def plugin_opt_thinlto_prefix_replace_eq: J<"plugin-opt=thinlto-prefix-replace=">; + // Ignore LTO plugin-related options. // clang -flto passes -plugin and -plugin-opt to the linker. This is required // for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't @@ -407,29 +464,38 @@ def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; // just ignore the option on lld side as it's easier. In fact, the linker could // be called 'ld' and understanding which linker is used would require parsing of // --version output. -defm plugin: Eq<"plugin">; +defm plugin: Eq<"plugin", "Ignored for compatibility with GNU linkers">; + +def plugin_opt_fresolution_eq: J<"plugin-opt=-fresolution=">; +def plugin_opt_pass_through_eq: J<"plugin-opt=-pass-through=">; +def plugin_opt_thinlto: J<"plugin-opt=thinlto">; +def plugin_opt_slash: J<"plugin-opt=/">; // Options listed below are silently ignored for now for compatibility. -def allow_shlib_undefined: F<"allow-shlib-undefined">; -def cref: F<"cref">; -def detect_odr_violations: F<"detect-odr-violations">; -def g: Flag<["-"], "g">; -def long_plt: F<"long-plt">; -def no_add_needed: F<"no-add-needed">; -def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">; -def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">; -def no_ctors_in_init_array: F<"no-ctors-in-init-array">; -def no_keep_memory: F<"no-keep-memory">; -def no_mmap_output_file: F<"no-mmap-output-file">; -def no_warn_common: F<"no-warn-common">; -def no_warn_mismatch: F<"no-warn-mismatch">; -defm rpath_link: Eq<"rpath-link">; -def sort_common: F<"sort-common">; -def stats: F<"stats">; -def warn_execstack: F<"warn-execstack">; -def warn_once: F<"warn-once">; -def warn_shared_textrel: F<"warn-shared-textrel">; -def EB : F<"EB">; -def EL : F<"EL">; -def G: JoinedOrSeparate<["-"], "G">; -def Qy : F<"Qy">; +def: F<"allow-shlib-undefined">; +def: F<"detect-odr-violations">; +def: Flag<["-"], "g">; +def: F<"long-plt">; +def: F<"no-add-needed">; +def: F<"no-allow-shlib-undefined">; +def: F<"no-copy-dt-needed-entries">; +def: F<"no-ctors-in-init-array">; +def: F<"no-keep-memory">; +def: F<"no-mmap-output-file">; +def: F<"no-warn-mismatch">; +def: Separate<["--", "-"], "rpath-link">; +def: J<"rpath-link=">; +def: F<"sort-common">; +def: F<"stats">; +def: F<"warn-execstack">; +def: F<"warn-once">; +def: F<"warn-shared-textrel">; +def: F<"EB">; +def: F<"EL">; +def: JoinedOrSeparate<["-"], "G">; +def: F<"Qy">; + +// Hidden option used for testing MIPS multi-GOT implementation. +defm mips_got_size: + Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">, + Flags<[HelpHidden]>; diff --git a/gnu/llvm/tools/lld/ELF/OutputSections.cpp b/gnu/llvm/tools/lld/ELF/OutputSections.cpp index 94c98284196..8253b18b486 100644 --- a/gnu/llvm/tools/lld/ELF/OutputSections.cpp +++ b/gnu/llvm/tools/lld/ELF/OutputSections.cpp @@ -10,11 +10,11 @@ #include "OutputSections.h" #include "Config.h" #include "LinkerScript.h" -#include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/Compression.h" @@ -25,15 +25,12 @@ using namespace llvm; using namespace llvm::dwarf; using namespace llvm::object; -using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; uint8_t Out::First; -OutputSection *Out::Opd; -uint8_t *Out::OpdBuf; PhdrEntry *Out::TlsPhdr; OutputSection *Out::DebugInfo; OutputSection *Out::ElfHeader; @@ -45,7 +42,9 @@ OutputSection *Out::FiniArray; std::vector<OutputSection *> elf::OutputSections; uint32_t OutputSection::getPhdrFlags() const { - uint32_t Ret = PF_R; + uint32_t Ret = 0; + if (Config->EMachine != EM_ARM || !(Flags & SHF_ARM_PURECODE)) + Ret |= PF_R; if (Flags & SHF_WRITE) Ret |= PF_W; if (Flags & SHF_EXECINSTR) @@ -70,9 +69,7 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) { OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags) : BaseCommand(OutputSectionKind), SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type, - /*Info*/ 0, - /*Link*/ 0), - SectionIndex(INT_MAX) { + /*Info*/ 0, /*Link*/ 0) { Live = false; } @@ -91,13 +88,15 @@ static bool canMergeToProgbits(unsigned Type) { void OutputSection::addSection(InputSection *IS) { if (!Live) { // If IS is the first section to be added to this section, - // initialize Type and Entsize from IS. + // initialize Type, Entsize and flags from IS. Live = true; Type = IS->Type; Entsize = IS->Entsize; + Flags = IS->Flags; } else { // Otherwise, check if new type or flags are compatible with existing ones. - if ((Flags & (SHF_ALLOC | SHF_TLS)) != (IS->Flags & (SHF_ALLOC | SHF_TLS))) + unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER; + if ((Flags & Mask) != (IS->Flags & Mask)) error("incompatible section flags for " + Name + "\n>>> " + toString(IS) + ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name + ": 0x" + utohexstr(Flags)); @@ -114,9 +113,14 @@ void OutputSection::addSection(InputSection *IS) { } IS->Parent = this; - Flags |= IS->Flags; + uint64_t AndMask = + Config->EMachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0; + uint64_t OrMask = ~AndMask; + uint64_t AndFlags = (Flags & IS->Flags) & AndMask; + uint64_t OrFlags = (Flags | IS->Flags) & OrMask; + Flags = AndFlags | OrFlags; + Alignment = std::max(Alignment, IS->Alignment); - IS->OutSecOff = Size++; // If this section contains a table of fixed-size entries, sh_entsize // holds the element size. If it contains elements of different size we @@ -134,8 +138,8 @@ void OutputSection::addSection(InputSection *IS) { } } -void elf::sortByOrder(MutableArrayRef<InputSection *> In, - std::function<int(InputSectionBase *S)> Order) { +static void sortByOrder(MutableArrayRef<InputSection *> In, + llvm::function_ref<int(InputSectionBase *S)> Order) { typedef std::pair<int, InputSection *> Pair; auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; @@ -158,11 +162,11 @@ bool OutputSection::classof(const BaseCommand *C) { return C->Kind == OutputSectionKind; } -void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) { +void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) { assert(Live); - assert(SectionCommands.size() == 1); - sortByOrder(cast<InputSectionDescription>(SectionCommands[0])->Sections, - Order); + for (BaseCommand *B : SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) + sortByOrder(ISD->Sections, Order); } // Fill [Buf, Buf + Size) with Filler. @@ -205,11 +209,11 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { if (Size == 1) *Buf = Data; else if (Size == 2) - write16(Buf, Data, Config->Endianness); + write16(Buf, Data); else if (Size == 4) - write32(Buf, Data, Config->Endianness); + write32(Buf, Data); else if (Size == 8) - write64(Buf, Data, Config->Endianness); + write64(Buf, Data); else llvm_unreachable("unsupported Size argument"); } @@ -231,12 +235,7 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) { } // Write leading padding. - std::vector<InputSection *> Sections; - for (BaseCommand *Cmd : SectionCommands) - if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) - for (InputSection *IS : ISD->Sections) - if (IS->Live) - Sections.push_back(IS); + std::vector<InputSection *> Sections = getInputSections(this); uint32_t Filler = getFiller(); if (Filler) fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler); @@ -281,17 +280,13 @@ static void finalizeShtGroup(OutputSection *OS, } template <class ELFT> void OutputSection::finalize() { - InputSection *First = nullptr; - for (BaseCommand *Base : SectionCommands) { - if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) { - if (ISD->Sections.empty()) - continue; - if (First == nullptr) - First = ISD->Sections.front(); - } - if (isa<ByteCommand>(Base) && Type == SHT_NOBITS) - Type = SHT_PROGBITS; - } + if (Type == SHT_NOBITS) + for (BaseCommand *Base : SectionCommands) + if (isa<ByteCommand>(Base)) + Type = SHT_PROGBITS; + + std::vector<InputSection *> V = getInputSections(this); + InputSection *First = V.empty() ? nullptr : V[0]; if (Flags & SHF_LINK_ORDER) { // We must preserve the link order dependency of sections with the @@ -367,8 +362,6 @@ static bool compCtors(const InputSection *A, const InputSection *B) { assert(Y.startswith(".ctors") || Y.startswith(".dtors")); X = X.substr(6); Y = Y.substr(6); - if (X.empty() && Y.empty()) - return false; return X < Y; } @@ -394,6 +387,14 @@ int elf::getPriority(StringRef S) { return V; } +std::vector<InputSection *> elf::getInputSections(OutputSection *OS) { + std::vector<InputSection *> Ret; + for (BaseCommand *Base : OS->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) + Ret.insert(Ret.end(), ISD->Sections.begin(), ISD->Sections.end()); + return Ret; +} + // Sorts input sections by section name suffixes, so that .foo.N comes // before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. // We want to keep the original order if the priorities are the same diff --git a/gnu/llvm/tools/lld/ELF/Relocations.cpp b/gnu/llvm/tools/lld/ELF/Relocations.cpp index abe5498ba51..467219ad054 100644 --- a/gnu/llvm/tools/lld/ELF/Relocations.cpp +++ b/gnu/llvm/tools/lld/ELF/Relocations.cpp @@ -45,14 +45,14 @@ #include "Config.h" #include "LinkerScript.h" #include "OutputSections.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "lld/Common/Memory.h" - +#include "lld/Common/Strings.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -80,55 +80,22 @@ static std::string getLocation(InputSectionBase &S, const Symbol &Sym, return Msg + S.getObjMsg(Off); } -// This is a MIPS-specific rule. -// -// In case of MIPS GP-relative relocations always resolve to a definition -// in a regular input file, ignoring the one-definition rule. So we, -// for example, should not attempt to create a dynamic relocation even -// if the target symbol is preemptible. There are two two MIPS GP-relative -// relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16 -// can be against a preemptible symbol. -// -// To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all -// relocation types occupy eight bit. In case of N64 ABI we extract first -// relocation from 3-in-1 packet because only the first relocation can -// be against a real symbol. -static bool isMipsGprel(RelType Type) { - if (Config->EMachine != EM_MIPS) - return false; - Type &= 0xff; - return Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 || - Type == R_MICROMIPS_GPREL7_S2; -} - // This function is similar to the `handleTlsRelocation`. MIPS does not // support any relaxations for TLS relocations so by factoring out MIPS // handling in to the separate function we can simplify the code and do not // pollute other `handleTlsRelocation` by MIPS `ifs` statements. // Mips has a custom MipsGotSection that handles the writing of GOT entries // without dynamic relocations. -template <class ELFT> static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { if (Expr == R_MIPS_TLSLD) { - if (InX::MipsGot->addTlsIndex() && Config->Pic) - InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot, - InX::MipsGot->getTlsIndexOff(), false, nullptr, - 0}); + InX::MipsGot->addTlsIndex(*C.File); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } - if (Expr == R_MIPS_TLSGD) { - if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) { - uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym); - InX::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Sym, 0}); - if (Sym.IsPreemptible) - InX::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot, - Off + Config->Wordsize, false, &Sym, 0}); - } + InX::MipsGot->addDynTlsEntry(*C.File, Sym); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } @@ -161,7 +128,7 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym, auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) { if (Dyn) - InX::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0}); + InX::RelaDyn->addReloc(Type, InX::Got, Off, Dest); else InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); }; @@ -207,7 +174,7 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, if (Config->EMachine == EM_ARM) return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr); if (Config->EMachine == EM_MIPS) - return handleMipsTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr); + return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) && Config->Shared) { @@ -221,40 +188,62 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, return 1; } - if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) { + if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC, + R_TLSLD_HINT>(Expr)) { // Local-Dynamic relocs can be relaxed to Local-Exec. if (!Config->Shared) { C.Relocations.push_back( - {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); - return 2; + {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, + Offset, Addend, &Sym}); + return Target->TlsGdRelaxSkip; } + if (Expr == R_TLSLD_HINT) + return 1; if (InX::Got->addTlsIndex()) - InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got, - InX::Got->getTlsIndexOff(), false, nullptr, 0}); + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, + InX::Got->getTlsIndexOff(), nullptr); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } // Local-Dynamic relocs can be relaxed to Local-Exec. - if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) { - C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); + if (Expr == R_ABS && !Config->Shared) { + C.Relocations.push_back( + {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, + Offset, Addend, &Sym}); return 1; } - if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD, - R_TLSGD_PC>(Expr)) { + // Local-Dynamic sequence where offset of tls variable relative to dynamic + // thread pointer is stored in the got. + if (Expr == R_TLSLD_GOT_OFF) { + // Local-Dynamic relocs can be relaxed to local-exec + if (!Config->Shared) { + C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); + return 1; + } + if (!Sym.isInGot()) { + InX::Got->addEntry(Sym); + uint64_t Off = Sym.getGotOffset(); + InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym}); + } + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return 1; + } + + if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT, + R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) { if (Config->Shared) { if (InX::Got->addDynTlsEntry(Sym)) { uint64_t Off = InX::Got->getGlobalDynOffset(Sym); - InX::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, InX::Got, Off, false, &Sym, 0}); + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, Off, &Sym); // If the symbol is preemptible we need the dynamic linker to write // the offset too. uint64_t OffsetOff = Off + Config->Wordsize; if (Sym.IsPreemptible) - InX::RelaDyn->addReloc( - {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Sym, 0}); + InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::Got, OffsetOff, + &Sym); else InX::Got->Relocations.push_back( {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym}); @@ -271,8 +260,8 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, Offset, Addend, &Sym}); if (!Sym.isInGot()) { InX::Got->addEntry(Sym); - InX::RelaDyn->addReloc( - {Target->TlsGotRel, InX::Got, Sym.getGotOffset(), false, &Sym, 0}); + InX::RelaDyn->addReloc(Target->TlsGotRel, InX::Got, Sym.getGotOffset(), + &Sym); } } else { C.Relocations.push_back( @@ -336,7 +325,7 @@ static bool isAbsoluteValue(const Symbol &Sym) { // Returns true if Expr refers a PLT entry. static bool needsPlt(RelExpr Expr) { - return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr); + return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr); } // Returns true if Expr refers a GOT entry. Note that this function @@ -352,7 +341,8 @@ static bool needsGot(RelExpr Expr) { // file (PC, or GOT for example). static bool isRelExpr(RelExpr Expr) { return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL, - R_PAGE_PC, R_RELAX_GOT_PC>(Expr); + R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC, + R_RELAX_GOT_PC>(Expr); } // Returns true if a given relocation can be computed at link-time. @@ -367,11 +357,13 @@ static bool isRelExpr(RelExpr Expr) { static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, InputSectionBase &S, uint64_t RelOff) { // These expressions always compute a constant - if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, - R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, - R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, - R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD, - R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E)) + if (isRelExprOneOf< + R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, + R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, + R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, + R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, + R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT, + R_TLSLD_HINT>(E)) return true; // These never do, except if the entire file is position dependent or if @@ -417,39 +409,45 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, } static RelExpr toPlt(RelExpr Expr) { - if (Expr == R_PPC_OPD) - return R_PPC_PLT_OPD; - if (Expr == R_PC) + switch (Expr) { + case R_PPC_CALL: + return R_PPC_CALL_PLT; + case R_PC: return R_PLT_PC; - if (Expr == R_PAGE_PC) + case R_PAGE_PC: return R_PLT_PAGE_PC; - if (Expr == R_ABS) + case R_ABS: return R_PLT; - return Expr; + default: + return Expr; + } } static RelExpr fromPlt(RelExpr Expr) { // We decided not to use a plt. Optimize a reference to the plt to a // reference to the symbol itself. - if (Expr == R_PLT_PC) + switch (Expr) { + case R_PLT_PC: return R_PC; - if (Expr == R_PPC_PLT_OPD) - return R_PPC_OPD; - if (Expr == R_PLT) + case R_PPC_CALL_PLT: + return R_PPC_CALL; + case R_PLT: return R_ABS; - return Expr; + default: + return Expr; + } } // Returns true if a given shared symbol is in a read-only segment in a DSO. -template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { +template <class ELFT> static bool isReadOnly(SharedSymbol &SS) { typedef typename ELFT::Phdr Elf_Phdr; // Determine if the symbol is read-only by scanning the DSO's program headers. - const SharedFile<ELFT> &File = SS->getFile<ELFT>(); + const SharedFile<ELFT> &File = SS.getFile<ELFT>(); for (const Elf_Phdr &Phdr : check(File.getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && - !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr && - SS->Value < Phdr.p_vaddr + Phdr.p_memsz) + !(Phdr.p_flags & ELF::PF_W) && SS.Value >= Phdr.p_vaddr && + SS.Value < Phdr.p_vaddr + Phdr.p_memsz) return true; return false; } @@ -458,26 +456,45 @@ template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { // // If two or more symbols are at the same offset, and at least one of // them are copied by a copy relocation, all of them need to be copied. -// Otherwise, they would refer different places at runtime. +// Otherwise, they would refer to different places at runtime. template <class ELFT> -static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { +static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) { typedef typename ELFT::Sym Elf_Sym; - SharedFile<ELFT> &File = SS->getFile<ELFT>(); + SharedFile<ELFT> &File = SS.getFile<ELFT>(); - std::vector<SharedSymbol *> Ret; + SmallSet<SharedSymbol *, 4> Ret; for (const Elf_Sym &S : File.getGlobalELFSyms()) { if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS || - S.st_value != SS->Value) + S.st_value != SS.Value) continue; StringRef Name = check(S.getName(File.getStringTable())); Symbol *Sym = Symtab->find(Name); if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym)) - Ret.push_back(Alias); + Ret.insert(Alias); } return Ret; } +// When a symbol is copy relocated or we create a canonical plt entry, it is +// effectively a defined symbol. In the case of copy relocation the symbol is +// in .bss and in the case of a canonical plt entry it is in .plt. This function +// replaces the existing symbol with a Defined pointing to the appropriate +// location. +static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value, + uint64_t Size) { + Symbol Old = Sym; + replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding, + Sym.StOther, Sym.Type, Value, Size, Sec); + Sym.PltIndex = Old.PltIndex; + Sym.GotIndex = Old.GotIndex; + Sym.VerdefIndex = Old.VerdefIndex; + Sym.IsPreemptible = true; + Sym.ExportDynamic = true; + Sym.IsUsedInRegularObj = true; + Sym.Used = true; +} + // Reserve space in .bss or .bss.rel.ro for copy relocation. // // The copy relocation is pretty much a hack. If you use a copy relocation @@ -520,17 +537,17 @@ static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { // to the variable in .bss. This kind of issue is sometimes very hard to // debug. What's a solution? Instead of exporting a varaible V from a DSO, // define an accessor getV(). -template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) { +template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) { // Copy relocation against zero-sized symbol doesn't make sense. - uint64_t SymSize = SS->getSize(); - if (SymSize == 0) - fatal("cannot create a copy relocation for symbol " + toString(*SS)); + uint64_t SymSize = SS.getSize(); + if (SymSize == 0 || SS.Alignment == 0) + fatal("cannot create a copy relocation for symbol " + toString(SS)); // See if this symbol is in a read-only segment. If so, preserve the symbol's // memory protection by reserving space in the .bss.rel.ro section. bool IsReadOnly = isReadOnly<ELFT>(SS); BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss", - SymSize, SS->Alignment); + SymSize, SS.Alignment); if (IsReadOnly) InX::BssRelRo->getParent()->addSection(Sec); else @@ -539,126 +556,10 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) { // Look through the DSO's dynamic symbol table for aliases and create a // dynamic symbol for each one. This causes the copy relocation to correctly // interpose any aliases. - for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) { - Sym->CopyRelSec = Sec; - Sym->IsPreemptible = false; - Sym->IsUsedInRegularObj = true; - Sym->Used = true; - } + for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) + replaceWithDefined(*Sym, Sec, 0, Sym->Size); - InX::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, SS, 0}); -} - -static void errorOrWarn(const Twine &Msg) { - if (!Config->NoinhibitExec) - error(Msg); - else - warn(Msg); -} - -// Returns PLT relocation expression. -// -// This handles a non PIC program call to function in a shared library. In -// an ideal world, we could just report an error saying the relocation can -// overflow at runtime. In the real world with glibc, crt1.o has a -// R_X86_64_PC32 pointing to libc.so. -// -// The general idea on how to handle such cases is to create a PLT entry and -// use that as the function value. -// -// For the static linking part, we just return a plt expr and everything -// else will use the the PLT entry as the address. -// -// The remaining problem is making sure pointer equality still works. We -// need the help of the dynamic linker for that. We let it know that we have -// a direct reference to a so symbol by creating an undefined symbol with a -// non zero st_value. Seeing that, the dynamic linker resolves the symbol to -// the value of the symbol we created. This is true even for got entries, so -// pointer equality is maintained. To avoid an infinite loop, the only entry -// that points to the real function is a dedicated got entry used by the -// plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, -// R_386_JMP_SLOT, etc). -static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) { - Sym.NeedsPltAddr = true; - Sym.IsPreemptible = false; - IsConstant = true; - return toPlt(Expr); -} - -// This modifies the expression if we can use a copy relocation or point the -// symbol to the PLT. -template <class ELFT> -static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, - InputSectionBase &S, uint64_t RelOff, - bool &IsConstant) { - // If a relocation can be applied at link-time, we don't need to - // create a dynamic relocation in the first place. - if (IsConstant) - return Expr; - - // We can create any dynamic relocation supported by the dynamic linker if a - // section is writable or we are passed -z notext. - bool CanWrite = (S.Flags & SHF_WRITE) || !Config->ZText; - if (CanWrite && Target->isPicRel(Type)) - return Expr; - - // If the relocation is to a weak undef, and we are producing - // executable, give up on it and produce a non preemptible 0. - if (!Config->Shared && Sym.isUndefWeak()) { - Sym.IsPreemptible = false; - IsConstant = true; - return Expr; - } - - // If we got here we know that this relocation would require the dynamic - // linker to write a value to read only memory or use an unsupported - // relocation. - - // We can hack around it if we are producing an executable and - // the refered symbol can be preemepted to refer to the executable. - if (!CanWrite && (Config->Shared || (Config->Pic && !isRelExpr(Expr)))) { - error( - "can't create dynamic relocation " + toString(Type) + " against " + - (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + - " in readonly segment; recompile object files with -fPIC" + - getLocation(S, Sym, RelOff)); - return Expr; - } - - // Copy relocations are only possible if we are creating an executable and the - // symbol is shared. - if (!Sym.isShared() || Config->Shared) - return Expr; - - if (Sym.getVisibility() != STV_DEFAULT && - (Sym.getVisibility() != STV_PROTECTED || !Sym.isFunc())) { - error("cannot preempt symbol: " + toString(Sym) + - getLocation(S, Sym, RelOff)); - return Expr; - } - - if (Sym.isObject()) { - // Produce a copy relocation. - auto *B = dyn_cast<SharedSymbol>(&Sym); - if (B && !B->CopyRelSec) { - if (Config->ZNocopyreloc) - error("unresolvable relocation " + toString(Type) + - " against symbol '" + toString(*B) + - "'; recompile with -fPIC or remove '-z nocopyreloc'" + - getLocation(S, Sym, RelOff)); - - addCopyRelSymbol<ELFT>(B); - } - IsConstant = true; - return Expr; - } - - if (Sym.isFunc()) - return getPltExpr(Sym, Expr, IsConstant); - - errorOrWarn("symbol '" + toString(Sym) + "' defined in " + - toString(Sym.File) + " has no type"); - return Expr; + InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); } // MIPS has an odd notion of "paired" relocations to calculate addends. @@ -733,7 +634,7 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, return false; bool CanBeExternal = - Sym.computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT; + Sym.computeBinding() != STB_LOCAL && Sym.Visibility == STV_DEFAULT; if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal) return false; @@ -761,12 +662,12 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, // this for the N32 ABI. Iterate over relocation with the same offset and put // theirs types into the single bit-set. template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) { - RelType Type = Rel->getType(Config->IsMips64EL); + RelType Type = 0; uint64_t Offset = Rel->r_offset; int N = 0; - while (Rel + 1 != End && (Rel + 1)->r_offset == Offset) - Type |= (++Rel)->getType(Config->IsMips64EL) << (8 * ++N); + while (Rel != End && Rel->r_offset == Offset) + Type |= (Rel++)->getType(Config->IsMips64EL) << (8 * N++); return Type; } @@ -816,16 +717,34 @@ private: }; } // namespace +static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec, + Symbol *Sym, int64_t Addend, RelExpr Expr, + RelType Type) { + // Add a relative relocation. If RelrDyn section is enabled, and the + // relocation offset is guaranteed to be even, add the relocation to + // the RelrDyn section, otherwise add it to the RelaDyn section. + // RelrDyn sections don't support odd offsets. Also, RelrDyn sections + // don't store the addend values, so we must write it to the relocated + // address. + if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { + IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); + InX::RelrDyn->Relocs.push_back({IS, OffsetInSec}); + return; + } + InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, + Expr, Type); +} + template <class ELFT, class GotPltSection> static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, - RelocationBaseSection *Rel, RelType Type, Symbol &Sym, - bool UseSymVA) { + RelocationBaseSection *Rel, RelType Type, Symbol &Sym) { Plt->addEntry<ELFT>(Sym); GotPlt->addEntry(Sym); - Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0}); + Rel->addReloc( + {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0}); } -template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { +template <class ELFT> static void addGotEntry(Symbol &Sym) { InX::Got->addEntry(Sym); RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS; @@ -838,7 +757,8 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { // add a static relocation to a Relocations vector so that // InputSection::relocate will do the work for us. We may be able // to just write a value now, but it is a TODO.) - bool IsLinkTimeConstant = !Preemptible && (!Config->Pic || isAbsolute(Sym)); + bool IsLinkTimeConstant = + !Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym)); if (IsLinkTimeConstant) { InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym}); return; @@ -846,23 +766,33 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that // the GOT slot will be fixed at load-time. - RelType Type; - if (Sym.isTls()) - Type = Target->TlsGotRel; - else if (!Preemptible && Config->Pic && !isAbsolute(Sym)) - Type = Target->RelativeRel; - else - Type = Target->GotRel; - InX::RelaDyn->addReloc({Type, InX::Got, Off, !Preemptible, &Sym, 0}); + if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) { + addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel); + return; + } + InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, + InX::Got, Off, &Sym, 0, + Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel); +} - // REL type relocations don't have addend fields unlike RELAs, and - // their addends are stored to the section to which they are applied. - // So, store addends if we need to. - // - // This is ugly -- the difference between REL and RELA should be - // handled in a better way. It's a TODO. - if (!Config->IsRela && !Preemptible) - InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym}); +// Return true if we can define a symbol in the executable that +// contains the value/function of a symbol defined in a shared +// library. +static bool canDefineSymbolInExecutable(Symbol &Sym) { + // If the symbol has default visibility the symbol defined in the + // executable will preempt it. + // Note that we want the visibility of the shared symbol itself, not + // the visibility of the symbol in the output file we are producing. That is + // why we use Sym.StOther. + if ((Sym.StOther & 0x3) == STV_DEFAULT) + return true; + + // If we are allowed to break address equality of functions, defining + // a plt entry will allow the program to call the function in the + // .so, but the .so and the executable will no agree on the address + // of the function. Similar logic for objects. + return ((Sym.isFunc() && Config->IgnoreFunctionAddressEquality) || + (Sym.isObject() && Config->IgnoreDataAddressEquality)); } // The reason we have to do this early scan is as follows @@ -879,129 +809,23 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { // complicates things for the dynamic linker and means we would have to reserve // space for the extra PT_LOAD even if we end up not using it. template <class ELFT, class RelTy> -static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { - OffsetGetter GetOffset(Sec); - - // Not all relocations end up in Sec.Relocations, but a lot do. - Sec.Relocations.reserve(Rels.size()); - - for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) { - const RelTy &Rel = *I; - Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); - RelType Type = Rel.getType(Config->IsMips64EL); - - // Deal with MIPS oddity. - if (Config->MipsN32Abi) - Type = getMipsN32RelType(I, End); - - // Get an offset in an output section this relocation is applied to. - uint64_t Offset = GetOffset.get(Rel.r_offset); - if (Offset == uint64_t(-1)) - continue; - - // Skip if the target symbol is an erroneous undefined symbol. - if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) - continue; - - RelExpr Expr = - Target->getRelExpr(Type, Sym, Sec.Data.begin() + Rel.r_offset); - - // Ignore "hint" relocations because they are only markers for relaxation. - if (isRelExprOneOf<R_HINT, R_NONE>(Expr)) - continue; - - // Handle yet another MIPS-ness. - if (isMipsGprel(Type)) { - int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); - Sec.Relocations.push_back({R_MIPS_GOTREL, Type, Offset, Addend, &Sym}); - continue; - } - - bool Preemptible = Sym.IsPreemptible; - - // Strenghten or relax a PLT access. - // - // GNU ifunc symbols must be accessed via PLT because their addresses - // are determined by runtime. - // - // On the other hand, if we know that a PLT entry will be resolved within - // the same ELF module, we can skip PLT access and directly jump to the - // destination function. For example, if we are linking a main exectuable, - // all dynamic symbols that can be resolved within the executable will - // actually be resolved that way at runtime, because the main exectuable - // is always at the beginning of a search list. We can leverage that fact. - if (Sym.isGnuIFunc()) - Expr = toPlt(Expr); - else if (!Preemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) - Expr = - Target->adjustRelaxExpr(Type, Sec.Data.data() + Rel.r_offset, Expr); - else if (!Preemptible) - Expr = fromPlt(Expr); - - bool IsConstant = - isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Rel.r_offset); - - Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset, IsConstant); - if (errorCount()) - continue; - - // This relocation does not require got entry, but it is relative to got and - // needs it to be created. Here we request for that. - if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL, - R_GOTREL_FROM_END, R_PPC_TOC>(Expr)) - InX::Got->HasGotOffRel = true; - - // Read an addend. - int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); - - // Process some TLS relocations, including relaxing TLS relocations. - // Note that this function does not handle all TLS relocations. - if (unsigned Processed = - handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) { - I += (Processed - 1); - continue; - } - - // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. - if (needsPlt(Expr) && !Sym.isInPlt()) { - if (Sym.isGnuIFunc() && !Preemptible) - addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt, - Target->IRelativeRel, Sym, true); - else - addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, - Sym, !Preemptible); - } - - // Create a GOT slot if a relocation needs GOT. - if (needsGot(Expr)) { - if (Config->EMachine == EM_MIPS) { - // MIPS ABI has special rules to process GOT entries and doesn't - // require relocation entries for them. A special case is TLS - // relocations. In that case dynamic loader applies dynamic - // relocations to initialize TLS GOT entries. - // See "Global Offset Table" in Chapter 5 in the following document - // for detailed description: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - InX::MipsGot->addEntry(Sym, Addend, Expr); - if (Sym.isTls() && Sym.IsPreemptible) - InX::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot, - Sym.getGotOffset(), false, &Sym, 0}); - } else if (!Sym.isInGot()) { - addGotEntry<ELFT>(Sym, Preemptible); - } - } - - if (!needsPlt(Expr) && !needsGot(Expr) && Sym.IsPreemptible) { - // We don't know anything about the finaly symbol. Just ask the dynamic - // linker to handle the relocation for us. - if (!Target->isPicRel(Type)) - errorOrWarn( - "relocation " + toString(Type) + - " cannot be used against shared object; recompile with -fPIC" + - getLocation(Sec, Sym, Offset)); +static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, + uint64_t Offset, Symbol &Sym, const RelTy &Rel, + int64_t Addend) { + if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) { + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return; + } + bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText; + if (CanWrite) { + // R_GOT refers to a position in the got, even if the symbol is preemptible. + bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT; - InX::RelaDyn->addReloc( - {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend}); + if (!IsPreemptibleValue) { + addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type); + return; + } else if (RelType Rel = Target->getDynRel(Type)) { + InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); // MIPS ABI turns using of GOT and dynamic relocations inside out. // While regular ABI uses dynamic relocations to fill up GOT entries @@ -1019,37 +843,210 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 if (Config->EMachine == EM_MIPS) - InX::MipsGot->addEntry(Sym, Addend, Expr); - continue; + InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); + return; } + } - // The size is not going to change, so we fold it in here. - if (Expr == R_SIZE) - Addend += Sym.getSize(); + // If the relocation is to a weak undef, and we are producing + // executable, give up on it and produce a non preemptible 0. + if (!Config->Shared && Sym.isUndefWeak()) { + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return; + } - // If the produced value is a constant, we just remember to write it - // when outputting this section. We also have to do it if the format - // uses Elf_Rel, since in that case the written value is the addend. - if (IsConstant) { - Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); - continue; + if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) { + error( + "can't create dynamic relocation " + toString(Type) + " against " + + (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + + " in readonly segment; recompile object files with -fPIC " + "or pass '-Wl,-z,notext' to allow text relocations in the output" + + getLocation(Sec, Sym, Offset)); + return; + } + + // Copy relocations are only possible if we are creating an executable. + if (Config->Shared) { + errorOrWarn("relocation " + toString(Type) + + " cannot be used against symbol " + toString(Sym) + + "; recompile with -fPIC" + getLocation(Sec, Sym, Offset)); + return; + } + + // If the symbol is undefined we already reported any relevant errors. + if (Sym.isUndefined()) + return; + + if (!canDefineSymbolInExecutable(Sym)) { + error("cannot preempt symbol: " + toString(Sym) + + getLocation(Sec, Sym, Offset)); + return; + } + + if (Sym.isObject()) { + // Produce a copy relocation. + if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) { + if (!Config->ZCopyreloc) + error("unresolvable relocation " + toString(Type) + + " against symbol '" + toString(*SS) + + "'; recompile with -fPIC or remove '-z nocopyreloc'" + + getLocation(Sec, Sym, Offset)); + addCopyRelSymbol<ELFT>(*SS); } + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return; + } - // If the output being produced is position independent, the final value - // is still not known. In that case we still need some help from the - // dynamic linker. We can however do better than just copying the incoming - // relocation. We can process some of it and and just ask the dynamic - // linker to add the load address. - if (Config->IsRela) { - InX::RelaDyn->addReloc( - {Target->RelativeRel, &Sec, Offset, true, &Sym, Addend}); - } else { - // In REL, addends are stored to the target section. - InX::RelaDyn->addReloc( - {Target->RelativeRel, &Sec, Offset, true, &Sym, 0}); - Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + if (Sym.isFunc()) { + // This handles a non PIC program call to function in a shared library. In + // an ideal world, we could just report an error saying the relocation can + // overflow at runtime. In the real world with glibc, crt1.o has a + // R_X86_64_PC32 pointing to libc.so. + // + // The general idea on how to handle such cases is to create a PLT entry and + // use that as the function value. + // + // For the static linking part, we just return a plt expr and everything + // else will use the PLT entry as the address. + // + // The remaining problem is making sure pointer equality still works. We + // need the help of the dynamic linker for that. We let it know that we have + // a direct reference to a so symbol by creating an undefined symbol with a + // non zero st_value. Seeing that, the dynamic linker resolves the symbol to + // the value of the symbol we created. This is true even for got entries, so + // pointer equality is maintained. To avoid an infinite loop, the only entry + // that points to the real function is a dedicated got entry used by the + // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, + // R_386_JMP_SLOT, etc). + + // For position independent executable on i386, the plt entry requires ebx + // to be set. This causes two problems: + // * If some code has a direct reference to a function, it was probably + // compiled without -fPIE/-fPIC and doesn't maintain ebx. + // * If a library definition gets preempted to the executable, it will have + // the wrong ebx value. + if (Config->Pie && Config->EMachine == EM_386) + errorOrWarn("symbol '" + toString(Sym) + + "' cannot be preempted; recompile with -fPIE" + + getLocation(Sec, Sym, Offset)); + if (!Sym.isInPlt()) + addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, + Sym); + if (!Sym.isDefined()) + replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0); + Sym.NeedsPltAddr = true; + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return; + } + + errorOrWarn("symbol '" + toString(Sym) + "' has no type" + + getLocation(Sec, Sym, Offset)); +} + +template <class ELFT, class RelTy> +static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I, + RelTy *End) { + const RelTy &Rel = *I; + Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); + RelType Type; + + // Deal with MIPS oddity. + if (Config->MipsN32Abi) { + Type = getMipsN32RelType(I, End); + } else { + Type = Rel.getType(Config->IsMips64EL); + ++I; + } + + // Get an offset in an output section this relocation is applied to. + uint64_t Offset = GetOffset.get(Rel.r_offset); + if (Offset == uint64_t(-1)) + return; + + // Skip if the target symbol is an erroneous undefined symbol. + if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) + return; + + const uint8_t *RelocatedAddr = Sec.Data.begin() + Rel.r_offset; + RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr); + + // Ignore "hint" relocations because they are only markers for relaxation. + if (isRelExprOneOf<R_HINT, R_NONE>(Expr)) + return; + + // Strenghten or relax relocations. + // + // GNU ifunc symbols must be accessed via PLT because their addresses + // are determined by runtime. + // + // On the other hand, if we know that a PLT entry will be resolved within + // the same ELF module, we can skip PLT access and directly jump to the + // destination function. For example, if we are linking a main exectuable, + // all dynamic symbols that can be resolved within the executable will + // actually be resolved that way at runtime, because the main exectuable + // is always at the beginning of a search list. We can leverage that fact. + if (Sym.isGnuIFunc()) + Expr = toPlt(Expr); + else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) + Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr); + else if (!Sym.IsPreemptible) + Expr = fromPlt(Expr); + + // This relocation does not require got entry, but it is relative to got and + // needs it to be created. Here we request for that. + if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL, + R_GOTREL_FROM_END, R_PPC_TOC>(Expr)) + InX::Got->HasGotOffRel = true; + + // Read an addend. + int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); + + // Process some TLS relocations, including relaxing TLS relocations. + // Note that this function does not handle all TLS relocations. + if (unsigned Processed = + handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) { + I += (Processed - 1); + return; + } + + // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. + if (needsPlt(Expr) && !Sym.isInPlt()) { + if (Sym.isGnuIFunc() && !Sym.IsPreemptible) + addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt, + Target->IRelativeRel, Sym); + else + addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, + Sym); + } + + // Create a GOT slot if a relocation needs GOT. + if (needsGot(Expr)) { + if (Config->EMachine == EM_MIPS) { + // MIPS ABI has special rules to process GOT entries and doesn't + // require relocation entries for them. A special case is TLS + // relocations. In that case dynamic loader applies dynamic + // relocations to initialize TLS GOT entries. + // See "Global Offset Table" in Chapter 5 in the following document + // for detailed description: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); + } else if (!Sym.isInGot()) { + addGotEntry<ELFT>(Sym); } } + + processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend); +} + +template <class ELFT, class RelTy> +static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { + OffsetGetter GetOffset(Sec); + + // Not all relocations end up in Sec.Relocations, but a lot do. + Sec.Relocations.reserve(Rels.size()); + + for (auto I = Rels.begin(), End = Rels.end(); I != End;) + scanReloc<ELFT>(Sec, GetOffset, I, End); } template <class ELFT> void elf::scanRelocations(InputSectionBase &S) { @@ -1264,17 +1261,30 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) { // // We follow a simple but conservative heuristic to place ThunkSections at // offsets that are multiples of a Target specific branch range. -// For an InputSectionRange that is smaller than the range, a single +// For an InputSectionDescription that is smaller than the range, a single // ThunkSection at the end of the range will do. +// +// For an InputSectionDescription that is more than twice the size of the range, +// we place the last ThunkSection at range bytes from the end of the +// InputSectionDescription in order to increase the likelihood that the +// distance from a thunk to its target will be sufficiently small to +// allow for the creation of a short thunk. void ThunkCreator::createInitialThunkSections( ArrayRef<OutputSection *> OutputSections) { forEachInputSectionDescription( OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { if (ISD->Sections.empty()) return; + uint32_t ISDBegin = ISD->Sections.front()->OutSecOff; + uint32_t ISDEnd = + ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize(); + uint32_t LastThunkLowerBound = -1; + if (ISDEnd - ISDBegin > Target->ThunkSectionSpacing * 2) + LastThunkLowerBound = ISDEnd - Target->ThunkSectionSpacing; + uint32_t ISLimit; - uint32_t PrevISLimit = ISD->Sections.front()->OutSecOff; - uint32_t ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + uint32_t PrevISLimit = ISDBegin; + uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing; for (const InputSection *IS : ISD->Sections) { ISLimit = IS->OutSecOff + IS->getSize(); @@ -1282,6 +1292,8 @@ void ThunkCreator::createInitialThunkSections( addThunkSection(OS, ISD, PrevISLimit); ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing; } + if (ISLimit > LastThunkLowerBound) + break; PrevISLimit = ISLimit; } addThunkSection(OS, ISD, ISLimit); @@ -1298,17 +1310,22 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS, std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type, uint64_t Src) { - auto Res = ThunkedSymbols.insert({&Sym, std::vector<Thunk *>()}); - if (!Res.second) { - // Check existing Thunks for Sym to see if they can be reused - for (Thunk *ET : Res.first->second) - if (ET->isCompatibleWith(Type) && - Target->inBranchRange(Type, Src, ET->ThunkSym->getVA())) - return std::make_pair(ET, false); - } + std::vector<Thunk *> *ThunkVec = nullptr; + // We use (section, offset) pair to find the thunk position if possible so + // that we create only one thunk for aliased symbols or ICFed sections. + if (auto *D = dyn_cast<Defined>(&Sym)) + if (!D->isInPlt() && D->Section) + ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}]; + if (!ThunkVec) + ThunkVec = &ThunkedSymbols[&Sym]; + // Check existing Thunks for Sym to see if they can be reused + for (Thunk *ET : *ThunkVec) + if (ET->isCompatibleWith(Type) && + Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA())) + return std::make_pair(ET, false); // No existing compatible Thunk in range, create a new one Thunk *T = addThunk(Type, Sym); - Res.first->second.push_back(T); + ThunkVec->push_back(T); return std::make_pair(T, true); } @@ -1316,7 +1333,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type, // InputSectionDescription::Sections. void ThunkCreator::forEachInputSectionDescription( ArrayRef<OutputSection *> OutputSections, - std::function<void(OutputSection *, InputSectionDescription *)> Fn) { + llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) { for (OutputSection *OS : OutputSections) { if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) continue; @@ -1384,7 +1401,7 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { for (InputSection *IS : ISD->Sections) for (Relocation &Rel : IS->Relocations) { - uint64_t Src = OS->Addr + IS->OutSecOff + Rel.Offset; + uint64_t Src = IS->getVA(Rel.Offset); // If we are a relocation to an existing Thunk, check if it is // still in range. If not then Rel will be altered to point to its @@ -1399,7 +1416,6 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { bool IsNew; std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src); if (IsNew) { - AddressesChanged = true; // Find or create a ThunkSection for the new Thunk ThunkSection *TS; if (auto *TIS = T->getTargetInputSection()) @@ -1407,13 +1423,18 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { else TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src); TS->addThunk(T); - Thunks[T->ThunkSym] = T; + Thunks[T->getThunkTargetSym()] = T; } // Redirect relocation to Thunk, we never go via the PLT to a Thunk - Rel.Sym = T->ThunkSym; + Rel.Sym = T->getThunkTargetSym(); Rel.Expr = fromPlt(Rel.Expr); } + for (auto &P : ISD->ThunkSections) + AddressesChanged |= P.first->assignOffsets(); }); + for (auto &P : ThunkedSections) + AddressesChanged |= P.second->assignOffsets(); + // Merge all created synthetic ThunkSections back into OutputSection mergeThunks(OutputSections); ++Pass; diff --git a/gnu/llvm/tools/lld/ELF/SymbolTable.cpp b/gnu/llvm/tools/lld/ELF/SymbolTable.cpp index c3a00bea4aa..1f5a84ec2c7 100644 --- a/gnu/llvm/tools/lld/ELF/SymbolTable.cpp +++ b/gnu/llvm/tools/lld/ELF/SymbolTable.cpp @@ -38,7 +38,7 @@ static InputFile *getFirstElf() { return ObjectFiles[0]; if (!SharedFiles.empty()) return SharedFiles[0]; - return nullptr; + return BitcodeFiles[0]; } // All input object files must be for the same architecture @@ -82,6 +82,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) { // Lazy object file if (auto *F = dyn_cast<LazyObjFile>(File)) { + LazyObjFiles.push_back(F); F->parse<ELFT>(); return; } @@ -117,7 +118,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) { // not in native object file format but in the LLVM bitcode format. // This function compiles bitcode files into a few big native files // using LLVM functions and replaces bitcode symbols with the results. -// Because all bitcode files that consist of a program are passed +// Because all bitcode files that the program consists of are passed // to the compiler at once, it can do whole-program optimization. template <class ELFT> void SymbolTable::addCombinedLTOObject() { if (BitcodeFiles.empty()) @@ -130,7 +131,10 @@ template <class ELFT> void SymbolTable::addCombinedLTOObject() { for (InputFile *File : LTO->compile()) { DenseSet<CachedHashStringRef> DummyGroups; - cast<ObjFile<ELFT>>(File)->parse(DummyGroups); + auto *Obj = cast<ObjFile<ELFT>>(File); + Obj->parse(DummyGroups); + for (Symbol *Sym : Obj->getGlobalSymbols()) + Sym->parseSymbolVersion(); ObjectFiles.push_back(File); } } @@ -154,6 +158,12 @@ template <class ELFT> void SymbolTable::addSymbolWrap(StringRef Name) { Symbol *Sym = find(Name); if (!Sym) return; + + // Do not wrap the same symbol twice. + for (const WrappedSymbol &S : WrappedSymbols) + if (S.Sym == Sym) + return; + Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name)); Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name)); WrappedSymbols.push_back({Sym, Real, Wrap}); @@ -186,7 +196,7 @@ void SymbolTable::applySymbolWrap() { // First, make a copy of __real_sym. Symbol *Real = nullptr; if (W.Real->isDefined()) { - Real = (Symbol *)make<SymbolUnion>(); + Real = reinterpret_cast<Symbol *>(make<SymbolUnion>()); memcpy(Real, W.Real, sizeof(SymbolUnion)); } @@ -234,8 +244,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { Symbol *Sym; if (IsNew) { - Sym = (Symbol *)make<SymbolUnion>(); - Sym->InVersionScript = false; + Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); Sym->Visibility = STV_DEFAULT; Sym->IsUsedInRegularObj = false; Sym->ExportDynamic = false; @@ -294,26 +303,88 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding, uint8_t Visibility = getVisibility(StOther); std::tie(S, WasInserted) = insert(Name, Type, Visibility, CanOmitFromDynSym, File); + // An undefined symbol with non default visibility must be satisfied // in the same DSO. if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) { replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type); return S; } + if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK)) S->Binding = Binding; - if (Binding != STB_WEAK) { + + if (!Config->GcSections && Binding != STB_WEAK) if (auto *SS = dyn_cast<SharedSymbol>(S)) - if (!Config->GcSections) - SS->getFile<ELFT>().IsNeeded = true; - } - if (auto *L = dyn_cast<Lazy>(S)) { + SS->getFile<ELFT>().IsNeeded = true; + + if (S->isLazy()) { // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. - if (Binding == STB_WEAK) - L->Type = Type; - else if (InputFile *F = L->fetch()) - addFile<ELFT>(F); + if (Binding == STB_WEAK) { + S->Type = Type; + return S; + } + + // Do extra check for --warn-backrefs. + // + // --warn-backrefs is an option to prevent an undefined reference from + // fetching an archive member written earlier in the command line. It can be + // used to keep compatibility with GNU linkers to some degree. + // I'll explain the feature and why you may find it useful in this comment. + // + // lld's symbol resolution semantics is more relaxed than traditional Unix + // linkers. For example, + // + // ld.lld foo.a bar.o + // + // succeeds even if bar.o contains an undefined symbol that has to be + // resolved by some object file in foo.a. Traditional Unix linkers don't + // allow this kind of backward reference, as they visit each file only once + // from left to right in the command line while resolving all undefined + // symbols at the moment of visiting. + // + // In the above case, since there's no undefined symbol when a linker visits + // foo.a, no files are pulled out from foo.a, and because the linker forgets + // about foo.a after visiting, it can't resolve undefined symbols in bar.o + // that could have been resolved otherwise. + // + // That lld accepts more relaxed form means that (besides it'd make more + // sense) you can accidentally write a command line or a build file that + // works only with lld, even if you have a plan to distribute it to wider + // users who may be using GNU linkers. With --warn-backrefs, you can detect + // a library order that doesn't work with other Unix linkers. + // + // The option is also useful to detect cyclic dependencies between static + // archives. Again, lld accepts + // + // ld.lld foo.a bar.a + // + // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is + // handled as an error. + // + // Here is how the option works. We assign a group ID to each file. A file + // with a smaller group ID can pull out object files from an archive file + // with an equal or greater group ID. Otherwise, it is a reverse dependency + // and an error. + // + // A file outside --{start,end}-group gets a fresh ID when instantiated. All + // files within the same --{start,end}-group get the same group ID. E.g. + // + // ld.lld A B --start-group C D --end-group E + // + // A forms group 0. B form group 1. C and D (including their member object + // files) form group 2. E forms group 3. I think that you can see how this + // group assignment rule simulates the traditional linker's semantics. + bool Backref = + Config->WarnBackrefs && File && S->File->GroupId < File->GroupId; + fetchLazy<ELFT>(S); + + // We don't report backward references to weak symbols as they can be + // overridden later. + if (Backref && S->Binding != STB_WEAK) + warn("backward reference detected: " + Name + " in " + toString(File) + + " refers to " + toString(S->File)); } return S; } @@ -381,7 +452,11 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, &File); + int Cmp = compareDefined(S, WasInserted, Binding, N); + if (Cmp < 0) + return S; + if (Cmp > 0) { auto *Bss = make<BssSection>("COMMON", Size, Alignment); Bss->File = &File; @@ -389,45 +464,43 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, InputSections.push_back(Bss); replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss); - } else if (Cmp == 0) { - auto *D = cast<Defined>(S); - auto *Bss = dyn_cast_or_null<BssSection>(D->Section); - if (!Bss) { - // Non-common symbols take precedence over common symbols. - if (Config->WarnCommon) - warn("common " + S->getName() + " is overridden"); - return S; - } + return S; + } + auto *D = cast<Defined>(S); + auto *Bss = dyn_cast_or_null<BssSection>(D->Section); + if (!Bss) { + // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) - warn("multiple common of " + D->getName()); + warn("common " + S->getName() + " is overridden"); + return S; + } - Bss->Alignment = std::max(Bss->Alignment, Alignment); - if (Size > Bss->Size) { - D->File = Bss->File = &File; - D->Size = Bss->Size = Size; - } + if (Config->WarnCommon) + warn("multiple common of " + D->getName()); + + Bss->Alignment = std::max(Bss->Alignment, Alignment); + if (Size > Bss->Size) { + D->File = Bss->File = &File; + D->Size = Bss->Size = Size; } return S; } -static void warnOrError(const Twine &Msg) { - if (Config->AllowMultipleDefinition) - warn(Msg); - else - error(Msg); -} - static void reportDuplicate(Symbol *Sym, InputFile *NewFile) { - warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + - toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); + if (!Config->AllowMultipleDefinition) + error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + + toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); } -static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, - uint64_t ErrOffset) { +static void reportDuplicate(Symbol *Sym, InputFile *NewFile, + InputSectionBase *ErrSec, uint64_t ErrOffset) { + if (Config->AllowMultipleDefinition) + return; + Defined *D = cast<Defined>(Sym); if (!D->Section || !ErrSec) { - reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr); + reportDuplicate(Sym, NewFile); return; } @@ -451,7 +524,7 @@ static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, if (!Src2.empty()) Msg += Src2 + "\n>>> "; Msg += Obj2; - warnOrError(Msg); + error(Msg); } Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, @@ -467,7 +540,8 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size, Section); else if (Cmp == 0) - reportDuplicate(S, dyn_cast_or_null<InputSectionBase>(Section), Value); + reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section), + Value); return S; } @@ -488,8 +562,8 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File, // An undefined symbol with non default visibility must be satisfied // in the same DSO. - if (WasInserted || ((S->isUndefined() || S->isLazy()) && - S->getVisibility() == STV_DEFAULT)) { + if (WasInserted || + ((S->isUndefined() || S->isLazy()) && S->Visibility == STV_DEFAULT)) { uint8_t Binding = S->Binding; bool WasUndefined = S->isUndefined(); replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other, @@ -528,85 +602,58 @@ Symbol *SymbolTable::find(StringRef Name) { return SymVector[It->second]; } -template <class ELFT> -Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F, - const object::Archive::Symbol Sym) { +// This is used to handle lazy symbols. May replace existent +// symbol with lazy version or request to Fetch it. +template <class ELFT, typename LazyT, typename... ArgT> +static void replaceOrFetchLazy(StringRef Name, InputFile &File, + llvm::function_ref<InputFile *()> Fetch, + ArgT &&... Arg) { Symbol *S; bool WasInserted; - std::tie(S, WasInserted) = insert(Name); + std::tie(S, WasInserted) = Symtab->insert(Name); if (WasInserted) { - replaceSymbol<LazyArchive>(S, F, Sym, Symbol::UnknownType); - return S; + replaceSymbol<LazyT>(S, File, Symbol::UnknownType, + std::forward<ArgT>(Arg)...); + return; } if (!S->isUndefined()) - return S; + return; // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. if (S->isWeak()) { - replaceSymbol<LazyArchive>(S, F, Sym, S->Type); + replaceSymbol<LazyT>(S, File, S->Type, std::forward<ArgT>(Arg)...); S->Binding = STB_WEAK; - return S; + return; } - std::pair<MemoryBufferRef, uint64_t> MBInfo = F.getMember(&Sym); - if (!MBInfo.first.getBuffer().empty()) - addFile<ELFT>(createObjectFile(MBInfo.first, F.getName(), MBInfo.second)); - return S; + + if (InputFile *F = Fetch()) + Symtab->addFile<ELFT>(F); } template <class ELFT> -void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(Name); - if (WasInserted) { - replaceSymbol<LazyObject>(S, Obj, Name, Symbol::UnknownType); - return; - } - if (!S->isUndefined()) - return; - - // See comment for addLazyArchive above. - if (S->isWeak()) - replaceSymbol<LazyObject>(S, Obj, Name, S->Type); - else if (InputFile *F = Obj.fetch()) - addFile<ELFT>(F); -} - -// If we already saw this symbol, force loading its file. -template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) { - if (Symbol *B = find(Name)) { - // Mark the symbol not to be eliminated by LTO - // even if it is a bitcode symbol. - B->IsUsedInRegularObj = true; - if (auto *L = dyn_cast<Lazy>(B)) - if (InputFile *File = L->fetch()) - addFile<ELFT>(File); - } +void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F, + const object::Archive::Symbol Sym) { + replaceOrFetchLazy<ELFT, LazyArchive>(Name, F, [&]() { return F.fetch(Sym); }, + Sym); } -// This function takes care of the case in which shared libraries depend on -// the user program (not the other way, which is usual). Shared libraries -// may have undefined symbols, expecting that the user program provides -// the definitions for them. An example is BSD's __progname symbol. -// We need to put such symbols to the main program's .dynsym so that -// shared libraries can find them. -// Except this, we ignore undefined symbols in DSOs. -template <class ELFT> void SymbolTable::scanShlibUndefined() { - for (InputFile *F : SharedFiles) { - for (StringRef U : cast<SharedFile<ELFT>>(F)->getUndefinedSymbols()) { - Symbol *Sym = find(U); - if (!Sym || !Sym->isDefined()) - continue; - Sym->ExportDynamic = true; +template <class ELFT> +void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { + replaceOrFetchLazy<ELFT, LazyObject>(Name, Obj, [&]() { return Obj.fetch(); }, + Name); +} - // If -dynamic-list is given, the default version is set to - // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym. - // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were - // specified by -dynamic-list. - Sym->VersionId = VER_NDX_GLOBAL; - } +template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) { + if (auto *S = dyn_cast<LazyArchive>(Sym)) { + if (InputFile *File = S->fetch()) + addFile<ELFT>(File); + return; } + + auto *S = cast<LazyObject>(Sym); + if (InputFile *File = cast<LazyObjFile>(S->File)->fetch()) + addFile<ELFT>(File); } // Initialize DemangledSyms with a map from demangled symbols to symbol @@ -705,7 +752,7 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, // Get a list of symbols which we need to assign the version to. std::vector<Symbol *> Syms = findByVersion(Ver); if (Syms.empty()) { - if (Config->NoUndefinedVersion) + if (!Config->UndefinedVersion) error("version script assignment of '" + VersionName + "' to symbol '" + Ver.Name + "' failed: symbol not defined"); return; @@ -719,10 +766,10 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, if (Sym->getName().contains('@')) continue; - if (Sym->InVersionScript) - warn("duplicate symbol '" + Ver.Name + "' in version script"); + if (Sym->VersionId != Config->DefaultSymbolVersion && + Sym->VersionId != VersionId) + error("duplicate symbol '" + Ver.Name + "' in version script"); Sym->VersionId = VersionId; - Sym->InVersionScript = true; } } @@ -770,6 +817,11 @@ void SymbolTable::scanVersionScript() { Sym->parseSymbolVersion(); } +template void SymbolTable::addFile<ELF32LE>(InputFile *); +template void SymbolTable::addFile<ELF32BE>(InputFile *); +template void SymbolTable::addFile<ELF64LE>(InputFile *); +template void SymbolTable::addFile<ELF64BE>(InputFile *); + template void SymbolTable::addSymbolWrap<ELF32LE>(StringRef); template void SymbolTable::addSymbolWrap<ELF32BE>(StringRef); template void SymbolTable::addSymbolWrap<ELF64LE>(StringRef); @@ -794,16 +846,16 @@ template void SymbolTable::addCombinedLTOObject<ELF32BE>(); template void SymbolTable::addCombinedLTOObject<ELF64LE>(); template void SymbolTable::addCombinedLTOObject<ELF64BE>(); -template Symbol * +template void SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &, const object::Archive::Symbol); -template Symbol * +template void SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &, const object::Archive::Symbol); -template Symbol * +template void SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &, const object::Archive::Symbol); -template Symbol * +template void SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &, const object::Archive::Symbol); @@ -812,6 +864,11 @@ template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &); +template void SymbolTable::fetchLazy<ELF32LE>(Symbol *); +template void SymbolTable::fetchLazy<ELF32BE>(Symbol *); +template void SymbolTable::fetchLazy<ELF64LE>(Symbol *); +template void SymbolTable::fetchLazy<ELF64BE>(Symbol *); + template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &, const typename ELF32LE::Sym &, uint32_t Alignment, uint32_t); @@ -824,13 +881,3 @@ template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &, template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &, const typename ELF64BE::Sym &, uint32_t Alignment, uint32_t); - -template void SymbolTable::fetchIfLazy<ELF32LE>(StringRef); -template void SymbolTable::fetchIfLazy<ELF32BE>(StringRef); -template void SymbolTable::fetchIfLazy<ELF64LE>(StringRef); -template void SymbolTable::fetchIfLazy<ELF64BE>(StringRef); - -template void SymbolTable::scanShlibUndefined<ELF32LE>(); -template void SymbolTable::scanShlibUndefined<ELF32BE>(); -template void SymbolTable::scanShlibUndefined<ELF64LE>(); -template void SymbolTable::scanShlibUndefined<ELF64BE>(); diff --git a/gnu/llvm/tools/lld/ELF/Symbols.cpp b/gnu/llvm/tools/lld/ELF/Symbols.cpp index 6e0a83c9612..dc0d891af97 100644 --- a/gnu/llvm/tools/lld/ELF/Symbols.cpp +++ b/gnu/llvm/tools/lld/ELF/Symbols.cpp @@ -14,7 +14,6 @@ #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" - #include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" @@ -40,6 +39,7 @@ Defined *ElfSym::GlobalOffsetTable; Defined *ElfSym::MipsGp; Defined *ElfSym::MipsGpDisp; Defined *ElfSym::MipsLocalGp; +Defined *ElfSym::RelaIpltEnd; static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { switch (Sym.kind()) { @@ -59,6 +59,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { return D.Value; IS = IS->Repl; + uint64_t Offset = D.Value; // An object in an SHF_MERGE section might be referenced via a @@ -77,8 +78,6 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { Addend = 0; } - const OutputSection *OutSec = IS->getOutputSection(); - // In the typical case, this is actually very simple and boils // down to adding together 3 numbers: // 1. The address of the output section. @@ -89,7 +88,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { // If you understand the data structures involved with this next // line (and how they get built), then you have a pretty good // understanding of the linker. - uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset); + uint64_t VA = IS->getVA(Offset); if (D.isTls() && !Config->Relocatable) { if (!Out::TlsPhdr) @@ -99,20 +98,12 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { } return VA; } - case Symbol::SharedKind: { - auto &SS = cast<SharedSymbol>(Sym); - if (SS.CopyRelSec) - return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff; - if (SS.NeedsPltAddr) - return Sym.getPltVA(); - return 0; - } + case Symbol::SharedKind: case Symbol::UndefinedKind: return 0; case Symbol::LazyArchiveKind: case Symbol::LazyObjectKind: - assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer"); - return 0; + llvm_unreachable("lazy symbol reached writer"); } llvm_unreachable("invalid symbol kind"); } @@ -135,22 +126,26 @@ uint64_t Symbol::getGotPltVA() const { } uint64_t Symbol::getGotPltOffset() const { - return GotPltIndex * Target->GotPltEntrySize; + if (IsInIgot) + return PltIndex * Target->GotPltEntrySize; + return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize; } uint64_t Symbol::getPltVA() const { if (this->IsInIplt) return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize; - return InX::Plt->getVA() + Target->PltHeaderSize + - PltIndex * Target->PltEntrySize; + return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex); +} + +uint64_t Symbol::getPltOffset() const { + assert(!this->IsInIplt); + return Target->getPltEntryOffset(PltIndex); } uint64_t Symbol::getSize() const { if (const auto *DR = dyn_cast<Defined>(this)) return DR->Size; - if (const auto *S = dyn_cast<SharedSymbol>(this)) - return S->Size; - return 0; + return cast<SharedSymbol>(this)->Size; } OutputSection *Symbol::getOutputSection() const { @@ -159,13 +154,6 @@ OutputSection *Symbol::getOutputSection() const { return Sec->Repl->getOutputSection(); return nullptr; } - - if (auto *S = dyn_cast<SharedSymbol>(this)) { - if (S->CopyRelSec) - return S->CopyRelSec->getParent(); - return nullptr; - } - return nullptr; } @@ -181,7 +169,7 @@ void Symbol::parseSymbolVersion() { return; // Truncate the symbol name so that it doesn't include the version string. - Name = {S.data(), Pos}; + NameSize = Pos; // If this is not in this DSO, it is not a definition. if (!isDefined()) @@ -207,42 +195,24 @@ void Symbol::parseSymbolVersion() { // It is an error if the specified version is not defined. // Usually version script is not provided when linking executable, // but we may still want to override a versioned symbol from DSO, - // so we do not report error in this case. - if (Config->Shared) + // so we do not report error in this case. We also do not error + // if the symbol has a local version as it won't be in the dynamic + // symbol table. + if (Config->Shared && VersionId != VER_NDX_LOCAL) error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); } -InputFile *Lazy::fetch() { - if (auto *S = dyn_cast<LazyArchive>(this)) - return S->fetch(); - return cast<LazyObject>(this)->fetch(); -} - -ArchiveFile &LazyArchive::getFile() { return *cast<ArchiveFile>(File); } - -InputFile *LazyArchive::fetch() { - std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile().getMember(&Sym); - - // getMember returns an empty buffer if the member was already - // read from the library. - if (MBInfo.first.getBuffer().empty()) - return nullptr; - return createObjectFile(MBInfo.first, getFile().getName(), MBInfo.second); -} - -LazyObjFile &LazyObject::getFile() { return *cast<LazyObjFile>(File); } - -InputFile *LazyObject::fetch() { return getFile().fetch(); } +InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); } uint8_t Symbol::computeBinding() const { if (Config->Relocatable) return Binding; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return STB_LOCAL; - if (VersionId == VER_NDX_LOCAL && isDefined()) + if (VersionId == VER_NDX_LOCAL && isDefined() && !IsPreemptible) return STB_LOCAL; - if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) + if (!Config->GnuUnique && Binding == STB_GNU_UNIQUE) return STB_GLOBAL; return Binding; } @@ -274,6 +244,27 @@ void elf::printTraceSymbol(Symbol *Sym) { message(toString(Sym->File) + S + Sym->getName()); } +void elf::warnUnorderableSymbol(const Symbol *Sym) { + if (!Config->WarnSymbolOrdering) + return; + + const InputFile *File = Sym->File; + auto *D = dyn_cast<Defined>(Sym); + + auto Warn = [&](StringRef S) { warn(toString(File) + S + Sym->getName()); }; + + if (Sym->isUndefined()) + Warn(": unable to order undefined symbol: "); + else if (Sym->isShared()) + Warn(": unable to order shared symbol: "); + else if (D && !D->Section) + Warn(": unable to order absolute symbol: "); + else if (D && isa<OutputSection>(D->Section)) + Warn(": unable to order synthetic symbol: "); + else if (D && !D->Section->Repl->Live) + Warn(": unable to order discarded symbol: "); +} + // Returns a symbol for an error message. std::string lld::toString(const Symbol &B) { if (Config->Demangle) diff --git a/gnu/llvm/tools/lld/ELF/Symbols.h b/gnu/llvm/tools/lld/ELF/Symbols.h index 1e3c0af64ef..6a33f5ebce2 100644 --- a/gnu/llvm/tools/lld/ELF/Symbols.h +++ b/gnu/llvm/tools/lld/ELF/Symbols.h @@ -7,8 +7,7 @@ // //===----------------------------------------------------------------------===// // -// All symbols are handled as SymbolBodies regardless of their types. -// This file defines various types of SymbolBodies. +// This file defines various types of Symbols. // //===----------------------------------------------------------------------===// @@ -16,9 +15,8 @@ #define LLD_ELF_SYMBOLS_H #include "InputSection.h" -#include "Strings.h" - #include "lld/Common/LLVM.h" +#include "lld/Common/Strings.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" @@ -34,6 +32,20 @@ template <class ELFT> class ObjFile; class OutputSection; template <class ELFT> class SharedFile; +// This is a StringRef-like container that doesn't run strlen(). +// +// ELF string tables contain a lot of null-terminated strings. Most of them +// are not necessary for the linker because they are names of local symbols, +// and the linker doesn't use local symbol names for name resolution. So, we +// use this class to represents strings read from string tables. +struct StringRefZ { + StringRefZ(const char *S) : Data(S), Size(-1) {} + StringRefZ(StringRef S) : Data(S.data()), Size(S.size()) {} + + const char *Data; + const uint32_t Size; +}; + // The base class for real symbol classes. class Symbol { public: @@ -47,6 +59,25 @@ public: Kind kind() const { return static_cast<Kind>(SymbolKind); } + // The file from which this symbol was created. + InputFile *File; + +protected: + const char *NameData; + mutable uint32_t NameSize; + +public: + uint32_t DynsymIndex = 0; + uint32_t GotIndex = -1; + uint32_t PltIndex = -1; + uint32_t GlobalDynIndex = -1; + + // This field is a index to the symbol's version definition. + uint32_t VerdefIndex = -1; + + // Version definition index. + uint16_t VersionId; + // Symbol binding. This is not overwritten by replaceSymbol to track // changes during resolution. In particular: // - An undefined weak is still weak when it resolves to a shared library. @@ -54,8 +85,11 @@ public: // remember it is weak. uint8_t Binding; - // Version definition index. - uint16_t VersionId; + // The following fields have the same meaning as the ELF symbol attributes. + uint8_t Type; // symbol type + uint8_t StOther; // st_other field value + + const uint8_t SymbolKind; // Symbol visibility. This is the computed minimum visibility of all // observed non-DSO symbols. @@ -81,12 +115,6 @@ public: // True if this symbol is specified by --trace-symbol option. unsigned Traced : 1; - // This symbol version was found in a version script. - unsigned InVersionScript : 1; - - // The file from which this symbol was created. - InputFile *File; - bool includeInDynsym() const; uint8_t computeBinding() const; bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } @@ -100,15 +128,15 @@ public: return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; } - // True is this is an undefined weak symbol. This only works once - // all input files have been added. - bool isUndefWeak() const { - // See comment on Lazy the details. - return isWeak() && (isUndefined() || isLazy()); + // True if this is an undefined weak symbol. + bool isUndefWeak() const { return isWeak() && isUndefined(); } + + StringRef getName() const { + if (NameSize == (uint32_t)-1) + NameSize = strlen(NameData); + return {NameData, NameSize}; } - StringRef getName() const { return Name; } - uint8_t getVisibility() const { return StOther & 0x3; } void parseSymbolVersion(); bool isInGot() const { return GotIndex != -1U; } @@ -121,34 +149,22 @@ public: uint64_t getGotPltOffset() const; uint64_t getGotPltVA() const; uint64_t getPltVA() const; + uint64_t getPltOffset() const; uint64_t getSize() const; OutputSection *getOutputSection() const; - uint32_t DynsymIndex = 0; - uint32_t GotIndex = -1; - uint32_t GotPltIndex = -1; - uint32_t PltIndex = -1; - uint32_t GlobalDynIndex = -1; - protected: Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther, uint8_t Type) - : Binding(Binding), File(File), SymbolKind(K), NeedsPltAddr(false), - IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), - IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections), - Type(Type), StOther(StOther), Name(Name) {} - - const unsigned SymbolKind : 8; + : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding), + Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false), + IsInIplt(false), IsInIgot(false), IsPreemptible(false), + Used(!Config->GcSections), NeedsTocRestore(false) {} public: // True the symbol should point to its PLT entry. // For SharedSymbol only. unsigned NeedsPltAddr : 1; - // True if this symbol has an entry in the global part of MIPS GOT. - unsigned IsInGlobalMipsGot : 1; - - // True if this symbol is referenced by 32-bit GOT relocations. - unsigned Is32BitMipsGot : 1; // True if this symbol is in the Iplt sub-section of the Plt. unsigned IsInIplt : 1; @@ -156,14 +172,15 @@ public: // True if this symbol is in the Igot sub-section of the .got.plt or .got. unsigned IsInIgot : 1; + // True if this symbol is preemptible at load time. unsigned IsPreemptible : 1; // True if an undefined or shared symbol is used from a live section. unsigned Used : 1; - // The following fields have the same meaning as the ELF symbol attributes. - uint8_t Type; // symbol type - uint8_t StOther; // st_other field value + // True if a call to this symbol needs to be followed by a restore of the + // PPC64 toc pointer. + unsigned NeedsTocRestore : 1; // The Type field may also have this value. It means that we have not yet seen // a non-Lazy symbol with this name, so we don't know what its type is. The @@ -178,9 +195,6 @@ public: bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; } bool isObject() const { return Type == llvm::ELF::STT_OBJECT; } bool isFile() const { return Type == llvm::ELF::STT_FILE; } - -protected: - StringRefZ Name; }; // Represents a symbol that is defined in the current output file. @@ -214,8 +228,9 @@ public: SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint32_t Alignment, uint32_t VerdefIndex) - : Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value), - Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) { + : Symbol(SharedKind, &File, Name, Binding, StOther, Type), + Alignment(Alignment), Value(Value), Size(Size) { + this->VerdefIndex = VerdefIndex; // GNU ifunc is a mechanism to allow user-supplied functions to // resolve PLT slot values at load-time. This is contrary to the // regular symbol resolution scheme in which symbols are resolved just @@ -240,54 +255,36 @@ public: return *cast<SharedFile<ELFT>>(File); } - // If not null, there is a copy relocation to this section. - InputSection *CopyRelSec = nullptr; + uint32_t Alignment; uint64_t Value; // st_value uint64_t Size; // st_size - - // This field is a index to the symbol's version definition. - uint32_t VerdefIndex; - - uint32_t Alignment; }; -// This represents a symbol that is not yet in the link, but we know where to -// find it if needed. If the resolver finds both Undefined and Lazy for the same -// name, it will ask the Lazy to load a file. +// LazyArchive and LazyObject represent a symbols that is not yet in the link, +// but we know where to find it if needed. If the resolver finds both Undefined +// and Lazy for the same name, it will ask the Lazy to load a file. // // A special complication is the handling of weak undefined symbols. They should // not load a file, but we have to remember we have seen both the weak undefined // and the lazy. We represent that with a lazy symbol with a weak binding. This // means that code looking for undefined symbols normally also has to take lazy // symbols into consideration. -class Lazy : public Symbol { -public: - static bool classof(const Symbol *S) { return S->isLazy(); } - - // Returns an object file for this symbol, or a nullptr if the file - // was already returned. - InputFile *fetch(); - -protected: - Lazy(Kind K, InputFile &File, StringRef Name, uint8_t Type) - : Symbol(K, &File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT, - Type) {} -}; // This class represents a symbol defined in an archive file. It is // created from an archive file header, and it knows how to load an // object file from an archive to replace itself with a defined // symbol. -class LazyArchive : public Lazy { +class LazyArchive : public Symbol { public: - LazyArchive(InputFile &File, const llvm::object::Archive::Symbol S, - uint8_t Type) - : Lazy(LazyArchiveKind, File, S.getName(), Type), Sym(S) {} + LazyArchive(InputFile &File, uint8_t Type, + const llvm::object::Archive::Symbol S) + : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL, + llvm::ELF::STV_DEFAULT, Type), + Sym(S) {} static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; } - ArchiveFile &getFile(); InputFile *fetch(); private: @@ -296,15 +293,13 @@ private: // LazyObject symbols represents symbols in object files between // --start-lib and --end-lib options. -class LazyObject : public Lazy { +class LazyObject : public Symbol { public: - LazyObject(InputFile &File, StringRef Name, uint8_t Type) - : Lazy(LazyObjectKind, File, Name, Type) {} + LazyObject(InputFile &File, uint8_t Type, StringRef Name) + : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL, + llvm::ELF::STV_DEFAULT, Type) {} static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; } - - LazyObjFile &getFile(); - InputFile *fetch(); }; // Some linker-generated symbols need to be created as @@ -337,6 +332,9 @@ struct ElfSym { static Defined *MipsGp; static Defined *MipsGpDisp; static Defined *MipsLocalGp; + + // __rela_iplt_end or __rel_iplt_end + static Defined *RelaIpltEnd; }; // A buffer class that is large enough to hold any Symbol-derived @@ -354,6 +352,8 @@ void printTraceSymbol(Symbol *Sym); template <typename T, typename... ArgT> void replaceSymbol(Symbol *S, ArgT &&... Arg) { + static_assert(std::is_trivially_destructible<T>(), + "Symbol types must be trivially destructible"); static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small"); static_assert(alignof(T) <= alignof(SymbolUnion), "SymbolUnion not aligned enough"); @@ -370,13 +370,14 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) { S->ExportDynamic = Sym.ExportDynamic; S->CanInline = Sym.CanInline; S->Traced = Sym.Traced; - S->InVersionScript = Sym.InVersionScript; // Print out a log message if --trace-symbol was specified. // This is for debugging. if (S->Traced) printTraceSymbol(S); } + +void warnUnorderableSymbol(const Symbol *Sym); } // namespace elf std::string toString(const elf::Symbol &B); diff --git a/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp b/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp index 023554cb268..475531f0ad1 100644 --- a/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp +++ b/gnu/llvm/tools/lld/ELF/SyntheticSections.cpp @@ -20,15 +20,16 @@ #include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "Target.h" #include "Writer.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/Decompressor.h" @@ -47,27 +48,20 @@ using namespace llvm::dwarf; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; -using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; -constexpr size_t MergeNoTailSection::NumShards; - -static void write32(void *Buf, uint32_t Val) { - endian::write32(Buf, Val, Config->Endianness); -} +using llvm::support::endian::read32le; +using llvm::support::endian::write32le; +using llvm::support::endian::write64le; -uint64_t SyntheticSection::getVA() const { - if (OutputSection *Sec = getParent()) - return Sec->Addr + OutSecOff; - return 0; -} +constexpr size_t MergeNoTailSection::NumShards; // Returns an LLD version string. static ArrayRef<uint8_t> getVersion() { // Check LLD_VERSION first for ease of testing. - // You can get consitent output by using the environment variable. + // You can get consistent output by using the environment variable. // This is only for testing. StringRef S = getenv("LLD_VERSION"); if (S.empty()) @@ -192,8 +186,6 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() { auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data()); if (Opt->kind == ODK_REGINFO) { - if (Config->Relocatable && Opt->getRegInfo().ri_gp_value) - error(Filename + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask; Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value; break; @@ -244,10 +236,8 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() { error(toString(Sec->File) + ": invalid size of .reginfo section"); return nullptr; } - auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data()); - if (Config->Relocatable && R->ri_gp_value) - error(toString(Sec->File) + ": unsupported non-zero ri_gp_value"); + auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data()); Reginfo.ri_gprmask |= R->ri_gprmask; Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value; }; @@ -266,8 +256,8 @@ InputSection *elf::createInterpSection() { return Sec; } -Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase &Section) { +Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, + uint64_t Size, InputSectionBase &Section) { auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type, Value, Size, &Section); if (InX::SymTab) @@ -338,8 +328,6 @@ void BuildIdSection::computeHash( BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment) : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) { this->Bss = true; - if (OutputSection *Sec = getParent()) - Sec->Alignment = std::max(Sec->Alignment, Alignment); this->Size = Size; } @@ -347,7 +335,7 @@ void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) { switch (Config->BuildId) { case BuildIdKind::Fast: computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { - write64le(Dest, xxHash64(toStringRef(Arr))); + write64le(Dest, xxHash64(Arr)); }); break; case BuildIdKind::Md5: @@ -380,15 +368,11 @@ EhFrameSection::EhFrameSection() // and where their relocations point to. template <class ELFT, class RelTy> CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) { - auto *Sec = cast<EhInputSection>(Cie.Sec); - if (read32(Cie.data().data() + 4, Config->Endianness) != 0) - fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame"); - Symbol *Personality = nullptr; unsigned FirstRelI = Cie.FirstRelocation; if (FirstRelI != (unsigned)-1) Personality = - &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]); + &Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]); // Search for an existing CIE by CIE contents/relocation target pair. CieRecord *&Rec = CieMap[{Cie.data(), Personality}]; @@ -433,14 +417,14 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) { // one and associates FDEs to the CIE. template <class ELFT, class RelTy> void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) { - DenseMap<size_t, CieRecord *> OffsetToCie; + OffsetToCie.clear(); for (EhSectionPiece &Piece : Sec->Pieces) { // The empty record is the end marker. if (Piece.Size == 4) return; size_t Offset = Piece.InputOff; - uint32_t ID = read32(Piece.data().data() + 4, Config->Endianness); + uint32_t ID = read32(Piece.data().data() + 4); if (ID == 0) { OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels); continue; @@ -468,10 +452,6 @@ template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) { for (auto *DS : Sec->DependentSections) DependentSections.push_back(DS); - // .eh_frame is a sequence of CIE or FDE records. This function - // splits it into pieces so that we can call - // SplitInputSection::getSectionPiece on the section. - Sec->split<ELFT>(); if (Sec->Pieces.empty()) return; @@ -494,9 +474,7 @@ static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) { } void EhFrameSection::finalizeContents() { - if (this->Size) - return; // Already finalized. - + assert(!this->Size); // Not finalized. size_t Off = 0; for (CieRecord *Rec : CieRecords) { Rec->Cie->OutputOff = Off; @@ -509,10 +487,10 @@ void EhFrameSection::finalizeContents() { } // The LSB standard does not allow a .eh_frame section with zero - // Call Frame Information records. Therefore add a CIE record length - // 0 as a terminator if this .eh_frame section is empty. - if (Off == 0) - Off = 4; + // Call Frame Information records. glibc unwind-dw2-fde.c + // classify_object_over_fdes expects there is a CIE record length 0 as a + // terminator. Thus we add one unconditionally. + Off += 4; this->Size = Off; } @@ -524,25 +502,47 @@ std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const { uint8_t *Buf = getParent()->Loc + OutSecOff; std::vector<FdeData> Ret; + uint64_t VA = InX::EhFrameHdr->getVA(); for (CieRecord *Rec : CieRecords) { uint8_t Enc = getFdeEncoding(Rec->Cie); for (EhSectionPiece *Fde : Rec->Fdes) { - uint32_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); - uint32_t FdeVA = getParent()->Addr + Fde->OutputOff; - Ret.push_back({Pc, FdeVA}); + uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); + uint64_t FdeVA = getParent()->Addr + Fde->OutputOff; + if (!isInt<32>(Pc - VA)) + fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" + + Twine::utohexstr(Pc - VA)); + Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)}); } } + + // Sort the FDE list by their PC and uniqueify. Usually there is only + // one FDE for a PC (i.e. function), but if ICF merges two functions + // into one, there can be more than one FDEs pointing to the address. + auto Less = [](const FdeData &A, const FdeData &B) { + return A.PcRel < B.PcRel; + }; + std::stable_sort(Ret.begin(), Ret.end(), Less); + auto Eq = [](const FdeData &A, const FdeData &B) { + return A.PcRel == B.PcRel; + }; + Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end()); + return Ret; } static uint64_t readFdeAddr(uint8_t *Buf, int Size) { switch (Size) { case DW_EH_PE_udata2: - return read16(Buf, Config->Endianness); + return read16(Buf); + case DW_EH_PE_sdata2: + return (int16_t)read16(Buf); case DW_EH_PE_udata4: - return read32(Buf, Config->Endianness); + return read32(Buf); + case DW_EH_PE_sdata4: + return (int32_t)read32(Buf); case DW_EH_PE_udata8: - return read64(Buf, Config->Endianness); + case DW_EH_PE_sdata8: + return read64(Buf); case DW_EH_PE_absptr: return readUint(Buf); } @@ -556,7 +556,7 @@ uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff, // The starting address to which this FDE applies is // stored at FDE + 8 byte. size_t Off = FdeOff + 8; - uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0x7); + uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf); if ((Enc & 0x70) == DW_EH_PE_absptr) return Addr; if ((Enc & 0x70) == DW_EH_PE_pcrel) @@ -589,7 +589,15 @@ void EhFrameSection::writeTo(uint8_t *Buf) { GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotEntrySize, ".got") {} + Target->GotEntrySize, ".got") { + // PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the + // .got. If there are no references to .TOC. in the symbol table, + // ElfSym::GlobalOffsetTable will not be defined and we won't need to save + // .TOC. in the .got. When it is defined, we increase NumEntries by the number + // of entries used to emit ElfSym::GlobalOffsetTable. + if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt) + NumEntries += Target->GotHeaderEntriesNum; +} void GotSection::addEntry(Symbol &Sym) { Sym.GotIndex = NumEntries; @@ -623,196 +631,383 @@ uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const { return B.GlobalDynIndex * Config->Wordsize; } -void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; } +void GotSection::finalizeContents() { + Size = NumEntries * Config->Wordsize; +} bool GotSection::empty() const { // We need to emit a GOT even if it's empty if there's a relocation that is // relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT - // (i.e. _GLOBAL_OFFSET_TABLE_). - return NumEntries == 0 && !HasGotOffRel && !ElfSym::GlobalOffsetTable; + // (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got. + return NumEntries == 0 && !HasGotOffRel && + !(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt); } void GotSection::writeTo(uint8_t *Buf) { // Buf points to the start of this section's buffer, // whereas InputSectionBase::relocateAlloc() expects its argument // to point to the start of the output section. + Target->writeGotHeader(Buf); relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size); } +static uint64_t getMipsPageAddr(uint64_t Addr) { + return (Addr + 0x8000) & ~0xffff; +} + +static uint64_t getMipsPageCount(uint64_t Size) { + return (Size + 0xfffe) / 0xffff + 1; +} + MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, ".got") {} -void MipsGotSection::addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr) { - // For "true" local symbols which can be referenced from the same module - // only compiler creates two instructions for address loading: - // - // lw $8, 0($gp) # R_MIPS_GOT16 - // addi $8, $8, 0 # R_MIPS_LO16 - // - // The first instruction loads high 16 bits of the symbol address while - // the second adds an offset. That allows to reduce number of required - // GOT entries because only one global offset table entry is necessary - // for every 64 KBytes of local data. So for local symbols we need to - // allocate number of GOT entries to hold all required "page" addresses. - // - // All global symbols (hidden and regular) considered by compiler uniformly. - // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation - // to load address of the symbol. So for each such symbol we need to - // allocate dedicated GOT entry to store its address. - // - // If a symbol is preemptible we need help of dynamic linker to get its - // final address. The corresponding GOT entries are allocated in the - // "global" part of GOT. Entries for non preemptible global symbol allocated - // in the "local" part of GOT. - // - // See "Global Offset Table" in Chapter 5: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf +void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend, + RelExpr Expr) { + FileGot &G = getGot(File); if (Expr == R_MIPS_GOT_LOCAL_PAGE) { - // At this point we do not know final symbol value so to reduce number - // of allocated GOT entries do the following trick. Save all output - // sections referenced by GOT relocations. Then later in the `finalize` - // method calculate number of "pages" required to cover all saved output - // section and allocate appropriate number of GOT entries. - PageIndexMap.insert({Sym.getOutputSection(), 0}); - return; - } - if (Sym.isTls()) { - // GOT entries created for MIPS TLS relocations behave like - // almost GOT entries from other ABIs. They go to the end - // of the global offset table. - Sym.GotIndex = TlsEntries.size(); - TlsEntries.push_back(&Sym); - return; - } - auto AddEntry = [&](Symbol &S, uint64_t A, GotEntries &Items) { - if (S.isInGot() && !A) - return; - size_t NewIndex = Items.size(); - if (!EntryIndexMap.insert({{&S, A}, NewIndex}).second) - return; - Items.emplace_back(&S, A); - if (!A) - S.GotIndex = NewIndex; - }; - if (Sym.IsPreemptible) { - // Ignore addends for preemptible symbols. They got single GOT entry anyway. - AddEntry(Sym, 0, GlobalEntries); - Sym.IsInGlobalMipsGot = true; - } else if (Expr == R_MIPS_GOT_OFF32) { - AddEntry(Sym, Addend, LocalEntries32); - Sym.Is32BitMipsGot = true; - } else { - // Hold local GOT entries accessed via a 16-bit index separately. - // That allows to write them in the beginning of the GOT and keep - // their indexes as less as possible to escape relocation's overflow. - AddEntry(Sym, Addend, LocalEntries); - } + if (const OutputSection *OS = Sym.getOutputSection()) + G.PagesMap.insert({OS, {}}); + else + G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0}); + } else if (Sym.isTls()) + G.Tls.insert({&Sym, 0}); + else if (Sym.IsPreemptible && Expr == R_ABS) + G.Relocs.insert({&Sym, 0}); + else if (Sym.IsPreemptible) + G.Global.insert({&Sym, 0}); + else if (Expr == R_MIPS_GOT_OFF32) + G.Local32.insert({{&Sym, Addend}, 0}); + else + G.Local16.insert({{&Sym, Addend}, 0}); } -bool MipsGotSection::addDynTlsEntry(Symbol &Sym) { - if (Sym.GlobalDynIndex != -1U) - return false; - Sym.GlobalDynIndex = TlsEntries.size(); - // Global Dynamic TLS entries take two GOT slots. - TlsEntries.push_back(nullptr); - TlsEntries.push_back(&Sym); - return true; +void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) { + getGot(File).DynTlsSymbols.insert({&Sym, 0}); } -// Reserves TLS entries for a TLS module ID and a TLS block offset. -// In total it takes two GOT slots. -bool MipsGotSection::addTlsIndex() { - if (TlsIndexOff != uint32_t(-1)) - return false; - TlsIndexOff = TlsEntries.size() * Config->Wordsize; - TlsEntries.push_back(nullptr); - TlsEntries.push_back(nullptr); - return true; +void MipsGotSection::addTlsIndex(InputFile &File) { + getGot(File).DynTlsSymbols.insert({nullptr, 0}); } -static uint64_t getMipsPageAddr(uint64_t Addr) { - return (Addr + 0x8000) & ~0xffff; +size_t MipsGotSection::FileGot::getEntriesNum() const { + return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() + + Tls.size() + DynTlsSymbols.size() * 2; } -static uint64_t getMipsPageCount(uint64_t Size) { - return (Size + 0xfffe) / 0xffff + 1; +size_t MipsGotSection::FileGot::getPageEntriesNum() const { + size_t Num = 0; + for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap) + Num += P.second.Count; + return Num; } -uint64_t MipsGotSection::getPageEntryOffset(const Symbol &B, - int64_t Addend) const { - const OutputSection *OutSec = B.getOutputSection(); - uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); - uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend)); - uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; - assert(Index < PageEntriesNum); - return (HeaderEntriesNum + Index) * Config->Wordsize; +size_t MipsGotSection::FileGot::getIndexedEntriesNum() const { + size_t Count = getPageEntriesNum() + Local16.size() + Global.size(); + // If there are relocation-only entries in the GOT, TLS entries + // are allocated after them. TLS entries should be addressable + // by 16-bit index so count both reloc-only and TLS entries. + if (!Tls.empty() || !DynTlsSymbols.empty()) + Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2; + return Count; } -uint64_t MipsGotSection::getSymEntryOffset(const Symbol &B, - int64_t Addend) const { - // Calculate offset of the GOT entries block: TLS, global, local. - uint64_t Index = HeaderEntriesNum + PageEntriesNum; - if (B.isTls()) - Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size(); - else if (B.IsInGlobalMipsGot) - Index += LocalEntries.size() + LocalEntries32.size(); - else if (B.Is32BitMipsGot) - Index += LocalEntries.size(); - // Calculate offset of the GOT entry in the block. - if (B.isInGot()) - Index += B.GotIndex; - else { - auto It = EntryIndexMap.find({&B, Addend}); - assert(It != EntryIndexMap.end()); - Index += It->second; +MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) { + if (!F.MipsGotIndex.hasValue()) { + Gots.emplace_back(); + Gots.back().File = &F; + F.MipsGotIndex = Gots.size() - 1; + } + return Gots[*F.MipsGotIndex]; +} + +uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F, + const Symbol &Sym, + int64_t Addend) const { + const FileGot &G = Gots[*F->MipsGotIndex]; + uint64_t Index = 0; + if (const OutputSection *OutSec = Sym.getOutputSection()) { + uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); + uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend)); + Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff; + } else { + Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))}); } return Index * Config->Wordsize; } -uint64_t MipsGotSection::getTlsOffset() const { - return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize; +uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S, + int64_t Addend) const { + const FileGot &G = Gots[*F->MipsGotIndex]; + Symbol *Sym = const_cast<Symbol *>(&S); + if (Sym->isTls()) + return G.Tls.lookup(Sym) * Config->Wordsize; + if (Sym->IsPreemptible) + return G.Global.lookup(Sym) * Config->Wordsize; + return G.Local16.lookup({Sym, Addend}) * Config->Wordsize; +} + +uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const { + const FileGot &G = Gots[*F->MipsGotIndex]; + return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize; } -uint64_t MipsGotSection::getGlobalDynOffset(const Symbol &B) const { - return B.GlobalDynIndex * Config->Wordsize; +uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F, + const Symbol &S) const { + const FileGot &G = Gots[*F->MipsGotIndex]; + Symbol *Sym = const_cast<Symbol *>(&S); + return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize; } const Symbol *MipsGotSection::getFirstGlobalEntry() const { - return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first; + if (Gots.empty()) + return nullptr; + const FileGot &PrimGot = Gots.front(); + if (!PrimGot.Global.empty()) + return PrimGot.Global.front().first; + if (!PrimGot.Relocs.empty()) + return PrimGot.Relocs.front().first; + return nullptr; } unsigned MipsGotSection::getLocalEntriesNum() const { - return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() + - LocalEntries32.size(); + if (Gots.empty()) + return HeaderEntriesNum; + return HeaderEntriesNum + Gots.front().getPageEntriesNum() + + Gots.front().Local16.size(); +} + +bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) { + FileGot Tmp = Dst; + set_union(Tmp.PagesMap, Src.PagesMap); + set_union(Tmp.Local16, Src.Local16); + set_union(Tmp.Global, Src.Global); + set_union(Tmp.Relocs, Src.Relocs); + set_union(Tmp.Tls, Src.Tls); + set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols); + + size_t Count = IsPrimary ? HeaderEntriesNum : 0; + Count += Tmp.getIndexedEntriesNum(); + + if (Count * Config->Wordsize > Config->MipsGotSize) + return false; + + std::swap(Tmp, Dst); + return true; } void MipsGotSection::finalizeContents() { updateAllocSize(); } bool MipsGotSection::updateAllocSize() { - PageEntriesNum = 0; - for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) { - // For each output section referenced by GOT page relocations calculate - // and save into PageIndexMap an upper bound of MIPS GOT entries required - // to store page addresses of local symbols. We assume the worst case - - // each 64kb page of the output section has at least one GOT relocation - // against it. And take in account the case when the section intersects - // page boundaries. - P.second = PageEntriesNum; - PageEntriesNum += getMipsPageCount(P.first->Size); - } - Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * - Config->Wordsize; + Size = HeaderEntriesNum * Config->Wordsize; + for (const FileGot &G : Gots) + Size += G.getEntriesNum() * Config->Wordsize; return false; } +template <class ELFT> void MipsGotSection::build() { + if (Gots.empty()) + return; + + std::vector<FileGot> MergedGots(1); + + // For each GOT move non-preemptible symbols from the `Global` + // to `Local16` list. Preemptible symbol might become non-preemptible + // one if, for example, it gets a related copy relocation. + for (FileGot &Got : Gots) { + for (auto &P: Got.Global) + if (!P.first->IsPreemptible) + Got.Local16.insert({{P.first, 0}, 0}); + Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) { + return !P.first->IsPreemptible; + }); + } + + // For each GOT remove "reloc-only" entry if there is "global" + // entry for the same symbol. And add local entries which indexed + // using 32-bit value at the end of 16-bit entries. + for (FileGot &Got : Gots) { + Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) { + return Got.Global.count(P.first); + }); + set_union(Got.Local16, Got.Local32); + Got.Local32.clear(); + } + + // Evaluate number of "reloc-only" entries in the resulting GOT. + // To do that put all unique "reloc-only" and "global" entries + // from all GOTs to the future primary GOT. + FileGot *PrimGot = &MergedGots.front(); + for (FileGot &Got : Gots) { + set_union(PrimGot->Relocs, Got.Global); + set_union(PrimGot->Relocs, Got.Relocs); + Got.Relocs.clear(); + } + + // Evaluate number of "page" entries in each GOT. + for (FileGot &Got : Gots) { + for (std::pair<const OutputSection *, FileGot::PageBlock> &P : + Got.PagesMap) { + const OutputSection *OS = P.first; + uint64_t SecSize = 0; + for (BaseCommand *Cmd : OS->SectionCommands) { + if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) + for (InputSection *IS : ISD->Sections) { + uint64_t Off = alignTo(SecSize, IS->Alignment); + SecSize = Off + IS->getSize(); + } + } + P.second.Count = getMipsPageCount(SecSize); + } + } + + // Merge GOTs. Try to join as much as possible GOTs but do not exceed + // maximum GOT size. At first, try to fill the primary GOT because + // the primary GOT can be accessed in the most effective way. If it + // is not possible, try to fill the last GOT in the list, and finally + // create a new GOT if both attempts failed. + for (FileGot &SrcGot : Gots) { + InputFile *File = SrcGot.File; + if (tryMergeGots(MergedGots.front(), SrcGot, true)) { + File->MipsGotIndex = 0; + } else { + // If this is the first time we failed to merge with the primary GOT, + // MergedGots.back() will also be the primary GOT. We must make sure not + // to try to merge again with IsPrimary=false, as otherwise, if the + // inputs are just right, we could allow the primary GOT to become 1 or 2 + // words too big due to ignoring the header size. + if (MergedGots.size() == 1 || + !tryMergeGots(MergedGots.back(), SrcGot, false)) { + MergedGots.emplace_back(); + std::swap(MergedGots.back(), SrcGot); + } + File->MipsGotIndex = MergedGots.size() - 1; + } + } + std::swap(Gots, MergedGots); + + // Reduce number of "reloc-only" entries in the primary GOT + // by substracting "global" entries exist in the primary GOT. + PrimGot = &Gots.front(); + PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) { + return PrimGot->Global.count(P.first); + }); + + // Calculate indexes for each GOT entry. + size_t Index = HeaderEntriesNum; + for (FileGot &Got : Gots) { + Got.StartIndex = &Got == PrimGot ? 0 : Index; + for (std::pair<const OutputSection *, FileGot::PageBlock> &P : + Got.PagesMap) { + // For each output section referenced by GOT page relocations calculate + // and save into PagesMap an upper bound of MIPS GOT entries required + // to store page addresses of local symbols. We assume the worst case - + // each 64kb page of the output section has at least one GOT relocation + // against it. And take in account the case when the section intersects + // page boundaries. + P.second.FirstIndex = Index; + Index += P.second.Count; + } + for (auto &P: Got.Local16) + P.second = Index++; + for (auto &P: Got.Global) + P.second = Index++; + for (auto &P: Got.Relocs) + P.second = Index++; + for (auto &P: Got.Tls) + P.second = Index++; + for (auto &P: Got.DynTlsSymbols) { + P.second = Index; + Index += 2; + } + } + + // Update Symbol::GotIndex field to use this + // value later in the `sortMipsSymbols` function. + for (auto &P : PrimGot->Global) + P.first->GotIndex = P.second; + for (auto &P : PrimGot->Relocs) + P.first->GotIndex = P.second; + + // Create dynamic relocations. + for (FileGot &Got : Gots) { + // Create dynamic relocations for TLS entries. + for (std::pair<Symbol *, size_t> &P : Got.Tls) { + Symbol *S = P.first; + uint64_t Offset = P.second * Config->Wordsize; + if (S->IsPreemptible) + InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S); + } + for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) { + Symbol *S = P.first; + uint64_t Offset = P.second * Config->Wordsize; + if (S == nullptr) { + if (!Config->Pic) + continue; + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + } else { + // When building a shared library we still need a dynamic relocation + // for the module index. Therefore only checking for + // S->IsPreemptible is not sufficient (this happens e.g. for + // thread-locals that have been marked as local through a linker script) + if (!S->IsPreemptible && !Config->Pic) + continue; + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + // However, we can skip writing the TLS offset reloc for non-preemptible + // symbols since it is known even in shared libraries + if (!S->IsPreemptible) + continue; + Offset += Config->Wordsize; + InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S); + } + } + + // Do not create dynamic relocations for non-TLS + // entries in the primary GOT. + if (&Got == PrimGot) + continue; + + // Dynamic relocations for "global" entries. + for (const std::pair<Symbol *, size_t> &P : Got.Global) { + uint64_t Offset = P.second * Config->Wordsize; + InX::RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first); + } + if (!Config->Pic) + continue; + // Dynamic relocations for "local" entries in case of PIC. + for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : + Got.PagesMap) { + size_t PageCount = L.second.Count; + for (size_t PI = 0; PI < PageCount; ++PI) { + uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize; + InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first, + int64_t(PI * 0x10000)}); + } + } + for (const std::pair<GotEntry, size_t> &P : Got.Local16) { + uint64_t Offset = P.second * Config->Wordsize; + InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, + P.first.first, P.first.second}); + } + } +} + bool MipsGotSection::empty() const { // We add the .got section to the result for dynamic MIPS target because // its address and properties are mentioned in the .dynamic section. return Config->Relocatable; } -uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); } +uint64_t MipsGotSection::getGp(const InputFile *F) const { + // For files without related GOT or files refer a primary GOT + // returns "common" _gp value. For secondary GOTs calculate + // individual _gp values. + if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0) + return ElfSym::MipsGp->getVA(0); + return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize + + 0x7ff0; +} void MipsGotSection::writeTo(uint8_t *Buf) { // Set the MSB of the second GOT slot. This is not required by any @@ -830,59 +1025,67 @@ void MipsGotSection::writeTo(uint8_t *Buf) { // keep doing this for now. We really need to revisit this to see // if we had to do this. writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1)); - Buf += HeaderEntriesNum * Config->Wordsize; - // Write 'page address' entries to the local part of the GOT. - for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) { - size_t PageCount = getMipsPageCount(L.first->Size); - uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); - for (size_t PI = 0; PI < PageCount; ++PI) { - uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize; - writeUint(Entry, FirstPageAddr + PI * 0x10000); - } - } - Buf += PageEntriesNum * Config->Wordsize; - auto AddEntry = [&](const GotEntry &SA) { - uint8_t *Entry = Buf; - Buf += Config->Wordsize; - const Symbol *Sym = SA.first; - uint64_t VA = Sym->getVA(SA.second); - if (Sym->StOther & STO_MIPS_MICROMIPS) - VA |= 1; - writeUint(Entry, VA); - }; - std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry); - std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry); - std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry); - // Initialize TLS-related GOT entries. If the entry has a corresponding - // dynamic relocations, leave it initialized by zero. Write down adjusted - // TLS symbol's values otherwise. To calculate the adjustments use offsets - // for thread-local storage. - // https://www.linux-mips.org/wiki/NPTL - if (TlsIndexOff != -1U && !Config->Pic) - writeUint(Buf + TlsIndexOff, 1); - for (const Symbol *B : TlsEntries) { - if (!B || B->IsPreemptible) - continue; - uint64_t VA = B->getVA(); - if (B->GotIndex != -1U) { - uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize; - writeUint(Entry, VA - 0x7000); + for (const FileGot &G : Gots) { + auto Write = [&](size_t I, const Symbol *S, int64_t A) { + uint64_t VA = A; + if (S) { + VA = S->getVA(A); + if (S->StOther & STO_MIPS_MICROMIPS) + VA |= 1; + } + writeUint(Buf + I * Config->Wordsize, VA); + }; + // Write 'page address' entries to the local part of the GOT. + for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : + G.PagesMap) { + size_t PageCount = L.second.Count; + uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); + for (size_t PI = 0; PI < PageCount; ++PI) + Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000); } - if (B->GlobalDynIndex != -1U) { - uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize; - writeUint(Entry, 1); - Entry += Config->Wordsize; - writeUint(Entry, VA - 0x8000); + // Local, global, TLS, reloc-only entries. + // If TLS entry has a corresponding dynamic relocations, leave it + // initialized by zero. Write down adjusted TLS symbol's values otherwise. + // To calculate the adjustments use offsets for thread-local storage. + // https://www.linux-mips.org/wiki/NPTL + for (const std::pair<GotEntry, size_t> &P : G.Local16) + Write(P.second, P.first.first, P.first.second); + // Write VA to the primary GOT only. For secondary GOTs that + // will be done by REL32 dynamic relocations. + if (&G == &Gots.front()) + for (const std::pair<const Symbol *, size_t> &P : G.Global) + Write(P.second, P.first, 0); + for (const std::pair<Symbol *, size_t> &P : G.Relocs) + Write(P.second, P.first, 0); + for (const std::pair<Symbol *, size_t> &P : G.Tls) + Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000); + for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) { + if (P.first == nullptr && !Config->Pic) + Write(P.second, nullptr, 1); + else if (P.first && !P.first->IsPreemptible) { + // If we are emitting PIC code with relocations we mustn't write + // anything to the GOT here. When using Elf_Rel relocations the value + // one will be treated as an addend and will cause crashes at runtime + if (!Config->Pic) + Write(P.second, nullptr, 1); + Write(P.second + 1, P.first, -0x8000); + } } } } +// On PowerPC the .plt section is used to hold the table of function addresses +// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss +// section. I don't know why we have a BSS style type for the section but it is +// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI. GotPltSection::GotPltSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotPltEntrySize, ".got.plt") {} + : SyntheticSection(SHF_ALLOC | SHF_WRITE, + Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, + Target->GotPltEntrySize, + Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {} void GotPltSection::addEntry(Symbol &Sym) { - Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); + assert(Sym.PltIndex == Entries.size()); Entries.push_back(&Sym); } @@ -900,16 +1103,37 @@ void GotPltSection::writeTo(uint8_t *Buf) { } } -// On ARM the IgotPltSection is part of the GotSection, on other Targets it is -// part of the .got.plt +bool GotPltSection::empty() const { + // We need to emit a GOT.PLT even if it's empty if there's a symbol that + // references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol + // relative to the .got.plt section. + return Entries.empty() && + !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt); +} + +static StringRef getIgotPltName() { + // On ARM the IgotPltSection is part of the GotSection. + if (Config->EMachine == EM_ARM) + return ".got"; + + // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection + // needs to be named the same. + if (Config->EMachine == EM_PPC64) + return ".plt"; + + return ".got.plt"; +} + +// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit +// with the IgotPltSection. IgotPltSection::IgotPltSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotPltEntrySize, - Config->EMachine == EM_ARM ? ".got" : ".got.plt") {} + : SyntheticSection(SHF_ALLOC | SHF_WRITE, + Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, + Target->GotPltEntrySize, getIgotPltName()) {} void IgotPltSection::addEntry(Symbol &Sym) { Sym.IsInIgot = true; - Sym.GotPltIndex = Entries.size(); + assert(Sym.PltIndex == Entries.size()); Entries.push_back(&Sym); } @@ -1005,8 +1229,14 @@ void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) { template <class ELFT> void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) { + Entries.push_back({Tag, [=] { return Sec->getVA(0); }}); +} + +template <class ELFT> +void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) { + size_t TagOffset = Entries.size() * Entsize; Entries.push_back( - {Tag, [=] { return Sec->getParent()->Addr + Sec->OutSecOff; }}); + {Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }}); } template <class ELFT> @@ -1036,6 +1266,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { DtFlags |= DF_SYMBOLIC; if (Config->ZInitfirst) DtFlags1 |= DF_1_INITFIRST; + if (Config->ZInterpose) + DtFlags1 |= DF_1_INTERPOSE; if (Config->ZNodelete) DtFlags1 |= DF_1_NODELETE; if (Config->ZNodlopen) @@ -1048,6 +1280,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { DtFlags |= DF_ORIGIN; DtFlags1 |= DF_1_ORIGIN; } + if (!Config->ZText) + DtFlags |= DF_TEXTREL; if (DtFlags) addInt(DT_FLAGS, DtFlags); @@ -1083,6 +1317,14 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); } } + if (InX::RelrDyn && !InX::RelrDyn->Relocs.empty()) { + addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, + InX::RelrDyn); + addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, + InX::RelrDyn->getParent()); + addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, + sizeof(Elf_Relr)); + } // .rel[a].plt section usually consists of two parts, containing plt and // iplt relocations. It is possible to have only iplt relocations in the // output. In that case RelaPlt is empty and have zero offset, the same offset @@ -1162,8 +1404,23 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { else addInt(DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols()); addInSec(DT_PLTGOT, InX::MipsGot); - if (InX::MipsRldMap) - addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap); + if (InX::MipsRldMap) { + if (!Config->Pie) + addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap); + // Store the offset to the .rld_map section + // relative to the address of the tag. + addInSecRelative(DT_MIPS_RLD_MAP_REL, InX::MipsRldMap); + } + } + + // Glink dynamic tag is required by the V2 abi if the plt section isn't empty. + if (Config->EMachine == EM_PPC64 && !InX::Plt->empty()) { + // The Glink tag points to 32 bytes before the first lazy symbol resolution + // stub, which starts directly after the header. + Entries.push_back({DT_PPC64_GLINK, [=] { + unsigned Offset = Target->PltHeaderSize - 32; + return InX::Plt->getVA(0) + Offset; + }}); } addInt(DT_NULL, 0); @@ -1183,13 +1440,16 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { } uint64_t DynamicReloc::getOffset() const { - return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec); + return InputSec->getVA(OffsetInSec); } -int64_t DynamicReloc::getAddend() const { +int64_t DynamicReloc::computeAddend() const { if (UseSymVA) return Sym->getVA(Addend); - return Addend; + if (!OutputSec) + return Addend; + // See the comment in the DynamicReloc ctor. + return getMipsPageAddr(OutputSec->Addr) + Addend; } uint32_t DynamicReloc::getSymIndex() const { @@ -1204,6 +1464,23 @@ RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type, : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name), DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {} +void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS, + uint64_t OffsetInSec, Symbol *Sym) { + addReloc({DynType, IS, OffsetInSec, false, Sym, 0}); +} + +void RelocationBaseSection::addReloc(RelType DynType, + InputSectionBase *InputSec, + uint64_t OffsetInSec, Symbol *Sym, + int64_t Addend, RelExpr Expr, + RelType Type) { + // Write the addends to the relocated address if required. We skip + // it if the written value would be zero. + if (Config->WriteAddends && (Expr != R_ADDEND || Addend != 0)) + InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); + addReloc({DynType, InputSec, OffsetInSec, Expr != R_ADDEND, Sym, Addend}); +} + void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) { if (Reloc.Type == Target->RelativeRel) ++NumRelativeRelocs; @@ -1220,23 +1497,17 @@ void RelocationBaseSection::finalizeContents() { getParent()->Link = Link; } +RelrBaseSection::RelrBaseSection() + : SyntheticSection(SHF_ALLOC, + Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, + Config->Wordsize, ".relr.dyn") {} + template <class ELFT> static void encodeDynamicReloc(typename ELFT::Rela *P, const DynamicReloc &Rel) { if (Config->IsRela) - P->r_addend = Rel.getAddend(); + P->r_addend = Rel.computeAddend(); P->r_offset = Rel.getOffset(); - if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot) - // The MIPS GOT section contains dynamic relocations that correspond to TLS - // entries. These entries are placed after the global and local sections of - // the GOT. At the point when we create these relocations, the size of the - // global and local sections is unknown, so the offset that we store in the - // TLS entry's DynamicReloc is relative to the start of the TLS section of - // the GOT, rather than being relative to the start of the GOT. This line of - // code adds the size of the global and local sections to the virtual - // address computed by getOffset() in order to adjust it into the TLS - // section. - P->r_offset += InX::MipsGot->getTlsOffset(); P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); } @@ -1249,32 +1520,22 @@ RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } -template <class ELFT, class RelTy> -static bool compRelocations(const RelTy &A, const RelTy &B) { - bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel; - bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel; +static bool compRelocations(const DynamicReloc &A, const DynamicReloc &B) { + bool AIsRel = A.Type == Target->RelativeRel; + bool BIsRel = B.Type == Target->RelativeRel; if (AIsRel != BIsRel) return AIsRel; - - return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL); + return A.getSymIndex() < B.getSymIndex(); } template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { - uint8_t *BufBegin = Buf; + if (Sort) + std::stable_sort(Relocs.begin(), Relocs.end(), compRelocations); + for (const DynamicReloc &Rel : Relocs) { encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel); Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } - - if (Sort) { - if (Config->IsRela) - std::stable_sort((Elf_Rela *)BufBegin, - (Elf_Rela *)BufBegin + Relocs.size(), - compRelocations<ELFT, Elf_Rela>); - else - std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(), - compRelocations<ELFT, Elf_Rel>); - } } template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() { @@ -1362,10 +1623,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { NonRelatives.push_back(R); } - std::sort(Relatives.begin(), Relatives.end(), - [](const Elf_Rel &A, const Elf_Rel &B) { - return A.r_offset < B.r_offset; - }); + llvm::sort(Relatives.begin(), Relatives.end(), + [](const Elf_Rel &A, const Elf_Rel &B) { + return A.r_offset < B.r_offset; + }); // Try to find groups of relative relocations which are spaced one word // apart from one another. These generally correspond to vtable entries. The @@ -1443,10 +1704,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { } // Finally the non-relative relocations. - std::sort(NonRelatives.begin(), NonRelatives.end(), - [](const Elf_Rela &A, const Elf_Rela &B) { - return A.r_offset < B.r_offset; - }); + llvm::sort(NonRelatives.begin(), NonRelatives.end(), + [](const Elf_Rela &A, const Elf_Rela &B) { + return A.r_offset < B.r_offset; + }); if (!NonRelatives.empty()) { Add(NonRelatives.size()); Add(HasAddendIfRela); @@ -1469,6 +1730,97 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { return RelocData.size() != OldSize; } +template <class ELFT> RelrSection<ELFT>::RelrSection() { + this->Entsize = Config->Wordsize; +} + +template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() { + // This function computes the contents of an SHT_RELR packed relocation + // section. + // + // Proposal for adding SHT_RELR sections to generic-abi is here: + // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg + // + // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks + // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ] + // + // i.e. start with an address, followed by any number of bitmaps. The address + // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63 + // relocations each, at subsequent offsets following the last address entry. + // + // The bitmap entries must have 1 in the least significant bit. The assumption + // here is that an address cannot have 1 in lsb. Odd addresses are not + // supported. + // + // Excluding the least significant bit in the bitmap, each non-zero bit in + // the bitmap represents a relocation to be applied to a corresponding machine + // word that follows the base address word. The second least significant bit + // represents the machine word immediately following the initial address, and + // each bit that follows represents the next word, in linear order. As such, + // a single bitmap can encode up to 31 relocations in a 32-bit object, and + // 63 relocations in a 64-bit object. + // + // This encoding has a couple of interesting properties: + // 1. Looking at any entry, it is clear whether it's an address or a bitmap: + // even means address, odd means bitmap. + // 2. Just a simple list of addresses is a valid encoding. + + size_t OldSize = RelrRelocs.size(); + RelrRelocs.clear(); + + // Same as Config->Wordsize but faster because this is a compile-time + // constant. + const size_t Wordsize = sizeof(typename ELFT::uint); + + // Number of bits to use for the relocation offsets bitmap. + // Must be either 63 or 31. + const size_t NBits = Wordsize * 8 - 1; + + // Get offsets for all relative relocations and sort them. + std::vector<uint64_t> Offsets; + for (const RelativeReloc &Rel : Relocs) + Offsets.push_back(Rel.getOffset()); + llvm::sort(Offsets.begin(), Offsets.end()); + + // For each leading relocation, find following ones that can be folded + // as a bitmap and fold them. + for (size_t I = 0, E = Offsets.size(); I < E;) { + // Add a leading relocation. + RelrRelocs.push_back(Elf_Relr(Offsets[I])); + uint64_t Base = Offsets[I] + Wordsize; + ++I; + + // Find foldable relocations to construct bitmaps. + while (I < E) { + uint64_t Bitmap = 0; + + while (I < E) { + uint64_t Delta = Offsets[I] - Base; + + // If it is too far, it cannot be folded. + if (Delta >= NBits * Wordsize) + break; + + // If it is not a multiple of wordsize away, it cannot be folded. + if (Delta % Wordsize) + break; + + // Fold it. + Bitmap |= 1ULL << (Delta / Wordsize); + ++I; + } + + if (!Bitmap) + break; + + RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1)); + Base += NBits * Wordsize; + } + } + + return RelrRelocs.size() != OldSize; +} + SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, @@ -1484,50 +1836,70 @@ SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) static bool sortMipsSymbols(const SymbolTableEntry &L, const SymbolTableEntry &R) { // Sort entries related to non-local preemptible symbols by GOT indexes. - // All other entries go to the first part of GOT in arbitrary order. - bool LIsInLocalGot = !L.Sym->IsInGlobalMipsGot; - bool RIsInLocalGot = !R.Sym->IsInGlobalMipsGot; - if (LIsInLocalGot || RIsInLocalGot) - return !RIsInLocalGot; - return L.Sym->GotIndex < R.Sym->GotIndex; + // All other entries go to the beginning of a dynsym in arbitrary order. + if (L.Sym->isInGot() && R.Sym->isInGot()) + return L.Sym->GotIndex < R.Sym->GotIndex; + if (!L.Sym->isInGot() && !R.Sym->isInGot()) + return false; + return !L.Sym->isInGot(); } void SymbolTableBaseSection::finalizeContents() { getParent()->Link = StrTabSec.getParent()->SectionIndex; + if (this->Type != SHT_DYNSYM) + return; + // If it is a .dynsym, there should be no local symbols, but we need // to do a few things for the dynamic linker. - if (this->Type == SHT_DYNSYM) { - // Section's Info field has the index of the first non-local symbol. - // Because the first symbol entry is a null entry, 1 is the first. - getParent()->Info = 1; - - if (InX::GnuHashTab) { - // NB: It also sorts Symbols to meet the GNU hash table requirements. - InX::GnuHashTab->addSymbols(Symbols); - } else if (Config->EMachine == EM_MIPS) { - std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); - } - size_t I = 0; - for (const SymbolTableEntry &S : Symbols) S.Sym->DynsymIndex = ++I; - return; + // Section's Info field has the index of the first non-local symbol. + // Because the first symbol entry is a null entry, 1 is the first. + getParent()->Info = 1; + + if (InX::GnuHashTab) { + // NB: It also sorts Symbols to meet the GNU hash table requirements. + InX::GnuHashTab->addSymbols(Symbols); + } else if (Config->EMachine == EM_MIPS) { + std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); } + + size_t I = 0; + for (const SymbolTableEntry &S : Symbols) + S.Sym->DynsymIndex = ++I; } // The ELF spec requires that all local symbols precede global symbols, so we // sort symbol entries in this function. (For .dynsym, we don't do that because // symbols for dynamic linking are inherently all globals.) +// +// Aside from above, we put local symbols in groups starting with the STT_FILE +// symbol. That is convenient for purpose of identifying where are local symbols +// coming from. void SymbolTableBaseSection::postThunkContents() { - if (this->Type == SHT_DYNSYM) - return; - // move all local symbols before global symbols. - auto It = std::stable_partition( + assert(this->Type == SHT_SYMTAB); + + // Move all local symbols before global symbols. + auto E = std::stable_partition( Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) { return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL; }); - size_t NumLocals = It - Symbols.begin(); + size_t NumLocals = E - Symbols.begin(); getParent()->Info = NumLocals + 1; + + // We want to group the local symbols by file. For that we rebuild the local + // part of the symbols vector. We do not need to care about the STT_FILE + // symbols, they are already naturally placed first in each group. That + // happens because STT_FILE is always the first symbol in the object and hence + // precede all other local symbols we add for a file. + MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr; + for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E)) + Arr[S.Sym->File].push_back(S); + + auto I = Symbols.begin(); + for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr) + for (SymbolTableEntry &Entry : P.second) + *I++ = Entry; } void SymbolTableBaseSection::addSymbol(Symbol *B) { @@ -1565,6 +1937,23 @@ SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec) this->Entsize = sizeof(Elf_Sym); } +static BssSection *getCommonSec(Symbol *Sym) { + if (!Config->DefineCommon) + if (auto *D = dyn_cast<Defined>(Sym)) + return dyn_cast_or_null<BssSection>(D->Section); + return nullptr; +} + +static uint32_t getSymSectionIndex(Symbol *Sym) { + if (getCommonSec(Sym)) + return SHN_COMMON; + if (!isa<Defined>(Sym) || Sym->NeedsPltAddr) + return SHN_UNDEF; + if (const OutputSection *OS = Sym->getOutputSection()) + return OS->SectionIndex >= SHN_LORESERVE ? SHN_XINDEX : OS->SectionIndex; + return SHN_ABS; +} + // Write the internal symbol table contents to the output symbol table. template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { // The first entry is a null entry as per the ELF spec. @@ -1586,20 +1975,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { } ESym->st_name = Ent.StrTabOffset; - - // Set a section index. - BssSection *CommonSec = nullptr; - if (!Config->DefineCommon) - if (auto *D = dyn_cast<Defined>(Sym)) - CommonSec = dyn_cast_or_null<BssSection>(D->Section); - if (CommonSec) - ESym->st_shndx = SHN_COMMON; - else if (const OutputSection *OutSec = Sym->getOutputSection()) - ESym->st_shndx = OutSec->SectionIndex; - else if (isa<Defined>(Sym)) - ESym->st_shndx = SHN_ABS; - else - ESym->st_shndx = SHN_UNDEF; + ESym->st_shndx = getSymSectionIndex(Ent.Sym); // Copy symbol size if it is a defined symbol. st_size is not significant // for undefined symbols, so whether copying it or not is up to us if that's @@ -1614,7 +1990,7 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { // st_value is usually an address of a symbol, but that has a // special meaining for uninstantiated common symbols (this can // occur if -r is given). - if (CommonSec) + if (BssSection *CommonSec = getCommonSec(Ent.Sym)) ESym->st_value = CommonSec->Alignment; else ESym->st_value = Sym->getVA(); @@ -1635,9 +2011,11 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { ESym->st_other |= STO_MIPS_PLT; if (isMicroMips()) { // Set STO_MIPS_MICROMIPS flag and less-significant bit for - // defined microMIPS symbols and shared symbols with PLT record. - if ((Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) || - (Sym->isShared() && Sym->NeedsPltAddr)) { + // a defined microMIPS symbol and symbol should point to its + // PLT entry (in case of microMIPS, PLT entries always contain + // microMIPS code). + if (Sym->isDefined() && + ((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) { if (StrTabSec.isDynamic()) ESym->st_value |= 1; ESym->st_other |= STO_MIPS_MICROMIPS; @@ -1652,6 +2030,44 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { } } +SymtabShndxSection::SymtabShndxSection() + : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndxr") { + this->Entsize = 4; +} + +void SymtabShndxSection::writeTo(uint8_t *Buf) { + // We write an array of 32 bit values, where each value has 1:1 association + // with an entry in .symtab. If the corresponding entry contains SHN_XINDEX, + // we need to write actual index, otherwise, we must write SHN_UNDEF(0). + Buf += 4; // Ignore .symtab[0] entry. + for (const SymbolTableEntry &Entry : InX::SymTab->getSymbols()) { + if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX) + write32(Buf, Entry.Sym->getOutputSection()->SectionIndex); + Buf += 4; + } +} + +bool SymtabShndxSection::empty() const { + // SHT_SYMTAB can hold symbols with section indices values up to + // SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX + // section. Problem is that we reveal the final section indices a bit too + // late, and we do not know them here. For simplicity, we just always create + // a .symtab_shndxr section when the amount of output sections is huge. + size_t Size = 0; + for (BaseCommand *Base : Script->SectionCommands) + if (isa<OutputSection>(Base)) + ++Size; + return Size < SHN_LORESERVE; +} + +void SymtabShndxSection::finalizeContents() { + getParent()->Link = InX::SymTab->getParent()->SectionIndex; +} + +size_t SymtabShndxSection::getSize() const { + return InX::SymTab->getNumSymbols() * 4; +} + // .hash and .gnu.hash sections contain on-disk hash tables that map // symbol names to their dynamic symbol table indices. Their purpose // is to help the dynamic linker resolve symbols quickly. If ELF files @@ -1690,12 +2106,14 @@ GnuHashTableSection::GnuHashTableSection() void GnuHashTableSection::finalizeContents() { getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; - // Computes bloom filter size in word size. We want to allocate 8 + // Computes bloom filter size in word size. We want to allocate 12 // bits for each symbol. It must be a power of two. - if (Symbols.empty()) + if (Symbols.empty()) { MaskWords = 1; - else - MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize); + } else { + uint64_t NumBits = Symbols.size() * 12; + MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8)); + } Size = 16; // Header Size += Config->Wordsize * MaskWords; // Bloom filter @@ -1713,7 +2131,7 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) { write32(Buf, NBuckets); write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size()); write32(Buf + 8, MaskWords); - write32(Buf + 12, getShift2()); + write32(Buf + 12, Shift2); Buf += 16; // Write a bloom filter and a hash table. @@ -1730,12 +2148,12 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) { // [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2), // p.9, https://www.akkadia.org/drepper/dsohowto.pdf void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) { - const unsigned C = Config->Wordsize * 8; + unsigned C = Config->Is64 ? 64 : 32; for (const Entry &Sym : Symbols) { size_t I = (Sym.Hash / C) & (MaskWords - 1); uint64_t Val = readUint(Buf + I * Config->Wordsize); Val |= uint64_t(1) << (Sym.Hash % C); - Val |= uint64_t(1) << ((Sym.Hash >> getShift2()) % C); + Val |= uint64_t(1) << ((Sym.Hash >> Shift2) % C); writeUint(Buf + I * Config->Wordsize, Val); } } @@ -1777,21 +2195,23 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) { // its type correctly. std::vector<SymbolTableEntry>::iterator Mid = std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { - // Shared symbols that this executable preempts are special. The dynamic - // linker has to look them up, so they have to be in the hash table. - if (auto *SS = dyn_cast<SharedSymbol>(S.Sym)) - return SS->CopyRelSec == nullptr && !SS->NeedsPltAddr; return !S.Sym->isDefined(); }); - if (Mid == V.end()) - return; // We chose load factor 4 for the on-disk hash table. For each hash // collision, the dynamic linker will compare a uint32_t hash value. - // Since the integer comparison is quite fast, we believe we can make - // the load factor even larger. 4 is just a conservative choice. + // Since the integer comparison is quite fast, we believe we can + // make the load factor even larger. 4 is just a conservative choice. + // + // Note that we don't want to create a zero-sized hash table because + // Android loader as of 2018 doesn't like a .gnu.hash containing such + // table. If that's the case, we create a hash table with one unused + // dummy slot. NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1); + if (Mid == V.end()) + return; + for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) { Symbol *B = Ent.Sym; uint32_t Hash = hashGnu(B->getName()); @@ -1847,9 +2267,12 @@ void HashTableSection::writeTo(uint8_t *Buf) { } } -PltSection::PltSection(size_t S) - : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"), - HeaderSize(S) { +// On PowerPC64 the lazy symbol resolvers go into the `global linkage table` +// in the .glink section, rather then the typical .plt section. +PltSection::PltSection(bool IsIplt) + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, + Config->EMachine == EM_PPC64 ? ".glink" : ".plt"), + HeaderSize(IsIplt ? 0 : Target->PltHeaderSize), IsIplt(IsIplt) { // The PLT needs to be writable on SPARC as the dynamic linker will // modify the instructions in the PLT entries. if (Config->EMachine == EM_SPARCV9) @@ -1859,7 +2282,7 @@ PltSection::PltSection(size_t S) void PltSection::writeTo(uint8_t *Buf) { // At beginning of PLT but not the IPLT, we have code to call the dynamic // linker to resolve dynsyms at runtime. Write such code. - if (HeaderSize != 0) + if (!IsIplt) Target->writePltHeader(Buf); size_t Off = HeaderSize; // The IPlt is immediately after the Plt, account for this in RelOff @@ -1878,7 +2301,7 @@ void PltSection::writeTo(uint8_t *Buf) { template <class ELFT> void PltSection::addEntry(Symbol &Sym) { Sym.PltIndex = Entries.size(); RelocationBaseSection *PltRelocSection = InX::RelaPlt; - if (HeaderSize == 0) { + if (IsIplt) { PltRelocSection = InX::RelaIplt; Sym.IsInIplt = true; } @@ -1895,7 +2318,7 @@ size_t PltSection::getSize() const { // example ARM uses mapping symbols to aid disassembly void PltSection::addSymbols() { // The PLT may have symbols defined for the Header, the IPLT has no header - if (HeaderSize != 0) + if (!IsIplt) Target->addPltHeaderSymbols(*this); size_t Off = HeaderSize; for (size_t I = 0; I < Entries.size(); ++I) { @@ -1905,7 +2328,7 @@ void PltSection::addSymbols() { } unsigned PltSection::getPltRelocOff() const { - return (HeaderSize == 0) ? InX::Plt->getSize() : 0; + return IsIplt ? InX::Plt->getSize() : 0; } // The string hash function for .gdb_index. @@ -1916,16 +2339,48 @@ static uint32_t computeGdbHash(StringRef S) { return H; } -static std::vector<GdbIndexChunk::CuEntry> readCuList(DWARFContext &Dwarf) { - std::vector<GdbIndexChunk::CuEntry> Ret; +GdbIndexSection::GdbIndexSection() + : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {} + +// Returns the desired size of an on-disk hash table for a .gdb_index section. +// There's a tradeoff between size and collision rate. We aim 75% utilization. +size_t GdbIndexSection::computeSymtabSize() const { + return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024); +} + +// Compute the output section size. +void GdbIndexSection::initOutputSize() { + Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8; + + for (GdbChunk &Chunk : Chunks) + Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20; + + // Add the constant pool size if exists. + if (!Symbols.empty()) { + GdbSymbol &Sym = Symbols.back(); + Size += Sym.NameOff + Sym.Name.size() + 1; + } +} + +static std::vector<InputSection *> getDebugInfoSections() { + std::vector<InputSection *> Ret; + for (InputSectionBase *S : InputSections) + if (InputSection *IS = dyn_cast<InputSection>(S)) + if (IS->Name == ".debug_info") + Ret.push_back(IS); + return Ret; +} + +static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) { + std::vector<GdbIndexSection::CuEntry> Ret; for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) Ret.push_back({Cu->getOffset(), Cu->getLength() + 4}); return Ret; } -static std::vector<GdbIndexChunk::AddressEntry> +static std::vector<GdbIndexSection::AddressEntry> readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) { - std::vector<GdbIndexChunk::AddressEntry> Ret; + std::vector<GdbIndexSection::AddressEntry> Ret; uint32_t CuIdx = 0; for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) { @@ -1949,218 +2404,192 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) { return Ret; } -static std::vector<GdbIndexChunk::NameTypeEntry> -readPubNamesAndTypes(DWARFContext &Dwarf) { +static std::vector<GdbIndexSection::NameTypeEntry> +readPubNamesAndTypes(DWARFContext &Dwarf, uint32_t Idx) { StringRef Sec1 = Dwarf.getDWARFObj().getGnuPubNamesSection(); StringRef Sec2 = Dwarf.getDWARFObj().getGnuPubTypesSection(); - std::vector<GdbIndexChunk::NameTypeEntry> Ret; + std::vector<GdbIndexSection::NameTypeEntry> Ret; for (StringRef Sec : {Sec1, Sec2}) { DWARFDebugPubTable Table(Sec, Config->IsLE, true); - for (const DWARFDebugPubTable::Set &Set : Table.getData()) { - for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) { - CachedHashStringRef S(Ent.Name, computeGdbHash(Ent.Name)); - Ret.push_back({S, Ent.Descriptor.toBits()}); - } - } + for (const DWARFDebugPubTable::Set &Set : Table.getData()) + for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) + Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)}, + (Ent.Descriptor.toBits() << 24) | Idx}); } return Ret; } -static std::vector<InputSection *> getDebugInfoSections() { - std::vector<InputSection *> Ret; - for (InputSectionBase *S : InputSections) - if (InputSection *IS = dyn_cast<InputSection>(S)) - if (IS->Name == ".debug_info") - Ret.push_back(IS); - return Ret; -} +// Create a list of symbols from a given list of symbol names and types +// by uniquifying them by name. +static std::vector<GdbIndexSection::GdbSymbol> +createSymbols(ArrayRef<std::vector<GdbIndexSection::NameTypeEntry>> NameTypes) { + typedef GdbIndexSection::GdbSymbol GdbSymbol; + typedef GdbIndexSection::NameTypeEntry NameTypeEntry; -void GdbIndexSection::fixCuIndex() { - uint32_t Idx = 0; - for (GdbIndexChunk &Chunk : Chunks) { - for (GdbIndexChunk::AddressEntry &Ent : Chunk.AddressAreas) - Ent.CuIndex += Idx; - Idx += Chunk.CompilationUnits.size(); - } -} + // The number of symbols we will handle in this function is of the order + // of millions for very large executables, so we use multi-threading to + // speed it up. + size_t NumShards = 32; + size_t Concurrency = 1; + if (ThreadsEnabled) + Concurrency = + std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards); -std::vector<std::vector<uint32_t>> GdbIndexSection::createCuVectors() { - std::vector<std::vector<uint32_t>> Ret; - uint32_t Idx = 0; - uint32_t Off = 0; + // A sharded map to uniquify symbols by name. + std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards); + size_t Shift = 32 - countTrailingZeros(NumShards); - for (GdbIndexChunk &Chunk : Chunks) { - for (GdbIndexChunk::NameTypeEntry &Ent : Chunk.NamesAndTypes) { - GdbSymbol *&Sym = Symbols[Ent.Name]; - if (!Sym) { - Sym = make<GdbSymbol>(GdbSymbol{Ent.Name.hash(), Off, Ret.size()}); - Off += Ent.Name.size() + 1; - Ret.push_back({}); - } + // Instantiate GdbSymbols while uniqufying them by name. + std::vector<std::vector<GdbSymbol>> Symbols(NumShards); + parallelForEachN(0, Concurrency, [&](size_t ThreadId) { + for (ArrayRef<NameTypeEntry> Entries : NameTypes) { + for (const NameTypeEntry &Ent : Entries) { + size_t ShardId = Ent.Name.hash() >> Shift; + if ((ShardId & (Concurrency - 1)) != ThreadId) + continue; + + size_t &Idx = Map[ShardId][Ent.Name]; + if (Idx) { + Symbols[ShardId][Idx - 1].CuVector.push_back(Ent.Type); + continue; + } - // gcc 5.4.1 produces a buggy .debug_gnu_pubnames that contains - // duplicate entries, so we want to dedup them. - std::vector<uint32_t> &Vec = Ret[Sym->CuVectorIndex]; - uint32_t Val = (Ent.Type << 24) | Idx; - if (Vec.empty() || Vec.back() != Val) - Vec.push_back(Val); + Idx = Symbols[ShardId].size() + 1; + Symbols[ShardId].push_back({Ent.Name, {Ent.Type}, 0, 0}); + } } - Idx += Chunk.CompilationUnits.size(); + }); + + size_t NumSymbols = 0; + for (ArrayRef<GdbSymbol> V : Symbols) + NumSymbols += V.size(); + + // The return type is a flattened vector, so we'll copy each vector + // contents to Ret. + std::vector<GdbSymbol> Ret; + Ret.reserve(NumSymbols); + for (std::vector<GdbSymbol> &Vec : Symbols) + for (GdbSymbol &Sym : Vec) + Ret.push_back(std::move(Sym)); + + // CU vectors and symbol names are adjacent in the output file. + // We can compute their offsets in the output file now. + size_t Off = 0; + for (GdbSymbol &Sym : Ret) { + Sym.CuVectorOff = Off; + Off += (Sym.CuVector.size() + 1) * 4; + } + for (GdbSymbol &Sym : Ret) { + Sym.NameOff = Off; + Off += Sym.Name.size() + 1; } - StringPoolSize = Off; return Ret; } -template <class ELFT> GdbIndexSection *elf::createGdbIndex() { - // Gather debug info to create a .gdb_index section. +// Returns a newly-created .gdb_index section. +template <class ELFT> GdbIndexSection *GdbIndexSection::create() { std::vector<InputSection *> Sections = getDebugInfoSections(); - std::vector<GdbIndexChunk> Chunks(Sections.size()); - - parallelForEachN(0, Chunks.size(), [&](size_t I) { - ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>(); - DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File)); - - Chunks[I].DebugInfoSec = Sections[I]; - Chunks[I].CompilationUnits = readCuList(Dwarf); - Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]); - Chunks[I].NamesAndTypes = readPubNamesAndTypes(Dwarf); - }); // .debug_gnu_pub{names,types} are useless in executables. // They are present in input object files solely for creating - // a .gdb_index. So we can remove it from the output. + // a .gdb_index. So we can remove them from the output. for (InputSectionBase *S : InputSections) if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes") S->Live = false; - // Create a .gdb_index and returns it. - return make<GdbIndexSection>(std::move(Chunks)); -} + std::vector<GdbChunk> Chunks(Sections.size()); + std::vector<std::vector<NameTypeEntry>> NameTypes(Sections.size()); -static size_t getCuSize(ArrayRef<GdbIndexChunk> Arr) { - size_t Ret = 0; - for (const GdbIndexChunk &D : Arr) - Ret += D.CompilationUnits.size(); - return Ret; -} - -static size_t getAddressAreaSize(ArrayRef<GdbIndexChunk> Arr) { - size_t Ret = 0; - for (const GdbIndexChunk &D : Arr) - Ret += D.AddressAreas.size(); - return Ret; -} - -std::vector<GdbSymbol *> GdbIndexSection::createGdbSymtab() { - uint32_t Size = NextPowerOf2(Symbols.size() * 4 / 3); - if (Size < 1024) - Size = 1024; - - uint32_t Mask = Size - 1; - std::vector<GdbSymbol *> Ret(Size); + parallelForEachN(0, Sections.size(), [&](size_t I) { + ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>(); + DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File)); - for (auto &KV : Symbols) { - GdbSymbol *Sym = KV.second; - uint32_t I = Sym->NameHash & Mask; - uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1; + Chunks[I].Sec = Sections[I]; + Chunks[I].CompilationUnits = readCuList(Dwarf); + Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]); + NameTypes[I] = readPubNamesAndTypes(Dwarf, I); + }); - while (Ret[I]) - I = (I + Step) & Mask; - Ret[I] = Sym; - } + auto *Ret = make<GdbIndexSection>(); + Ret->Chunks = std::move(Chunks); + Ret->Symbols = createSymbols(NameTypes); + Ret->initOutputSize(); return Ret; } -GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&C) - : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), Chunks(std::move(C)) { - fixCuIndex(); - CuVectors = createCuVectors(); - GdbSymtab = createGdbSymtab(); - - // Compute offsets early to know the section size. - // Each chunk size needs to be in sync with what we write in writeTo. - CuTypesOffset = CuListOffset + getCuSize(Chunks) * 16; - SymtabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * 20; - ConstantPoolOffset = SymtabOffset + GdbSymtab.size() * 8; - - size_t Off = 0; - for (ArrayRef<uint32_t> Vec : CuVectors) { - CuVectorOffsets.push_back(Off); - Off += (Vec.size() + 1) * 4; - } - StringPoolOffset = ConstantPoolOffset + Off; -} - -size_t GdbIndexSection::getSize() const { - return StringPoolOffset + StringPoolSize; -} - void GdbIndexSection::writeTo(uint8_t *Buf) { - // Write the section header. - write32le(Buf, 7); - write32le(Buf + 4, CuListOffset); - write32le(Buf + 8, CuTypesOffset); - write32le(Buf + 12, CuTypesOffset); - write32le(Buf + 16, SymtabOffset); - write32le(Buf + 20, ConstantPoolOffset); - Buf += 24; + // Write the header. + auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf); + uint8_t *Start = Buf; + Hdr->Version = 7; + Buf += sizeof(*Hdr); // Write the CU list. - for (GdbIndexChunk &D : Chunks) { - for (GdbIndexChunk::CuEntry &Cu : D.CompilationUnits) { - write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset); + Hdr->CuListOff = Buf - Start; + for (GdbChunk &Chunk : Chunks) { + for (CuEntry &Cu : Chunk.CompilationUnits) { + write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset); write64le(Buf + 8, Cu.CuLength); Buf += 16; } } // Write the address area. - for (GdbIndexChunk &D : Chunks) { - for (GdbIndexChunk::AddressEntry &E : D.AddressAreas) { - uint64_t BaseAddr = - E.Section->getParent()->Addr + E.Section->getOffset(0); + Hdr->CuTypesOff = Buf - Start; + Hdr->AddressAreaOff = Buf - Start; + uint32_t CuOff = 0; + for (GdbChunk &Chunk : Chunks) { + for (AddressEntry &E : Chunk.AddressAreas) { + uint64_t BaseAddr = E.Section->getVA(0); write64le(Buf, BaseAddr + E.LowAddress); write64le(Buf + 8, BaseAddr + E.HighAddress); - write32le(Buf + 16, E.CuIndex); + write32le(Buf + 16, E.CuIndex + CuOff); Buf += 20; } + CuOff += Chunk.CompilationUnits.size(); } - // Write the symbol table. - for (GdbSymbol *Sym : GdbSymtab) { - if (Sym) { - write32le(Buf, Sym->NameOffset + StringPoolOffset - ConstantPoolOffset); - write32le(Buf + 4, CuVectorOffsets[Sym->CuVectorIndex]); - } - Buf += 8; + // Write the on-disk open-addressing hash table containing symbols. + Hdr->SymtabOff = Buf - Start; + size_t SymtabSize = computeSymtabSize(); + uint32_t Mask = SymtabSize - 1; + + for (GdbSymbol &Sym : Symbols) { + uint32_t H = Sym.Name.hash(); + uint32_t I = H & Mask; + uint32_t Step = ((H * 17) & Mask) | 1; + + while (read32le(Buf + I * 8)) + I = (I + Step) & Mask; + + write32le(Buf + I * 8, Sym.NameOff); + write32le(Buf + I * 8 + 4, Sym.CuVectorOff); } + Buf += SymtabSize * 8; + + // Write the string pool. + Hdr->ConstantPoolOff = Buf - Start; + for (GdbSymbol &Sym : Symbols) + memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size()); + // Write the CU vectors. - for (ArrayRef<uint32_t> Vec : CuVectors) { - write32le(Buf, Vec.size()); + for (GdbSymbol &Sym : Symbols) { + write32le(Buf, Sym.CuVector.size()); Buf += 4; - for (uint32_t Val : Vec) { + for (uint32_t Val : Sym.CuVector) { write32le(Buf, Val); Buf += 4; } } - - // Write the string pool. - for (auto &KV : Symbols) { - CachedHashStringRef S = KV.first; - GdbSymbol *Sym = KV.second; - size_t Off = Sym->NameOffset; - memcpy(Buf + Off, S.val().data(), S.size()); - Buf[Off + S.size()] = '\0'; - } } bool GdbIndexSection::empty() const { return !Out::DebugInfo; } EhFrameHeader::EhFrameHeader() - : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {} + : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {} // .eh_frame_hdr contains a binary search table of pointers to FDEs. // Each entry of the search table consists of two values, @@ -2171,14 +2600,6 @@ void EhFrameHeader::writeTo(uint8_t *Buf) { std::vector<FdeData> Fdes = InX::EhFrame->getFdeData(); - // Sort the FDE list by their PC and uniqueify. Usually there is only - // one FDE for a PC (i.e. function), but if ICF merges two functions - // into one, there can be more than one FDEs pointing to the address. - auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; }; - std::stable_sort(Fdes.begin(), Fdes.end(), Less); - auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; }; - Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end()); - Buf[0] = 1; Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; Buf[2] = DW_EH_PE_udata4; @@ -2187,10 +2608,9 @@ void EhFrameHeader::writeTo(uint8_t *Buf) { write32(Buf + 8, Fdes.size()); Buf += 12; - uint64_t VA = this->getVA(); for (FdeData &Fde : Fdes) { - write32(Buf, Fde.Pc - VA); - write32(Buf + 4, Fde.FdeVA - VA); + write32(Buf, Fde.PcRel); + write32(Buf + 4, Fde.FdeVARel); Buf += 8; } } @@ -2300,11 +2720,9 @@ VersionNeedSection<ELFT>::VersionNeedSection() NextIndex = getVerDefNum() + 1; } -template <class ELFT> -void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { - SharedFile<ELFT> &File = SS->getFile<ELFT>(); - const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex]; - if (!Ver) { +template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) { + auto &File = cast<SharedFile<ELFT>>(*SS->File); + if (SS->VerdefIndex == VER_NDX_GLOBAL) { SS->VersionId = VER_NDX_GLOBAL; return; } @@ -2314,7 +2732,9 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { // for the soname. if (File.VerdefMap.empty()) Needed.push_back({&File, InX::DynStrTab->addString(File.SoName)}); + const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex]; typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver]; + // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, // prepare to create one by allocating a version identifier and creating a // dynstr entry for the version name. @@ -2478,11 +2898,20 @@ static MergeSyntheticSection *createMergeSynthetic(StringRef Name, return make<MergeNoTailSection>(Name, Type, Flags, Alignment); } -// Debug sections may be compressed by zlib. Uncompress if exists. +// Debug sections may be compressed by zlib. Decompress if exists. void elf::decompressSections() { + parallelForEach(InputSections, + [](InputSectionBase *Sec) { Sec->maybeDecompress(); }); +} + +template <class ELFT> void elf::splitSections() { + // splitIntoPieces needs to be called on each MergeInputSection + // before calling finalizeContents(). parallelForEach(InputSections, [](InputSectionBase *Sec) { - if (Sec->Live) - Sec->maybeUncompress(); + if (auto *S = dyn_cast<MergeInputSection>(Sec)) + S->splitIntoPieces(); + else if (auto *Eh = dyn_cast<EhInputSection>(Sec)) + Eh->split<ELFT>(); }); } @@ -2494,14 +2923,6 @@ void elf::decompressSections() { // that it replaces. It then finalizes each synthetic section in order // to compute an output offset for each piece of each input section. void elf::mergeSections() { - // splitIntoPieces needs to be called on each MergeInputSection - // before calling finalizeContents(). Do that first. - parallelForEach(InputSections, [](InputSectionBase *Sec) { - if (Sec->Live) - if (auto *S = dyn_cast<MergeInputSection>(Sec)) - S->splitIntoPieces(); - }); - std::vector<MergeSyntheticSection *> MergeSections; for (InputSectionBase *&S : InputSections) { MergeInputSection *MS = dyn_cast<MergeInputSection>(S); @@ -2510,8 +2931,10 @@ void elf::mergeSections() { // We do not want to handle sections that are not alive, so just remove // them instead of trying to merge. - if (!MS->Live) + if (!MS->Live) { + S = nullptr; continue; + } StringRef OutsecName = getOutputSectionName(MS); uint32_t Alignment = MS->Alignment; @@ -2565,8 +2988,7 @@ ARMExidxSentinelSection::ARMExidxSentinelSection() // address described by any other table entry. void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { assert(Highest); - uint64_t S = - Highest->getParent()->Addr + Highest->getOffset(Highest->getSize()); + uint64_t S = Highest->getVA(Highest->getSize()); uint64_t P = getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 1); @@ -2574,18 +2996,16 @@ void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { // The sentinel has to be removed if there are no other .ARM.exidx entries. bool ARMExidxSentinelSection::empty() const { - OutputSection *OS = getParent(); - if (!OS) - return false; - - for (auto *B : OS->SectionCommands) - if (auto *ISD = dyn_cast<InputSectionDescription>(B)) - for (auto *S : ISD->Sections) - if (!isa<ARMExidxSentinelSection>(S)) - return false; + for (InputSection *IS : getInputSections(getParent())) + if (!isa<ARMExidxSentinelSection>(IS)) + return false; return true; } +bool ARMExidxSentinelSection::classof(const SectionBase *D) { + return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX; +} + ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, Config->Wordsize, ".text.thunk") { @@ -2594,16 +3014,13 @@ ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) } void ThunkSection::addThunk(Thunk *T) { - uint64_t Off = alignTo(Size, T->Alignment); - T->Offset = Off; Thunks.push_back(T); T->addSymbols(*this); - Size = Off + T->size(); } void ThunkSection::writeTo(uint8_t *Buf) { - for (const Thunk *T : Thunks) - T->writeTo(Buf + T->Offset, *this); + for (Thunk *T : Thunks) + T->writeTo(Buf + T->Offset); } InputSection *ThunkSection::getTargetInputSection() const { @@ -2613,6 +3030,20 @@ InputSection *ThunkSection::getTargetInputSection() const { return T->getTargetInputSection(); } +bool ThunkSection::assignOffsets() { + uint64_t Off = 0; + for (Thunk *T : Thunks) { + Off = alignTo(Off, T->Alignment); + T->setOffset(Off); + uint32_t Size = T->size(); + T->getThunkTargetSym()->Size = Size; + Off += Size; + } + bool Changed = Off != Size; + Size = Off; + return Changed; +} + InputSection *InX::ARMAttributes; BssSection *InX::Bss; BssSection *InX::BssRelRo; @@ -2634,16 +3065,23 @@ MipsRldMapSection *InX::MipsRldMap; PltSection *InX::Plt; PltSection *InX::Iplt; RelocationBaseSection *InX::RelaDyn; +RelrBaseSection *InX::RelrDyn; RelocationBaseSection *InX::RelaPlt; RelocationBaseSection *InX::RelaIplt; StringTableSection *InX::ShStrTab; StringTableSection *InX::StrTab; SymbolTableBaseSection *InX::SymTab; +SymtabShndxSection *InX::SymTabShndx; + +template GdbIndexSection *GdbIndexSection::create<ELF32LE>(); +template GdbIndexSection *GdbIndexSection::create<ELF32BE>(); +template GdbIndexSection *GdbIndexSection::create<ELF64LE>(); +template GdbIndexSection *GdbIndexSection::create<ELF64BE>(); -template GdbIndexSection *elf::createGdbIndex<ELF32LE>(); -template GdbIndexSection *elf::createGdbIndex<ELF32BE>(); -template GdbIndexSection *elf::createGdbIndex<ELF64LE>(); -template GdbIndexSection *elf::createGdbIndex<ELF64BE>(); +template void elf::splitSections<ELF32LE>(); +template void elf::splitSections<ELF32BE>(); +template void elf::splitSections<ELF64LE>(); +template void elf::splitSections<ELF64BE>(); template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *); template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *); @@ -2655,6 +3093,11 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym); template void PltSection::addEntry<ELF64LE>(Symbol &Sym); template void PltSection::addEntry<ELF64BE>(Symbol &Sym); +template void MipsGotSection::build<ELF32LE>(); +template void MipsGotSection::build<ELF32BE>(); +template void MipsGotSection::build<ELF64LE>(); +template void MipsGotSection::build<ELF64BE>(); + template class elf::MipsAbiFlagsSection<ELF32LE>; template class elf::MipsAbiFlagsSection<ELF32BE>; template class elf::MipsAbiFlagsSection<ELF64LE>; @@ -2685,6 +3128,11 @@ template class elf::AndroidPackedRelocationSection<ELF32BE>; template class elf::AndroidPackedRelocationSection<ELF64LE>; template class elf::AndroidPackedRelocationSection<ELF64BE>; +template class elf::RelrSection<ELF32LE>; +template class elf::RelrSection<ELF32BE>; +template class elf::RelrSection<ELF64LE>; +template class elf::RelrSection<ELF64BE>; + template class elf::SymbolTableSection<ELF32LE>; template class elf::SymbolTableSection<ELF32BE>; template class elf::SymbolTableSection<ELF64LE>; diff --git a/gnu/llvm/tools/lld/ELF/Writer.cpp b/gnu/llvm/tools/lld/ELF/Writer.cpp index 058aa178771..ccff0c58333 100644 --- a/gnu/llvm/tools/lld/ELF/Writer.cpp +++ b/gnu/llvm/tools/lld/ELF/Writer.cpp @@ -9,18 +9,19 @@ #include "Writer.h" #include "AArch64ErrataFix.h" +#include "CallGraphSort.h" #include "Config.h" #include "Filesystem.h" #include "LinkerScript.h" #include "MapFile.h" #include "OutputSections.h" #include "Relocations.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" @@ -49,7 +50,7 @@ public: private: void copyLocalSymbols(); void addSectionSymbols(); - void forEachRelSec(std::function<void(InputSectionBase &)> Fn); + void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn); void sortSections(); void resolveShfLinkOrder(); void sortInputSections(); @@ -62,6 +63,7 @@ private: void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); + void checkSections(); void fixSectionAlignments(); void openFile(); void writeTrapInstr(); @@ -81,40 +83,49 @@ private: uint64_t FileSize; uint64_t SectionHeaderOff; - - bool HasGotBaseSym = false; }; } // anonymous namespace -StringRef elf::getOutputSectionName(InputSectionBase *S) { - // ".zdebug_" is a prefix for ZLIB-compressed sections. - // Because we decompressed input sections, we want to remove 'z'. - if (S->Name.startswith(".zdebug_")) - return Saver.save("." + S->Name.substr(2)); +static bool isSectionPrefix(StringRef Prefix, StringRef Name) { + return Name.startswith(Prefix) || Name == Prefix.drop_back(); +} +StringRef elf::getOutputSectionName(const InputSectionBase *S) { if (Config->Relocatable) return S->Name; // This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want // to emit .rela.text.foo as .rela.text.bar for consistency (this is not // technically required, but not doing it is odd). This code guarantees that. - if ((S->Type == SHT_REL || S->Type == SHT_RELA) && - !isa<SyntheticSection>(S)) { - OutputSection *Out = - cast<InputSection>(S)->getRelocatedSection()->getOutputSection(); - if (S->Type == SHT_RELA) - return Saver.save(".rela" + Out->Name); - return Saver.save(".rel" + Out->Name); + if (auto *IS = dyn_cast<InputSection>(S)) { + if (InputSectionBase *Rel = IS->getRelocatedSection()) { + OutputSection *Out = Rel->getOutputSection(); + if (S->Type == SHT_RELA) + return Saver.save(".rela" + Out->Name); + return Saver.save(".rel" + Out->Name); + } } + // This check is for -z keep-text-section-prefix. This option separates text + // sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or + // ".text.exit". + // When enabled, this allows identifying the hot code region (.text.hot) in + // the final binary which can be selectively mapped to huge pages or mlocked, + // for instance. + if (Config->ZKeepTextSectionPrefix) + for (StringRef V : + {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) { + if (isSectionPrefix(V, S->Name)) + return V.drop_back(); + } + for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab.", - ".openbsd.randomdata."}) { - StringRef Prefix = V.drop_back(); - if (S->Name.startswith(V) || S->Name == Prefix) - return Prefix; + ".openbsd.randomdata."}) { + if (isSectionPrefix(V, S->Name)) + return V.drop_back(); } // CommonSection is identified as "COMMON" in linker scripts. @@ -195,21 +206,30 @@ void elf::addReservedSymbols() { Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL); } + // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which + // combines the typical ELF GOT with the small data sections. It commonly + // includes .got .toc .sdata .sbss. The .TOC. symbol replaces both + // _GLOBAL_OFFSET_TABLE_ and _SDA_BASE_ from the 32-bit ABI. It is used to + // represent the TOC base which is offset by 0x8000 bytes from the start of + // the .got section. ElfSym::GlobalOffsetTable = addOptionalRegular( - "_GLOBAL_OFFSET_TABLE_", Out::ElfHeader, Target->GotBaseSymOff); + (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_", + Out::ElfHeader, Target->GotBaseSymOff); // __ehdr_start is the location of ELF file headers. Note that we define // this symbol unconditionally even when using a linker script, which // differs from the behavior implemented by GNU linker which only define // this symbol if ELF headers are in the memory mapped segment. + addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); + // __executable_start is not documented, but the expectation of at - // least the android libc is that it points to the elf header too. + // least the Android libc is that it points to the ELF header. + addOptionalRegular("__executable_start", Out::ElfHeader, 0, STV_HIDDEN); + // __dso_handle symbol is passed to cxa_finalize as a marker to identify // each DSO. The address of the symbol doesn't matter as long as they are // different in different DSOs, so we chose the start address of the DSO. - for (const char *Name : - {"__ehdr_start", "__executable_start", "__dso_handle"}) - addOptionalRegular(Name, Out::ElfHeader, 0, STV_HIDDEN); + addOptionalRegular("__dso_handle", Out::ElfHeader, 0, STV_HIDDEN); // If linker script do layout we do not need to create any standart symbols. if (Script->HasSectionsCommand) @@ -269,6 +289,7 @@ template <class ELFT> static void createSyntheticSections() { if (Config->Strip != StripPolicy::All) { InX::StrTab = make<StringTableSection>(".strtab", false); InX::SymTab = make<SymbolTableSection<ELFT>>(*InX::StrTab); + InX::SymTabShndx = make<SymtabShndxSection>(); } if (Config->BuildId != BuildIdKind::None) { @@ -282,10 +303,9 @@ template <class ELFT> static void createSyntheticSections() { // If there is a SECTIONS command and a .data.rel.ro section name use name // .data.rel.ro.bss so that we match in the .data.rel.ro output section. // This makes sure our relro is contiguous. - bool HasDataRelRo = - Script->HasSectionsCommand && findSection(".data.rel.ro"); - InX::BssRelRo = make<BssSection>( - HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); + bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro"); + InX::BssRelRo = + make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); Add(InX::BssRelRo); // Add MIPS-specific sections. @@ -332,6 +352,11 @@ template <class ELFT> static void createSyntheticSections() { Add(InX::RelaDyn); } + if (Config->RelrPackDynRelocs) { + InX::RelrDyn = make<RelrSection<ELFT>>(); + Add(InX::RelrDyn); + } + // Add .got. MIPS' .got is so different from the other archs, // it has its own class. if (Config->EMachine == EM_MIPS) { @@ -348,7 +373,7 @@ template <class ELFT> static void createSyntheticSections() { Add(InX::IgotPlt); if (Config->GdbIndex) { - InX::GdbIndex = createGdbIndex<ELFT>(); + InX::GdbIndex = GdbIndexSection::create<ELFT>(); Add(InX::GdbIndex); } @@ -371,9 +396,9 @@ template <class ELFT> static void createSyntheticSections() { false /*Sort*/); Add(InX::RelaIplt); - InX::Plt = make<PltSection>(Target->PltHeaderSize); + InX::Plt = make<PltSection>(false); Add(InX::Plt); - InX::Iplt = make<PltSection>(0); + InX::Iplt = make<PltSection>(true); Add(InX::Iplt); if (!Config->Relocatable) { @@ -387,6 +412,8 @@ template <class ELFT> static void createSyntheticSections() { if (InX::SymTab) Add(InX::SymTab); + if (InX::SymTabShndx) + Add(InX::SymTabShndx); Add(InX::ShStrTab); if (InX::StrTab) Add(InX::StrTab); @@ -456,6 +483,9 @@ template <class ELFT> void Writer<ELFT>::run() { Sec->Addr = 0; } + if (Config->CheckSections) + checkSections(); + // It does not make sense try to open the file if we have error already. if (errorCount()) return; @@ -478,8 +508,9 @@ template <class ELFT> void Writer<ELFT>::run() { if (errorCount()) return; - // Handle -Map option. + // Handle -Map and -cref options. writeMapFile(); + writeCrossReferenceTable(); if (errorCount()) return; @@ -492,10 +523,6 @@ static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, if (B.isSection()) return false; - // If sym references a section in a discarded group, don't keep it. - if (Sec == &InputSection::Discarded) - return false; - if (Config->Discard == DiscardPolicy::None) return true; @@ -640,6 +667,9 @@ static bool isRelroSection(const OutputSection *Sec) { if (InX::Got && Sec == InX::Got->getParent()) return true; + if (Sec->Name.equals(".toc")) + return true; + // .got.plt contains pointers to external function symbols. They are // by default resolved lazily, so we usually cannot put it into RELRO. // However, if "-z now" is given, the lazy symbol resolution is @@ -675,20 +705,22 @@ static bool isRelroSection(const OutputSection *Sec) { // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { - RF_NOT_ADDR_SET = 1 << 16, - RF_NOT_INTERP = 1 << 15, - RF_NOT_ALLOC = 1 << 14, - RF_WRITE = 1 << 13, - RF_EXEC_WRITE = 1 << 12, - RF_EXEC = 1 << 11, - RF_NON_TLS_BSS = 1 << 10, - RF_NON_TLS_BSS_RO = 1 << 9, - RF_NOT_TLS = 1 << 8, - RF_BSS = 1 << 7, + RF_NOT_ADDR_SET = 1 << 18, + RF_NOT_INTERP = 1 << 17, + RF_NOT_ALLOC = 1 << 16, + RF_WRITE = 1 << 15, + RF_EXEC_WRITE = 1 << 14, + RF_EXEC = 1 << 13, + RF_RODATA = 1 << 12, + RF_NON_TLS_BSS = 1 << 11, + RF_NON_TLS_BSS_RO = 1 << 10, + RF_NOT_TLS = 1 << 9, + RF_BSS = 1 << 8, + RF_NOTE = 1 << 7, RF_PPC_NOT_TOCBSS = 1 << 6, - RF_PPC_OPD = 1 << 5, - RF_PPC_TOCL = 1 << 4, - RF_PPC_TOC = 1 << 3, + RF_PPC_TOCL = 1 << 5, + RF_PPC_TOC = 1 << 4, + RF_PPC_GOT = 1 << 3, RF_PPC_BRANCH_LT = 1 << 2, RF_MIPS_GPREL = 1 << 1, RF_MIPS_NOT_GOT = 1 << 0 @@ -719,8 +751,7 @@ static unsigned getSectionRank(const OutputSection *Sec) { // considerations: // * Read-only sections come first such that they go in the // PT_LOAD covering the program headers at the start of the file. - // * Read-only, executable sections come next, unless the - // -no-rosegment option is used. + // * Read-only, executable sections come next. // * Writable, executable sections follow such that .plt on // architectures where it needs to be writable will be placed // between .text and .data. @@ -732,11 +763,16 @@ static unsigned getSectionRank(const OutputSection *Sec) { if (IsExec) { if (IsWrite) Rank |= RF_EXEC_WRITE; - else if (!Config->SingleRoRx) + else Rank |= RF_EXEC; - } else { - if (IsWrite) - Rank |= RF_WRITE; + } else if (IsWrite) { + Rank |= RF_WRITE; + } else if (Sec->Type == SHT_PROGBITS) { + // Make non-executable and non-writable PROGBITS sections (e.g .rodata + // .eh_frame) closer to .text. They likely contain PC or GOT relative + // relocations and there could be relocation overflow if other huge sections + // (.dynstr .dynsym) were placed in between. + Rank |= RF_RODATA; } // If we got here we know that both A and B are in the same PT_LOAD. @@ -772,6 +808,12 @@ static unsigned getSectionRank(const OutputSection *Sec) { if (IsNoBits) Rank |= RF_BSS; + // We create a NOTE segment for contiguous .note sections, so make + // them contigous if there are more than one .note section with the + // same attributes. + if (Sec->Type == SHT_NOTE) + Rank |= RF_NOTE; + // Some architectures have additional ordering restrictions for sections // within the same PT_LOAD. if (Config->EMachine == EM_PPC64) { @@ -785,18 +827,19 @@ static unsigned getSectionRank(const OutputSection *Sec) { if (Name != ".tocbss") Rank |= RF_PPC_NOT_TOCBSS; - if (Name == ".opd") - Rank |= RF_PPC_OPD; - if (Name == ".toc1") Rank |= RF_PPC_TOCL; if (Name == ".toc") Rank |= RF_PPC_TOC; + if (Name == ".got") + Rank |= RF_PPC_GOT; + if (Name == ".branch_lt") Rank |= RF_PPC_BRANCH_LT; } + if (Config->EMachine == EM_MIPS) { // All sections with SHF_MIPS_GPREL flag should be grouped together // because data in these sections is addressable with a gp relative address. @@ -828,8 +871,6 @@ void PhdrEntry::add(OutputSection *Sec) { p_align = std::max(p_align, Sec->Alignment); if (p_type == PT_LOAD) Sec->PtLoad = this; - if (Sec->LMAExpr) - ASectionHasLMA = true; } // The beginning and the ending of .rel[a].plt section are marked @@ -839,17 +880,19 @@ void PhdrEntry::add(OutputSection *Sec) { // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { - if (!Config->Static) + if (Config->Relocatable || needsInterpSection()) return; StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start"; addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK); S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; - addOptionalRegular(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK); + ElfSym::RelaIpltEnd = + addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK); } template <class ELFT> -void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) { +void Writer<ELFT>::forEachRelSec( + llvm::function_ref<void(InputSectionBase &)> Fn) { // Scan all relocations. Each relocation goes through a series // of tests to determine if it needs special treatment, such as // creating GOT, PLT, copy relocations, etc. @@ -869,14 +912,18 @@ void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) { // defining these symbols explicitly in the linker script. template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() { if (ElfSym::GlobalOffsetTable) { - // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to - // be at some offset from the base of the .got section, usually 0 or the end - // of the .got - InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot) - : cast<InputSection>(InX::Got); + // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually + // to the start of the .got or .got.plt section. + InputSection *GotSection = InX::GotPlt; + if (!Target->GotBaseSymInGotPlt) + GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot) + : cast<InputSection>(InX::Got); ElfSym::GlobalOffsetTable->Section = GotSection; } + if (ElfSym::RelaIpltEnd) + ElfSym::RelaIpltEnd->Value = InX::RelaIplt->getSize(); + PhdrEntry *Last = nullptr; PhdrEntry *LastRO = nullptr; @@ -949,8 +996,7 @@ static int getRankProximityAux(OutputSection *A, OutputSection *B) { static int getRankProximity(OutputSection *A, BaseCommand *B) { if (auto *Sec = dyn_cast<OutputSection>(B)) - if (Sec->Live) - return getRankProximityAux(A, Sec); + return getRankProximityAux(A, Sec); return -1; } @@ -969,11 +1015,9 @@ static int getRankProximity(OutputSection *A, BaseCommand *B) { // rw_sec : { *(rw_sec) } // would mean that the RW PT_LOAD would become unaligned. static bool shouldSkip(BaseCommand *Cmd) { - if (isa<OutputSection>(Cmd)) - return false; if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd)) return Assign->Name != "."; - return true; + return false; } // We want to place orphan sections so that they share as much @@ -996,20 +1040,16 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B, int Proximity = getRankProximity(Sec, *I); for (; I != E; ++I) { auto *CurSec = dyn_cast<OutputSection>(*I); - if (!CurSec || !CurSec->Live) + if (!CurSec) continue; if (getRankProximity(Sec, CurSec) != Proximity || Sec->SortRank < CurSec->SortRank) break; } - auto IsLiveSection = [](BaseCommand *Cmd) { - auto *OS = dyn_cast<OutputSection>(Cmd); - return OS && OS->Live; - }; - + auto IsOutputSec = [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); }; auto J = std::find_if(llvm::make_reverse_iterator(I), - llvm::make_reverse_iterator(B), IsLiveSection); + llvm::make_reverse_iterator(B), IsOutputSec); I = J.base(); // As a special case, if the orphan section is the last section, put @@ -1017,7 +1057,7 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B, // This matches bfd's behavior and is convenient when the linker script fully // specifies the start of the file, but doesn't care about the end (the non // alloc sections for example). - auto NextSec = std::find_if(I, E, IsLiveSection); + auto NextSec = std::find_if(I, E, IsOutputSec); if (NextSec == E) return E; @@ -1026,32 +1066,172 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B, return I; } -// If no layout was provided by linker script, we want to apply default -// sorting for special input sections and handle --symbol-ordering-file. -template <class ELFT> void Writer<ELFT>::sortInputSections() { - assert(!Script->HasSectionsCommand); +// Builds section order for handling --symbol-ordering-file. +static DenseMap<const InputSectionBase *, int> buildSectionOrder() { + DenseMap<const InputSectionBase *, int> SectionOrder; + // Use the rarely used option -call-graph-ordering-file to sort sections. + if (!Config->CallGraphProfile.empty()) + return computeCallGraphProfileOrder(); - // Sort input sections by priority using the list provided - // by --symbol-ordering-file. - DenseMap<SectionBase *, int> Order = buildSectionOrder(); - if (!Order.empty()) - for (BaseCommand *Base : Script->SectionCommands) - if (auto *Sec = dyn_cast<OutputSection>(Base)) - if (Sec->Live) - Sec->sort([&](InputSectionBase *S) { return Order.lookup(S); }); + if (Config->SymbolOrderingFile.empty()) + return SectionOrder; + + struct SymbolOrderEntry { + int Priority; + bool Present; + }; + + // Build a map from symbols to their priorities. Symbols that didn't + // appear in the symbol ordering file have the lowest priority 0. + // All explicitly mentioned symbols have negative (higher) priorities. + DenseMap<StringRef, SymbolOrderEntry> SymbolOrder; + int Priority = -Config->SymbolOrderingFile.size(); + for (StringRef S : Config->SymbolOrderingFile) + SymbolOrder.insert({S, {Priority++, false}}); + + // Build a map from sections to their priorities. + auto AddSym = [&](Symbol &Sym) { + auto It = SymbolOrder.find(Sym.getName()); + if (It == SymbolOrder.end()) + return; + SymbolOrderEntry &Ent = It->second; + Ent.Present = true; + + warnUnorderableSymbol(&Sym); + + if (auto *D = dyn_cast<Defined>(&Sym)) { + if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) { + int &Priority = SectionOrder[cast<InputSectionBase>(Sec->Repl)]; + Priority = std::min(Priority, Ent.Priority); + } + } + }; + // We want both global and local symbols. We get the global ones from the + // symbol table and iterate the object files for the local ones. + for (Symbol *Sym : Symtab->getSymbols()) + if (!Sym->isLazy()) + AddSym(*Sym); + for (InputFile *File : ObjectFiles) + for (Symbol *Sym : File->getSymbols()) + if (Sym->isLocal()) + AddSym(*Sym); + + if (Config->WarnSymbolOrdering) + for (auto OrderEntry : SymbolOrder) + if (!OrderEntry.second.Present) + warn("symbol ordering file: no such symbol: " + OrderEntry.first); + + return SectionOrder; +} + +// Sorts the sections in ISD according to the provided section order. +static void +sortISDBySectionOrder(InputSectionDescription *ISD, + const DenseMap<const InputSectionBase *, int> &Order) { + std::vector<InputSection *> UnorderedSections; + std::vector<std::pair<InputSection *, int>> OrderedSections; + uint64_t UnorderedSize = 0; + + for (InputSection *IS : ISD->Sections) { + auto I = Order.find(IS); + if (I == Order.end()) { + UnorderedSections.push_back(IS); + UnorderedSize += IS->getSize(); + continue; + } + OrderedSections.push_back({IS, I->second}); + } + llvm::sort( + OrderedSections.begin(), OrderedSections.end(), + [&](std::pair<InputSection *, int> A, std::pair<InputSection *, int> B) { + return A.second < B.second; + }); + + // Find an insertion point for the ordered section list in the unordered + // section list. On targets with limited-range branches, this is the mid-point + // of the unordered section list. This decreases the likelihood that a range + // extension thunk will be needed to enter or exit the ordered region. If the + // ordered section list is a list of hot functions, we can generally expect + // the ordered functions to be called more often than the unordered functions, + // making it more likely that any particular call will be within range, and + // therefore reducing the number of thunks required. + // + // For example, imagine that you have 8MB of hot code and 32MB of cold code. + // If the layout is: + // + // 8MB hot + // 32MB cold + // + // only the first 8-16MB of the cold code (depending on which hot function it + // is actually calling) can call the hot code without a range extension thunk. + // However, if we use this layout: + // + // 16MB cold + // 8MB hot + // 16MB cold + // + // both the last 8-16MB of the first block of cold code and the first 8-16MB + // of the second block of cold code can call the hot code without a thunk. So + // we effectively double the amount of code that could potentially call into + // the hot code without a thunk. + size_t InsPt = 0; + if (Target->ThunkSectionSpacing && !OrderedSections.empty()) { + uint64_t UnorderedPos = 0; + for (; InsPt != UnorderedSections.size(); ++InsPt) { + UnorderedPos += UnorderedSections[InsPt]->getSize(); + if (UnorderedPos > UnorderedSize / 2) + break; + } + } + + ISD->Sections.clear(); + for (InputSection *IS : makeArrayRef(UnorderedSections).slice(0, InsPt)) + ISD->Sections.push_back(IS); + for (std::pair<InputSection *, int> P : OrderedSections) + ISD->Sections.push_back(P.first); + for (InputSection *IS : makeArrayRef(UnorderedSections).slice(InsPt)) + ISD->Sections.push_back(IS); +} + +static void sortSection(OutputSection *Sec, + const DenseMap<const InputSectionBase *, int> &Order) { + StringRef Name = Sec->Name; // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). - if (OutputSection *Sec = findSection(".init_array")) - Sec->sortInitFini(); - if (OutputSection *Sec = findSection(".fini_array")) - Sec->sortInitFini(); + if (Name == ".init_array" || Name == ".fini_array") { + if (!Script->HasSectionsCommand) + Sec->sortInitFini(); + return; + } // Sort input sections by the special rule for .ctors and .dtors. - if (OutputSection *Sec = findSection(".ctors")) - Sec->sortCtorsDtors(); - if (OutputSection *Sec = findSection(".dtors")) - Sec->sortCtorsDtors(); + if (Name == ".ctors" || Name == ".dtors") { + if (!Script->HasSectionsCommand) + Sec->sortCtorsDtors(); + return; + } + + // Never sort these. + if (Name == ".init" || Name == ".fini") + return; + + // Sort input sections by priority using the list provided + // by --symbol-ordering-file. + if (!Order.empty()) + for (BaseCommand *B : Sec->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) + sortISDBySectionOrder(ISD, Order); +} + +// If no layout was provided by linker script, we want to apply default +// sorting for special input sections. This also handles --symbol-ordering-file. +template <class ELFT> void Writer<ELFT>::sortInputSections() { + // Build the order once since it is expensive. + DenseMap<const InputSectionBase *, int> Order = buildSectionOrder(); + for (BaseCommand *Base : Script->SectionCommands) + if (auto *Sec = dyn_cast<OutputSection>(Base)) + sortSection(Sec, Order); } template <class ELFT> void Writer<ELFT>::sortSections() { @@ -1062,22 +1242,29 @@ template <class ELFT> void Writer<ELFT>::sortSections() { if (Config->Relocatable) return; - for (BaseCommand *Base : Script->SectionCommands) - if (auto *Sec = dyn_cast<OutputSection>(Base)) - Sec->SortRank = getSectionRank(Sec); + sortInputSections(); - if (!Script->HasSectionsCommand) { - sortInputSections(); + for (BaseCommand *Base : Script->SectionCommands) { + auto *OS = dyn_cast<OutputSection>(Base); + if (!OS) + continue; + OS->SortRank = getSectionRank(OS); + + // We want to assign rude approximation values to OutSecOff fields + // to know the relative order of the input sections. We use it for + // sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder(). + uint64_t I = 0; + for (InputSection *Sec : getInputSections(OS)) + Sec->OutSecOff = I++; + } + if (!Script->HasSectionsCommand) { // We know that all the OutputSections are contiguous in this case. - auto E = Script->SectionCommands.end(); - auto I = Script->SectionCommands.begin(); auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); }; - I = std::find_if(I, E, IsSection); - E = std::find_if(llvm::make_reverse_iterator(E), - llvm::make_reverse_iterator(I), IsSection) - .base(); - std::stable_sort(I, E, compareSections); + std::stable_sort( + llvm::find_if(Script->SectionCommands, IsSection), + llvm::find_if(llvm::reverse(Script->SectionCommands), IsSection).base(), + compareSections); return; } @@ -1108,7 +1295,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() { // The way we define an order then is: // * Sort only the orphan sections. They are in the end right now. // * Move each orphan section to its preferred position. We try - // to put each section in the last position where it it can share + // to put each section in the last position where it can share // a PT_LOAD. // // There is some ambiguity as to where exactly a new entry should be @@ -1124,7 +1311,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() { auto E = Script->SectionCommands.end(); auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) { if (auto *Sec = dyn_cast<OutputSection>(Base)) - return Sec->Live && Sec->SectionIndex == INT_MAX; + return Sec->SectionIndex == UINT32_MAX; return false; }); @@ -1199,8 +1386,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) { }; // Get the last table Entry from the previous .ARM.exidx section. - const ExidxEntry &PrevEntry = *reinterpret_cast<const ExidxEntry *>( - Prev->Data.data() + Prev->getSize() - sizeof(ExidxEntry)); + const ExidxEntry &PrevEntry = Prev->getDataAs<ExidxEntry>().back(); if (IsExtabRef(PrevEntry.Unwind)) return false; @@ -1212,14 +1398,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) { // consecutive identical entries are rare and the effort to check that they // are identical is high. - if (isa<SyntheticSection>(Cur)) - // Exidx sentinel section has implicit EXIDX_CANTUNWIND; - return PrevEntry.Unwind == 0x1; - - ArrayRef<const ExidxEntry> Entries( - reinterpret_cast<const ExidxEntry *>(Cur->Data.data()), - Cur->getSize() / sizeof(ExidxEntry)); - for (const ExidxEntry &Entry : Entries) + for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>()) if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind) return false; // All table entries in this .ARM.exidx Section can be merged into the @@ -1249,13 +1428,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { if (!Config->Relocatable && Config->EMachine == EM_ARM && Sec->Type == SHT_ARM_EXIDX) { - if (!Sections.empty() && isa<ARMExidxSentinelSection>(Sections.back())) { + if (auto *Sentinel = dyn_cast<ARMExidxSentinelSection>(Sections.back())) { assert(Sections.size() >= 2 && "We should create a sentinel section only if there are " "alive regular exidx sections."); // The last executable section is required to fill the sentinel. // Remember it here so that we don't have to find it again. - auto *Sentinel = cast<ARMExidxSentinelSection>(Sections.back()); Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep(); } @@ -1266,16 +1444,13 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { // previous one. This does not require any rewriting of InputSection // contents but misses opportunities for fine grained deduplication // where only a subset of the InputSection contents can be merged. - int Cur = 1; - int Prev = 0; + size_t Prev = 0; // The last one is a sentinel entry which should not be removed. - int N = Sections.size() - 1; - while (Cur < N) { - if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur])) - Sections[Cur] = nullptr; + for (size_t I = 1; I < Sections.size() - 1; ++I) { + if (isDuplicateArmExidxSec(Sections[Prev], Sections[I])) + Sections[I] = nullptr; else - Prev = Cur; - ++Cur; + Prev = I; } } } @@ -1286,14 +1461,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { // Remove the Sections we marked as duplicate earlier. for (BaseCommand *Base : Sec->SectionCommands) if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) - ISD->Sections.erase( - std::remove(ISD->Sections.begin(), ISD->Sections.end(), nullptr), - ISD->Sections.end()); + llvm::erase_if(ISD->Sections, [](InputSection *IS) { return !IS; }); } } static void applySynthetic(const std::vector<SyntheticSection *> &Sections, - std::function<void(SyntheticSection *)> Fn) { + llvm::function_ref<void(SyntheticSection *)> Fn) { for (SyntheticSection *SS : Sections) if (SS && SS->getParent() && !SS->empty()) Fn(SS); @@ -1320,27 +1493,15 @@ static void removeUnusedSyntheticSections() { if (!SS) return; OutputSection *OS = SS->getParent(); - if (!SS->empty() || !OS) + if (!OS || !SS->empty()) continue; - std::vector<BaseCommand *>::iterator Empty = OS->SectionCommands.end(); - for (auto I = OS->SectionCommands.begin(), E = OS->SectionCommands.end(); - I != E; ++I) { - BaseCommand *B = *I; - if (auto *ISD = dyn_cast<InputSectionDescription>(B)) { + // If we reach here, then SS is an unused synthetic section and we want to + // remove it from corresponding input section description of output section. + for (BaseCommand *B : OS->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) llvm::erase_if(ISD->Sections, [=](InputSection *IS) { return IS == SS; }); - if (ISD->Sections.empty()) - Empty = I; - } - } - if (Empty != OS->SectionCommands.end()) - OS->SectionCommands.erase(Empty); - - // If there are no other sections in the output section, remove it from the - // output. - if (OS->SectionCommands.empty()) - OS->Live = false; } } @@ -1432,9 +1593,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (InX::DynSymTab && Sym->includeInDynsym()) { InX::DynSymTab->addSymbol(Sym); - if (auto *SS = dyn_cast<SharedSymbol>(Sym)) - if (cast<SharedFile<ELFT>>(Sym->File)->IsNeeded) - In<ELFT>::VerNeed->addSymbol(SS); + if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File)) + if (File->IsNeeded && !Sym->isUndefined()) + In<ELFT>::VerNeed->addSymbol(Sym); } } @@ -1442,10 +1603,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (errorCount()) return; + if (InX::MipsGot) + InX::MipsGot->build<ELFT>(); + removeUnusedSyntheticSections(); sortSections(); - Script->removeEmptyCommands(); // Now that we have the final list, create a list of all the // OutputSections for convenience. @@ -1453,6 +1616,15 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (auto *Sec = dyn_cast<OutputSection>(Base)) OutputSections.push_back(Sec); + // Ensure data sections are not mixed with executable sections when + // -execute-only is used. + if (Config->ExecuteOnly) + for (OutputSection *OS : OutputSections) + if (OS->Flags & SHF_EXECINSTR) + for (InputSection *IS : getInputSections(OS)) + if (!(IS->Flags & SHF_EXECINSTR)) + error("-execute-only does not support intermingling data and code"); + // Prefer command line supplied address over other constraints. for (OutputSection *Sec : OutputSections) { auto I = Config->SectionStartMap.find(Sec->Name); @@ -1461,7 +1633,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { } // This is a bit of a hack. A value of 0 means undef, so we set it - // to 1 t make __ehdr_start defined. The section number is not + // to 1 to make __ehdr_start defined. The section number is not // particularly relevant. Out::ElfHeader->SectionIndex = 1; @@ -1487,12 +1659,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic( - {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, - InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab, - In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot, - InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelaIplt, - InX::RelaPlt, InX::Plt, InX::Iplt, InX::EhFrameHdr, - In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic}, + {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, + InX::HashTab, InX::SymTab, InX::SymTabShndx, InX::ShStrTab, + InX::StrTab, In<ELFT>::VerDef, InX::DynStrTab, InX::Got, + InX::MipsGot, InX::IgotPlt, InX::GotPlt, InX::RelaDyn, + InX::RelrDyn, InX::RelaIplt, InX::RelaPlt, InX::Plt, + InX::Iplt, InX::EhFrameHdr, In<ELFT>::VerSym, In<ELFT>::VerNeed, + InX::Dynamic}, [](SyntheticSection *SS) { SS->finalizeContents(); }); if (!Script->HasSectionsCommand && !Config->Relocatable) @@ -1504,10 +1677,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // Some architectures need to generate content that depends on the address // of InputSections. For example some architectures use small displacements - // for jump instructions that is is the linker's responsibility for creating + // for jump instructions that is the linker's responsibility for creating // range extension thunks for. As the generation of the content may also // alter InputSection addresses we must converge to a fixed point. - if (Target->NeedsThunks || Config->AndroidPackDynRelocs) { + if (Target->NeedsThunks || Config->AndroidPackDynRelocs || + Config->RelrPackDynRelocs) { ThunkCreator TC; AArch64Err843419Patcher A64P; bool Changed; @@ -1524,34 +1698,48 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (InX::MipsGot) InX::MipsGot->updateAllocSize(); Changed |= InX::RelaDyn->updateAllocSize(); + if (InX::RelrDyn) + Changed |= InX::RelrDyn->updateAllocSize(); } while (Changed); } + // createThunks may have added local symbols to the static symbol table + applySynthetic({InX::SymTab}, + [](SyntheticSection *SS) { SS->postThunkContents(); }); + // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. for (OutputSection *Sec : OutputSections) Sec->finalize<ELFT>(); - - // createThunks may have added local symbols to the static symbol table - applySynthetic({InX::SymTab}, - [](SyntheticSection *SS) { SS->postThunkContents(); }); } // The linker is expected to define SECNAME_start and SECNAME_end // symbols for a few sections. This function defines them. template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { - auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) { - // These symbols resolve to the image base if the section does not exist. - // A special value -1 indicates end of the section. + // If a section does not exist, there's ambiguity as to how we + // define _start and _end symbols for an init/fini section. Since + // the loader assume that the symbols are always defined, we need to + // always define them. But what value? The loader iterates over all + // pointers between _start and _end to run global ctors/dtors, so if + // the section is empty, their symbol values don't actually matter + // as long as _start and _end point to the same location. + // + // That said, we don't want to set the symbols to 0 (which is + // probably the simplest value) because that could cause some + // program to fail to link due to relocation overflow, if their + // program text is above 2 GiB. We use the address of the .text + // section instead to prevent that failure. + OutputSection *Default = findSection(".text"); + if (!Default) + Default = Out::ElfHeader; + auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) { if (OS) { addOptionalRegular(Start, OS, 0); addOptionalRegular(End, OS, -1); } else { - if (Config->Pic) - OS = Out::ElfHeader; - addOptionalRegular(Start, OS, 0); - addOptionalRegular(End, OS, 0); + addOptionalRegular(Start, Default, 0); + addOptionalRegular(End, Default, 0); } }; @@ -1573,12 +1761,12 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) { StringRef S = Sec->Name; if (!isValidCIdentifier(S)) return; - addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); - addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); + addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_PROTECTED); + addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_PROTECTED); } static bool needsPtLoad(OutputSection *Sec) { - if (!(Sec->Flags & SHF_ALLOC)) + if (!(Sec->Flags & SHF_ALLOC) || Sec->Noload) return false; // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is @@ -1596,6 +1784,8 @@ static bool needsPtLoad(OutputSection *Sec) { static uint64_t computeFlags(uint64_t Flags) { if (Config->Omagic) return PF_R | PF_W | PF_X; + if (Config->ExecuteOnly && (Flags & PF_X)) + return Flags & ~PF_R; if (Config->SingleRoRx && !(Flags & PF_W)) return Flags | PF_X; return Flags; @@ -1634,10 +1824,14 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { // Segments are contiguous memory regions that has the same attributes // (e.g. executable or writable). There is one phdr for each segment. // Therefore, we need to create a new phdr when the next section has - // different flags or is loaded at a discontiguous address using AT linker - // script command. + // different flags or is loaded at a discontiguous address or memory + // region using AT or AT> linker script command, respectively. At the same + // time, we don't want to create a separate load segment for the headers, + // even if the first output section has an AT or AT> attribute. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); - if ((Sec->LMAExpr && Load->ASectionHasLMA) || + if (((Sec->LMAExpr || + (Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) && + Load->LastSec != Out::ProgramHeaders) || Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); @@ -1700,11 +1894,9 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { // pages for the stack non-executable. If you really want an executable // stack, you can pass -z execstack, but that's not recommended for // security reasons. - unsigned Perm; + unsigned Perm = PF_R | PF_W; if (Config->ZExecstack) - Perm = PF_R | PF_W | PF_X; - else - Perm = PF_R | PF_W; + Perm |= PF_X; AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable @@ -1717,7 +1909,7 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { // Create one PT_NOTE per a group of contiguous .note sections. PhdrEntry *Note = nullptr; for (OutputSection *Sec : OutputSections) { - if (Sec->Type == SHT_NOTE) { + if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) { if (!Note || Sec->LMAExpr) Note = AddHdr(PT_NOTE, PF_R); Note->add(Sec); @@ -1822,6 +2014,12 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() { FileSize = alignTo(Off, Config->Wordsize); } +static std::string rangeToString(uint64_t Addr, uint64_t Len) { + if (Len == 0) + return "<empty range at 0x" + utohexstr(Addr) + ">"; + return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]"; +} + // Assign file offsets to output sections. template <class ELFT> void Writer<ELFT>::assignFileOffsets() { uint64_t Off = 0; @@ -1846,6 +2044,24 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() { SectionHeaderOff = alignTo(Off, Config->Wordsize); FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); + + // Our logic assumes that sections have rising VA within the same segment. + // With use of linker scripts it is possible to violate this rule and get file + // offset overlaps or overflows. That should never happen with a valid script + // which does not move the location counter backwards and usually scripts do + // not do that. Unfortunately, there are apps in the wild, for example, Linux + // kernel, which control segment distribution explicitly and move the counter + // backwards, so we have to allow doing that to support linking them. We + // perform non-critical checks for overlaps in checkSectionOverlap(), but here + // we want to prevent file size overflows because it would crash the linker. + for (OutputSection *Sec : OutputSections) { + if (Sec->Type == SHT_NOBITS) + continue; + if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize)) + error("unable to place section " + Sec->Name + " at file offset " + + rangeToString(Sec->Offset, Sec->Offset + Sec->Size) + + "; check your linker script for overflows"); + } } // Finalize the program headers. We call this function after we assign @@ -1884,6 +2100,97 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() { } } +// A helper struct for checkSectionOverlap. +namespace { +struct SectionOffset { + OutputSection *Sec; + uint64_t Offset; +}; +} // namespace + +// Check whether sections overlap for a specific address range (file offsets, +// load and virtual adresses). +static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections, + bool IsVirtualAddr) { + llvm::sort(Sections.begin(), Sections.end(), + [=](const SectionOffset &A, const SectionOffset &B) { + return A.Offset < B.Offset; + }); + + // Finding overlap is easy given a vector is sorted by start position. + // If an element starts before the end of the previous element, they overlap. + for (size_t I = 1, End = Sections.size(); I < End; ++I) { + SectionOffset A = Sections[I - 1]; + SectionOffset B = Sections[I]; + if (B.Offset >= A.Offset + A.Sec->Size) + continue; + + // If both sections are in OVERLAY we allow the overlapping of virtual + // addresses, because it is what OVERLAY was designed for. + if (IsVirtualAddr && A.Sec->InOverlay && B.Sec->InOverlay) + continue; + + errorOrWarn("section " + A.Sec->Name + " " + Name + + " range overlaps with " + B.Sec->Name + "\n>>> " + A.Sec->Name + + " range is " + rangeToString(A.Offset, A.Sec->Size) + "\n>>> " + + B.Sec->Name + " range is " + + rangeToString(B.Offset, B.Sec->Size)); + } +} + +// Check for overlapping sections and address overflows. +// +// In this function we check that none of the output sections have overlapping +// file offsets. For SHF_ALLOC sections we also check that the load address +// ranges and the virtual address ranges don't overlap +template <class ELFT> void Writer<ELFT>::checkSections() { + // First, check that section's VAs fit in available address space for target. + for (OutputSection *OS : OutputSections) + if ((OS->Addr + OS->Size < OS->Addr) || + (!ELFT::Is64Bits && OS->Addr + OS->Size > UINT32_MAX)) + errorOrWarn("section " + OS->Name + " at 0x" + utohexstr(OS->Addr) + + " of size 0x" + utohexstr(OS->Size) + + " exceeds available address space"); + + // Check for overlapping file offsets. In this case we need to skip any + // section marked as SHT_NOBITS. These sections don't actually occupy space in + // the file so Sec->Offset + Sec->Size can overlap with others. If --oformat + // binary is specified only add SHF_ALLOC sections are added to the output + // file so we skip any non-allocated sections in that case. + std::vector<SectionOffset> FileOffs; + for (OutputSection *Sec : OutputSections) + if (0 < Sec->Size && Sec->Type != SHT_NOBITS && + (!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC))) + FileOffs.push_back({Sec, Sec->Offset}); + checkOverlap("file", FileOffs, false); + + // When linking with -r there is no need to check for overlapping virtual/load + // addresses since those addresses will only be assigned when the final + // executable/shared object is created. + if (Config->Relocatable) + return; + + // Checking for overlapping virtual and load addresses only needs to take + // into account SHF_ALLOC sections since others will not be loaded. + // Furthermore, we also need to skip SHF_TLS sections since these will be + // mapped to other addresses at runtime and can therefore have overlapping + // ranges in the file. + std::vector<SectionOffset> VMAs; + for (OutputSection *Sec : OutputSections) + if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS)) + VMAs.push_back({Sec, Sec->Addr}); + checkOverlap("virtual address", VMAs, true); + + // Finally, check that the load addresses don't overlap. This will usually be + // the same as the virtual addresses but can be different when using a linker + // script with AT(). + std::vector<SectionOffset> LMAs; + for (OutputSection *Sec : OutputSections) + if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS)) + LMAs.push_back({Sec, Sec->getLMA()}); + checkOverlap("load address", LMAs, false); +} + // The entry point address is chosen in the following ways. // // 1. the '-e' entry command-line option; @@ -1925,8 +2232,20 @@ static uint16_t getELFType() { return ET_EXEC; } +static uint8_t getAbiVersion() { + // MIPS non-PIC executable gets ABI version 1. + if (Config->EMachine == EM_MIPS && getELFType() == ET_EXEC && + (Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC) + return 1; + return 0; +} + template <class ELFT> void Writer<ELFT>::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); + // For executable segments, the trap instructions are written before writing + // the header. Setting Elf header bytes to zero ensures that any unused bytes + // in header are zero-cleared, instead of having trap instructions. + memset(Buf, 0, sizeof(Elf_Ehdr)); memcpy(Buf, "\177ELF", 4); // Write the ELF header. @@ -1935,6 +2254,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB; EHdr->e_ident[EI_VERSION] = EV_CURRENT; EHdr->e_ident[EI_OSABI] = Config->OSABI; + EHdr->e_ident[EI_ABIVERSION] = getAbiVersion(); EHdr->e_type = getELFType(); EHdr->e_machine = Config->EMachine; EHdr->e_version = EV_CURRENT; @@ -1944,8 +2264,6 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); - EHdr->e_shnum = OutputSections.size() + 1; - EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex; if (!Config->Relocatable) { EHdr->e_phoff = sizeof(Elf_Ehdr); @@ -1966,8 +2284,30 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { ++HBuf; } - // Write the section header table. Note that the first table entry is null. + // Write the section header table. + // + // The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum + // and e_shstrndx fields. When the value of one of these fields exceeds + // SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and + // use fields in the section header at index 0 to store + // the value. The sentinel values and fields are: + // e_shnum = 0, SHdrs[0].sh_size = number of sections. + // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index. auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff); + size_t Num = OutputSections.size() + 1; + if (Num >= SHN_LORESERVE) + SHdrs->sh_size = Num; + else + EHdr->e_shnum = Num; + + uint32_t StrTabIndex = InX::ShStrTab->getParent()->SectionIndex; + if (StrTabIndex >= SHN_LORESERVE) { + SHdrs->sh_link = StrTabIndex; + EHdr->e_shstrndx = SHN_XINDEX; + } else { + EHdr->e_shstrndx = StrTabIndex; + } + for (OutputSection *Sec : OutputSections) Sec->writeHeaderTo<ELFT>(++SHdrs); } @@ -2038,14 +2378,6 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() { template <class ELFT> void Writer<ELFT>::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); - // PPC64 needs to process relocations in the .opd section - // before processing relocations in code-containing sections. - if (auto *OpdCmd = findSection(".opd")) { - Out::Opd = OpdCmd; - Out::OpdBuf = Buf + Out::Opd->Offset; - OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset); - } - OutputSection *EhFrameHdr = nullptr; if (InX::EhFrameHdr && !InX::EhFrameHdr->empty()) EhFrameHdr = InX::EhFrameHdr->getParent(); @@ -2058,8 +2390,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() { Sec->writeTo<ELFT>(Buf + Sec->Offset); for (OutputSection *Sec : OutputSections) - if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL && - Sec->Type != SHT_RELA) + if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) Sec->writeTo<ELFT>(Buf + Sec->Offset); // The .eh_frame_hdr depends on .eh_frame section contents, therefore diff --git a/gnu/llvm/tools/lld/docs/ld.lld.1 b/gnu/llvm/tools/lld/docs/ld.lld.1 index 64e3e2dc624..98fc3a34bd1 100644 --- a/gnu/llvm/tools/lld/docs/ld.lld.1 +++ b/gnu/llvm/tools/lld/docs/ld.lld.1 @@ -3,7 +3,7 @@ .\" .\" This man page documents only lld's ELF linking support, obtained originally .\" from FreeBSD. -.Dd February 9, 2018 +.Dd September 14, 2018 .Dt LD.LLD 1 .Os .Sh NAME @@ -30,22 +30,24 @@ These options are available: .It Fl -allow-multiple-definition Do not error if a symbol is defined multiple times. The first definition will be used. +.It Fl -apply-dynamic-relocs +Apply link-time values for dynamic relocations. .It Fl -as-needed Only set .Dv DT_NEEDED for shared libraries if used. -.It Fl -auxiliary Ar value +.It Fl -auxiliary Ns = Ns Ar value Set the .Dv DT_AUXILIARY field to the specified name. -.It Fl -Bdynamic +.It Fl -Bdynamic , Fl -dy Link against shared libraries. -.It Fl -Bstatic +.It Fl -Bstatic , Fl -static , Fl -dn Do not link against shared libraries. -.It Fl -Bsymbolic-functions -Bind defined function symbols locally. .It Fl -Bsymbolic Bind defined symbols locally. +.It Fl -Bsymbolic-functions +Bind defined function symbols locally. .It Fl -build-id Ns = Ns Ar value Generate a build ID note. .Ar value @@ -93,7 +95,9 @@ may be .Cm none or .Cm zlib . -.It Fl -define-common +.It Fl -cref +Output cross reference table. +.It Fl -define-common , Fl d Assign space to common symbols. .It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression Define a symbol alias. @@ -107,13 +111,13 @@ or Demangle symbol names. .It Fl -disable-new-dtags Disable new dynamic tags. -.It Fl -discard-all +.It Fl -discard-all , Fl x Delete all local symbols. -.It Fl -discard-locals +.It Fl -discard-locals , Fl X Delete temporary local symbols. .It Fl -discard-none Keep all symbols in the symbol table. -.It Fl -dynamic-linker Ar value +.It Fl -dynamic-linker Ns = Ns Ar value Specify the dynamic linker to be used for a dynamically linked executable. This is recorded in an ELF segment of type .Dv PT_INTERP . @@ -126,7 +130,7 @@ Request creation of section and .Dv PT_GNU_EH_FRAME segment header. -.It Fl -emit-relocs +.It Fl -emit-relocs , Fl q Generate relocations in the output. .It Fl -enable-new-dtags Enable new dynamic tags. @@ -142,21 +146,21 @@ A value of zero indicates that there is no limit. Report unresolved symbols as errors. .It Fl -exclude-libs Ns = Ns Ar value Exclude static libraries from automatic export. +.It Fl -export-dynamic , Fl E +Put symbols in the dynamic symbol table. .It Fl -export-dynamic-symbol Ns = Ns Ar symbol Include .Ar symbol in the dynamic symbol table. -.It Fl -export-dynamic -Put symbols in the dynamic symbol table. .It Fl -fatal-warnings Treat warnings as errors. -.It Fl -filter Ns = Ns Ar value +.It Fl -filter Ns = Ns Ar value , Fl F Ar value Set the .Dv DT_FILTER field to the specified value. .It Fl -fini Ns = Ns Ar symbol Specify a finalizer function. -.It Fl -format Ns = Ns Ar input-format +.It Fl -format Ns = Ns Ar input-format , Fl b Ar input-format Specify the format of the inputs following this option. .Ar input-format may be one of @@ -187,6 +191,8 @@ is the default. Print a help message. .It Fl -icf Ns = Ns Cm all Enable identical code folding. +.It Fl -icf Ns = Ns Cm safe +Enable safe identical code folding. .It Fl -icf Ns = Ns Cm none Disable identical code folding. .It Fl -image-base Ns = Ns Ar value @@ -194,25 +200,29 @@ Set the base address to .Ar value . .It Fl -init Ns = Ns Ar symbol Specify an initializer function. +.It Fl -keep-unique Ns = Ns Ar symbol +Do not fold +.Ar symbol +during ICF. +.It Fl l Ar libName, Fl -library Ns = Ns Ar libName +Root name of library to use. +.It Fl L Ar dir , Fl -library-path Ns = Ns Ar dir +Add a directory to the library search path. .It Fl -lto-aa-pipeline Ns = Ns Ar value AA pipeline to run during LTO. Used in conjunction with .Fl -lto-newpm-passes . .It Fl -lto-newpm-passes Ns = Ns Ar value Passes to run during LTO. -.It Fl -lto-O Ar opt-level +.It Fl -lto-O Ns Ar opt-level Optimization level for LTO. .It Fl -lto-partitions Ns = Ns Ar value Number of LTO codegen partitions. -.It Fl L Ar dir -Add a directory to the library search path. -.It Fl l Ar libName -Root name of library to use. -.It Fl -Map Ns = Ns Ar file -Print a link map to -.Ar file . .It Fl m Ar value Set target emulation. +.It Fl -Map Ns = Ns Ar file , Fl M Ar file +Print a link map to +.Ar file . .It Fl -no-as-needed Always set .Dv DT_NEEDED @@ -241,26 +251,18 @@ Report version scripts that refer undefined symbols. Report unresolved symbols even if the linker is creating a shared library. .It Fl -no-whole-archive Restores the default behavior of loading archive members. -.It Fl -noinhibit-exec -Retain the executable output file whenever it is still usable. .It Fl -no-pie Do not create a position independent executable. +.It Fl -noinhibit-exec +Retain the executable output file whenever it is still usable. .It Fl -nostdlib Only search directories specified on the command line. -.It Fl -oformat Ar format -Specify the format for the output object file. -The only supported -.Ar format -is -.Cm binary , -which produces output with no ELF header. -.It Fl -omagic -Set the text and data sections to be readable and writable. -.It Fl -opt-remarks-filename Ar file -Write optimization remarks in YAML format to -.Ar file . -.It Fl -opt-remarks-with-hotness -Include hotness information in the optimization remarks file. +.It Fl o Ar path +Write the output executable, library, or object to +.Ar path . +If not specified, +.Dv a.out +is used as a default. .It Fl O Ns Ar value Optimize output file size. .Ar value @@ -277,25 +279,42 @@ Enable string tail merging. .Pp .Fl O Ns Cm 1 is the default. -.It Fl o Ar path -Write the output executable, library, or object to -.Ar path . -If not specified, -.Dv a.out -is used as a default. +.It Fl -oformat Ns = Ns Ar format +Specify the format for the output object file. +The only supported +.Ar format +is +.Cm binary , +which produces output with no ELF header. +.It Fl -omagic , Fl N +Set the text and data sections to be readable and writable. +.It Fl -opt-remarks-filename Ar file +Write optimization remarks in YAML format to +.Ar file . +.It Fl -opt-remarks-with-hotness +Include hotness information in the optimization remarks file. .It Fl -pie Create a position independent executable. .It Fl -print-gc-sections List removed unused sections. .It Fl -print-map Print a link map to the standard output. -.It Fl -relocatable +.It Fl -push-state +Save the current state of +.Fl -as-needed , +.Fl -static , +and +.Fl -while-archive. +.It Fl -pop-state +Undo the effect of +.Fl -push-state. +.It Fl -relocatable , Fl r Create relocatable object file. .It Fl -reproduce Ns = Ns Ar value Dump linker invocation and input files for debugging. .It Fl -retain-symbols-file Ns = Ns Ar file Retain only the symbols listed in the file. -.It Fl -rpath Ns = Ns Ar value +.It Fl -rpath Ns = Ns Ar value , Fl R Ar value Add a .Dv DT_RUNPATH to the output. @@ -305,14 +324,14 @@ The supported values are .Cm windows and .Cm posix . -.It Fl -script Ns = Ns Ar file +.It Fl -script Ns = Ns Ar file , Fl T Ar file Read linker script from .Ar file . -.It Fl -section-start Ar section Ns = Ns Ar address +.It Fl -section-start Ns = Ns Ar section Ns = Ns Ar address Set address of section. -.It Fl -shared +.It Fl -shared , Fl -Bsharable Build a shared object. -.It Fl -soname Ns = Ns Ar value +.It Fl -soname Ns = Ns Ar value , Fl h Ar value Set .Dv DT_SONAME to @@ -322,11 +341,11 @@ Specifies sections sorting rule when linkerscript is used. .It Fl -start-lib Start a grouping of objects that should be treated as if they were together in an archive. -.It Fl -strip-all +.It Fl -strip-all , Fl s Strip all symbols. -.It Fl -strip-debug +.It Fl -strip-debug , Fl S Strip debugging information. -.It Fl -symbol-ordering-file Ar file +.It Fl -symbol-ordering-file Ns = Ns Ar file Lay out sections in the order specified by .Ar file . .It Fl -sysroot Ns = Ns Ar value @@ -365,42 +384,46 @@ Same as with .Li .data as the sectionname. +.It Fl -Ttext Ns = Ns Ar value +Same as +.Fl -section-start +with +.Li .text +as the sectionname. .It Fl -thinlto-cache-dir Ns = Ns Ar value Path to ThinLTO cached object file directory. -.It Fl -thinlto-cache-policy Ar value +.It Fl -thinlto-cache-policy Ns = Ns Ar value Pruning policy for the ThinLTO cache. .It Fl -thinlto-jobs Ns = Ns Ar value Number of ThinLTO jobs. .It Fl -threads Run the linker multi-threaded. This option is enabled by default. -.It Fl -trace-symbol Ns = Ns Ar symbol -Trace references to -.Ar symbol . .It Fl -trace Print the names of the input files. -.It Fl -Ttext Ns = Ns Ar value -Same as -.Fl -section-start -with -.Li .text -as the sectionname. -.It Fl -undefined Ns = Ns Ar symbol +.It Fl -trace-symbol Ns = Ns Ar symbol , Fl y Ar symbol +Trace references to +.Ar symbol . +.It Fl -undefined Ns = Ns Ar symbol , Fl u Ar symbol Force .Ar symbol to be an undefined symbol during linking. .It Fl -unresolved-symbols Ns = Ns Ar value Determine how to handle unresolved symbols. +.It Fl v +Display the version number and proceed with linking if object files are +specified. +.It Fl V , Fl -version +Display the version number and exit. .It Fl -verbose Verbose mode. .It Fl -version-script Ns = Ns Ar file Read version script from .Ar file . -.It Fl V , Fl -version -Display the version number and exit. -.It Fl v -Display the version number and proceed with linking if object files are -specified. +.It Fl -warn-backrefs +Warn about reverse or cyclic dependencies to or between static archives. +This can be used to ensure linker invocation remains compatible with +traditional Unix-like linkers. .It Fl -warn-common Warn about duplicate common symbols. .It Fl -warn-unresolved-symbols @@ -417,6 +440,16 @@ Make the main stack executable. Stack permissions are recorded in the .Dv PT_GNU_STACK segment. +.It Cm initfirst +Sets the +.Dv DF_1_INITFIRST +flag to indicate the module should be initialized first. +.It Cm interpose +Set the +.Dv DF_1_INTERPOSE +flag to indicate to the runtime linker that the object is an interposer. +During symbol resolution interposers are searched after the application +but before other dependencies. .It Cm muldefs Do not error if a symbol is defined multiple times. The first definition will be used. @@ -525,3 +558,8 @@ may produce different results compared to traditional linkers. In practice, large bodies of third party software have been linked with .Nm without material issues. +.Pp +The +.Fl -warn-backrefs +option may be used to identify a linker invocation that may be incompatible +with traditional Unix-like linker behavior. diff --git a/gnu/llvm/tools/lld/tools/lld/lld.cpp b/gnu/llvm/tools/lld/tools/lld/lld.cpp index 01aae99e757..e84a94cc3f5 100644 --- a/gnu/llvm/tools/lld/tools/lld/lld.cpp +++ b/gnu/llvm/tools/lld/tools/lld/lld.cpp @@ -7,12 +7,22 @@ // //===----------------------------------------------------------------------===// // -// This is the entry point to the lld driver. This is a thin wrapper which -// dispatches to the given platform specific driver. +// This file contains the main function of the lld executable. The main +// function is a thin wrapper which dispatches to the platform specific +// driver. // -// If there is -flavor option, it is dispatched according to the arguments. -// If the flavor parameter is not present, then it is dispatched according -// to argv[0]. +// lld is a single executable that contains four different linkers for ELF, +// COFF, WebAssembly and Mach-O. The main function dispatches according to +// argv[0] (i.e. command name). The most common name for each target is shown +// below: +// +// - ld.lld: ELF (Unix) +// - ld64: Mach-O (macOS) +// - lld-link: COFF (Windows) +// - ld-wasm: WebAssembly +// +// lld can be invoked as "lld" along with "-flavor" option. This is for +// backward compatibility and not recommended. // //===----------------------------------------------------------------------===// @@ -20,10 +30,9 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" -#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" +#include <cstdlib> using namespace lld; using namespace llvm; @@ -104,13 +113,18 @@ static Flavor parseFlavor(std::vector<const char *> &V) { return parseProgname(Arg0); } +// If this function returns true, lld calls _exit() so that it quickly +// exits without invoking destructors of globally allocated objects. +// +// We don't want to do that if we are running tests though, because +// doing that breaks leak sanitizer. So, lit sets this environment variable, +// and we use it to detect whether we are running tests or not. +static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; } + /// Universal linker main(). This linker emulates the gnu, darwin, or /// windows linker based on the argv[0] or -flavor option. int main(int Argc, const char **Argv) { - // Standard set up, so program fails gracefully. - sys::PrintStackTraceOnErrorSignal(Argv[0]); - PrettyStackTraceProgram StackPrinter(Argc, Argv); - llvm_shutdown_obj Shutdown; + InitLLVM X(Argc, Argv); std::vector<const char *> Args(Argv, Argv + Argc); switch (parseFlavor(Args)) { @@ -119,17 +133,18 @@ int main(int Argc, const char **Argv) { if (isPETarget(Args)) return !mingw::link(Args); #endif - return !elf::link(Args, true); + return !elf::link(Args, canExitEarly()); #ifndef __OpenBSD__ case WinLink: - return !coff::link(Args, true); + return !coff::link(Args, canExitEarly()); case Darwin: - return !mach_o::link(Args); + return !mach_o::link(Args, canExitEarly()); case Wasm: - return !wasm::link(Args, true); + return !wasm::link(Args, canExitEarly()); #endif default: die("lld is a generic driver.\n" - "Invoke ld.lld (Unix), ld (macOS) or lld-link (Windows) instead."); + "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-lld" + " (WebAssembly) instead"); } } diff --git a/gnu/llvm/tools/lldb/include/lldb/Host/openbsd/HostInfoOpenBSD.h b/gnu/llvm/tools/lldb/include/lldb/Host/openbsd/HostInfoOpenBSD.h index 5a0388ffdd9..809a6f4461f 100644 --- a/gnu/llvm/tools/lldb/include/lldb/Host/openbsd/HostInfoOpenBSD.h +++ b/gnu/llvm/tools/lldb/include/lldb/Host/openbsd/HostInfoOpenBSD.h @@ -12,12 +12,13 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" +#include "llvm/Support/VersionTuple.h" namespace lldb_private { class HostInfoOpenBSD : public HostInfoPosix { public: - static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + static llvm::VersionTuple GetOSVersion(); static bool GetOSBuildString(std::string &s); static bool GetOSKernelDescription(std::string &s); static FileSpec GetProgramFileSpec(); diff --git a/gnu/llvm/tools/lldb/source/Host/openbsd/HostInfoOpenBSD.cpp b/gnu/llvm/tools/lldb/source/Host/openbsd/HostInfoOpenBSD.cpp index 54895889932..91433e955e0 100644 --- a/gnu/llvm/tools/lldb/source/Host/openbsd/HostInfoOpenBSD.cpp +++ b/gnu/llvm/tools/lldb/source/Host/openbsd/HostInfoOpenBSD.cpp @@ -17,16 +17,22 @@ using namespace lldb_private; -bool HostInfoOpenBSD::GetOSVersion(uint32_t &major, uint32_t &minor, - uint32_t &update) { +llvm::VersionTuple HostInfoOpenBSD::GetOSVersion() { struct utsname un; - ::memset(&un, 0, sizeof(utsname)); - if (uname(&un) < 0) - return false; + ::memset(&un, 0, sizeof(un)); + if (::uname(&un) < 0) + return llvm::VersionTuple(); - int status = sscanf(un.release, "%u.%u", &major, &minor); - return status == 2; + uint32_t major, minor; + int status = ::sscanf(un.release, "%" PRIu32 ".%" PRIu32, &major, &minor); + switch (status) { + case 1: + return llvm::VersionTuple(major); + case 2: + return llvm::VersionTuple(major, minor); + } + return llvm::VersionTuple(); } bool HostInfoOpenBSD::GetOSBuildString(std::string &s) { |