Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
// RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t -- -- -std=c23
// RUN: %check_clang_tidy -check-suffix=UPPER-CASE %s readability-implicit-bool-conversion %t -- \
// RUN: -config='{CheckOptions: { \
// RUN: readability-implicit-bool-conversion.UseUpperCaseLiteralSuffix: true \
// RUN: }}' -- -std=c23

#undef NULL
#define NULL 0L
Expand Down Expand Up @@ -95,6 +99,7 @@ void implicitConversionFromBoolLiterals() {
functionTakingUnsignedLong(false);
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'bool' -> 'unsigned long'
// CHECK-FIXES: functionTakingUnsignedLong(0u);
// CHECK-FIXES-UPPER-CASE: functionTakingUnsignedLong(0U);

functionTakingSignedChar(true);
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'bool' -> 'signed char'
Expand All @@ -103,6 +108,7 @@ void implicitConversionFromBoolLiterals() {
functionTakingFloat(false);
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'bool' -> 'float'
// CHECK-FIXES: functionTakingFloat(0.0f);
// CHECK-FIXES-UPPER-CASE: functionTakingFloat(0.0F);

functionTakingDouble(true);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'bool' -> 'double'
Expand Down Expand Up @@ -160,11 +166,13 @@ void implicitConversionToBoolSimpleCases() {
functionTakingBool(unsignedLong);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'unsigned long' -> 'bool'
// CHECK-FIXES: functionTakingBool(unsignedLong != 0u);
// CHECK-FIXES-UPPER-CASE: functionTakingBool(unsignedLong != 0U);

float floating = 0.0f;
functionTakingBool(floating);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: functionTakingBool(floating != 0.0f);
// CHECK-FIXES-UPPER-CASE: functionTakingBool(floating != 0.0F);

double doubleFloating = 1.0f;
functionTakingBool(doubleFloating);
Expand Down Expand Up @@ -194,6 +202,7 @@ void implicitConversionToBoolInSingleExpressions() {
boolComingFromFloat = floating;
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: boolComingFromFloat = (floating != 0.0f);
// CHECK-FIXES-UPPER-CASE: boolComingFromFloat = (floating != 0.0F);

signed char character = 'a';
bool boolComingFromChar;
Expand Down Expand Up @@ -288,6 +297,7 @@ void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() {
functionTakingBool(-0.0f);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: functionTakingBool((-0.0f) != 0.0f);
// CHECK-FIXES-UPPER-CASE: functionTakingBool((-0.0f) != 0.0F);

functionTakingBool(-0.0);
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
// RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t
// RUN: %check_clang_tidy -check-suffix=UPPER-CASE %s readability-implicit-bool-conversion %t -- \
// RUN: -config='{CheckOptions: { \
// RUN: readability-implicit-bool-conversion.UseUpperCaseLiteralSuffix: true \
// RUN: }}'

// We need NULL macro, but some buildbots don't like including <cstddef> header
// This is a portable way of getting it to work
Expand Down Expand Up @@ -99,6 +103,7 @@ void implicitConversionFromBoolLiterals() {
functionTaking<unsigned long>(false);
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'bool' -> 'unsigned long'
// CHECK-FIXES: functionTaking<unsigned long>(0u);
// CHECK-FIXES-UPPER-CASE: functionTaking<unsigned long>(0U);

functionTaking<signed char>(true);
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: implicit conversion 'bool' -> 'signed char'
Expand All @@ -107,6 +112,7 @@ void implicitConversionFromBoolLiterals() {
functionTaking<float>(false);
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion 'bool' -> 'float'
// CHECK-FIXES: functionTaking<float>(0.0f);
// CHECK-FIXES-UPPER-CASE: functionTaking<float>(0.0F);

functionTaking<double>(true);
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit conversion 'bool' -> 'double'
Expand Down Expand Up @@ -178,11 +184,13 @@ void implicitConversionToBoolSimpleCases() {
functionTaking<bool>(unsignedLong);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> 'bool'
// CHECK-FIXES: functionTaking<bool>(unsignedLong != 0u);
// CHECK-FIXES-UPPER-CASE: functionTaking<bool>(unsignedLong != 0U);

float floating = 0.0f;
functionTaking<bool>(floating);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: functionTaking<bool>(floating != 0.0f);
// CHECK-FIXES-UPPER-CASE: functionTaking<bool>(floating != 0.0F);

double doubleFloating = 1.0f;
functionTaking<bool>(doubleFloating);
Expand Down Expand Up @@ -215,6 +223,7 @@ void implicitConversionToBoolInSingleExpressions() {
bool boolComingFromFloat = floating;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: bool boolComingFromFloat = floating != 0.0f;
// CHECK-FIXES-UPPER-CASE: bool boolComingFromFloat = floating != 0.0F;

signed char character = 'a';
bool boolComingFromChar = character;
Expand All @@ -240,6 +249,7 @@ void implicitConversionToBoolInComplexExpressions() {
bool boolComingFromFloating = floating - 0.3f || boolean;
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: bool boolComingFromFloating = ((floating - 0.3f) != 0.0f) || boolean;
// CHECK-FIXES-UPPER-CASE: bool boolComingFromFloating = ((floating - 0.3f) != 0.0F) || boolean;

double doubleFloating = 0.3;
bool boolComingFromDoubleFloating = (doubleFloating - 0.4) && boolean;
Expand All @@ -257,6 +267,7 @@ void implicitConversionInNegationExpressions() {
bool boolComingFromNegatedFloat = ! floating;
// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: bool boolComingFromNegatedFloat = floating == 0.0f;
// CHECK-FIXES-UPPER-CASE: bool boolComingFromNegatedFloat = floating == 0.0F;

signed char character = 'a';
bool boolComingFromNegatedChar = (! character);
Expand Down Expand Up @@ -284,6 +295,7 @@ void implicitConversionToBoolInControlStatements() {
while (floating) {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: while (floating != 0.0f) {}
// CHECK-FIXES-UPPER-CASE: while (floating != 0.0F) {}

double doubleFloating = 0.4;
do {} while (doubleFloating);
Expand All @@ -296,6 +308,7 @@ bool implicitConversionToBoolInReturnValue() {
return floating;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: return floating != 0.0f;
// CHECK-FIXES-UPPER-CASE: return floating != 0.0F;
}

void implicitConversionToBoolFromLiterals() {
Expand Down Expand Up @@ -355,6 +368,7 @@ void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() {
functionTaking<bool>(-0.0f);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> 'bool'
// CHECK-FIXES: functionTaking<bool>((-0.0f) != 0.0f);
// CHECK-FIXES-UPPER-CASE: functionTaking<bool>((-0.0f) != 0.0F);

functionTaking<bool>(-0.0);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> 'bool'
Expand Down
7 changes: 5 additions & 2 deletions clang/cmake/caches/Release.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "")
set(CLANG_ENABLE_BOOTSTRAP ON CACHE BOOL "")

set(STAGE1_PROJECTS "clang")
set(STAGE1_RUNTIMES "")

# Building Flang on Windows requires compiler-rt, so we need to build it in
# stage1. compiler-rt is also required for building the Flang tests on
# macOS.
set(STAGE1_RUNTIMES "compiler-rt")

if (LLVM_RELEASE_ENABLE_PGO)
list(APPEND STAGE1_PROJECTS "lld")
list(APPEND STAGE1_RUNTIMES "compiler-rt")
set(CLANG_BOOTSTRAP_TARGETS
generate-profdata
stage2-package
Expand Down
17 changes: 16 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,13 @@ Non-comprehensive list of changes in this release
New Compiler Flags
------------------

- The ``-fc++-static-destructors={all,thread-local,none}`` flag was
added to control which C++ variables have static destructors
registered: all (the default) does so for all variables, thread-local
only for thread-local variables, and none (which corresponds to the
existing ``-fno-c++-static-destructors`` flag) skips all static
destructors registration.

Deprecated Compiler Flags
-------------------------

Expand Down Expand Up @@ -213,6 +220,11 @@ Attribute Changes in Clang
- ``[[clang::lifetimebound]]`` is now explicitly disallowed on explicit object member functions
where they were previously silently ignored.

- Clang now automatically adds ``[[clang::lifetimebound]]`` to the parameters of
``std::span, std::string_view`` constructors, this enables Clang to capture
more cases where the returned reference outlives the object.
(#GH100567)

Improvements to Clang's diagnostics
-----------------------------------

Expand Down Expand Up @@ -305,12 +317,15 @@ Bug Fixes to C++ Support
- Clang now properly handles the order of attributes in `extern` blocks. (#GH101990).
- Fixed an assertion failure by preventing null explicit object arguments from being deduced. (#GH102025).
- Correctly check constraints of explicit instantiations of member functions. (#GH46029)
- When performing partial ordering of function templates, clang now checks that
the deduction was consistent. Fixes (#GH18291).
- Fixed an assertion failure about a constraint of a friend function template references to a value with greater
template depth than the friend function template. (#GH98258)
- Clang now rebuilds the template parameters of out-of-line declarations and specializations in the context
of the current instantiation in all cases.
- Fix evaluation of the index of dependent pack indexing expressions/types specifiers (#GH105900)

- Correctly handle subexpressions of an immediate invocation in the presence of implicit casts. (#GH105558)
- Clang now correctly handles direct-list-initialization of a structured bindings from an array. (#GH31813)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
11 changes: 7 additions & 4 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -950,10 +950,13 @@ treated as a file name and is searched for sequentially in the directories:
- system directory,
- the directory where Clang executable resides.

Both user and system directories for configuration files are specified during
clang build using CMake parameters, ``CLANG_CONFIG_FILE_USER_DIR`` and
``CLANG_CONFIG_FILE_SYSTEM_DIR`` respectively. The first file found is used.
It is an error if the required file cannot be found.
Both user and system directories for configuration files can be specified
either during build or during runtime. At build time, use
``CLANG_CONFIG_FILE_USER_DIR`` and ``CLANG_CONFIG_FILE_SYSTEM_DIR``. At run
time use the ``--config-user-dir=`` and ``--config-system-dir=`` command line
options. Specifying config directories at runtime overrides the config
directories set at build time The first file found is used. It is an error if
the required file cannot be found.

The default configuration files are searched for in the same directories
following the rules described in the next paragraphs. Loading default
Expand Down
22 changes: 19 additions & 3 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ if ((y = make_int())) {
nullability
^^^^^^^^^^^
Objective C checkers that warn for null pointer passing and dereferencing errors.
Checkers (mostly Objective C) that warn for null pointer passing and dereferencing errors.
.. _nullability-NullPassedToNonnull:
Expand All @@ -588,8 +588,8 @@ Warns when a null pointer is passed to a pointer which has a _Nonnull type.
.. _nullability-NullReturnedFromNonnull:
nullability.NullReturnedFromNonnull (ObjC)
""""""""""""""""""""""""""""""""""""""""""
nullability.NullReturnedFromNonnull (C, C++, ObjC)
""""""""""""""""""""""""""""""""""""""""""""""""""
Warns when a null pointer is returned from a function that has _Nonnull return type.
.. code-block:: objc
Expand All @@ -604,6 +604,22 @@ Warns when a null pointer is returned from a function that has _Nonnull return t
return result;
}
Warns when a null pointer is returned from a function annotated with ``__attribute__((returns_nonnull))``
.. code-block:: cpp
int global;
__attribute__((returns_nonnull)) void* getPtr(void* p);
void* getPtr(void* p) {
if (p) { // forgot to negate the condition
return &global;
}
// Warning: nullptr returned from a function that is expected
// to return a non-null value
return p;
}
.. _nullability-NullableDereferenced:
nullability.NullableDereferenced (ObjC)
Expand Down
86 changes: 56 additions & 30 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,12 @@ succeeds but Clang emits a warning specifying that the function is deprecated.
Finally, if Clang is instructed to compile code for macOS 10.7, the call
fails because ``f()`` is no longer available.

Clang is instructed to compile code for a minimum deployment version using
the ``-target`` or ``-mtargetos`` command line arguments. For example,
macOS 10.7 would be specified as ``-target x86_64-apple-macos10.7`` or
``-mtargetos=macos10.7``. Variants like Mac Catalyst are specified as
``-target arm64-apple-ios15.0-macabi`` or ``-mtargetos=ios15.0-macabi``

The availability attribute is a comma-separated list starting with the
platform name and then including clauses specifying important milestones in the
declaration's lifetime (in any order) along with additional information. Those
Expand Down Expand Up @@ -1636,41 +1642,61 @@ the implicitly inferred availability attributes. If no availability attribute
specifies availability for the current target platform, the availability
attributes are ignored. Supported platforms are:

``ios``
Apple's iOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-ios*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=ios*version*``
command-line argument.
``iOS``
``macOS``
``tvOS``
``watchOS``
``iOSApplicationExtension``
``macOSApplicationExtension``
``tvOSApplicationExtension``
``watchOSApplicationExtension``
``macCatalyst``
``macCatalystApplicationExtension``
``visionOS``
``visionOSApplicationExtension``
``driverkit``
``swift``
``android``
``fuchsia``
``ohos``
``zos``
``ShaderModel``

``macos``
Apple's macOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-macos*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=macos*version*``
command-line argument. ``macosx`` is supported for
backward-compatibility reasons, but it is deprecated.
Some platforms have alias names:

``ios``
``macos``
``macosx (deprecated)``
``tvos``
Apple's tvOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-tvos*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=tvos*version*``
command-line argument.

``watchos``
Apple's watchOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-watchos*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=watchos*version*``
command-line argument.

``ios_app_extension``
``macos_app_extension``
``macosx_app_extension (deprecated)``
``tvos_app_extension``
``watchos_app_extension``
``maccatalyst``
``maccatalyst_app_extension``
``visionos``
Apple's visionOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-visionos*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=visionos*version*``
command-line argument.

``driverkit``
Apple's DriverKit userspace kernel extensions. The minimum deployment target
is specified as part of the ``-target *arch*-apple-driverkit*version*``
command line argument.
``visionos_app_extension``
``shadermodel``

Supported environment names for the ShaderModel platform:

``pixel``
``vertex``
``geometry``
``hull``
``domain``
``compute``
``raygeneration``
``intersection``
``anyhit``
``closesthit``
``miss``
``callable``
``mesh``
``amplification``
``library``

A declaration can typically be used even when deploying back to a platform
version prior to when the declaration was introduced. When this happens, the
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/BuiltinsNVPTX.def
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,9 @@ BUILTIN(__nvvm_atom_xor_gen_ll, "LLiLLiD*LLi", "n")
TARGET_BUILTIN(__nvvm_atom_cta_xor_gen_ll, "LLiLLiD*LLi", "n", SM_60)
TARGET_BUILTIN(__nvvm_atom_sys_xor_gen_ll, "LLiLLiD*LLi", "n", SM_60)

TARGET_BUILTIN(__nvvm_atom_cas_gen_us, "UsUsD*UsUs", "n", SM_70)
TARGET_BUILTIN(__nvvm_atom_cta_cas_gen_us, "UsUsD*UsUs", "n", SM_70)
TARGET_BUILTIN(__nvvm_atom_sys_cas_gen_us, "UsUsD*UsUs", "n", SM_70)
BUILTIN(__nvvm_atom_cas_gen_i, "iiD*ii", "n")
TARGET_BUILTIN(__nvvm_atom_cta_cas_gen_i, "iiD*ii", "n", SM_60)
TARGET_BUILTIN(__nvvm_atom_sys_cas_gen_i, "iiD*ii", "n", SM_60)
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,9 @@ LANGOPT(FixedPoint, 1, 0, "fixed point types")
LANGOPT(PaddingOnUnsignedFixedPoint, 1, 0,
"unsigned fixed point types having one extra padding bit")

LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors")
ENUM_LANGOPT(RegisterStaticDestructors, RegisterStaticDestructorsKind, 2,
RegisterStaticDestructorsKind::All,
"Register C++ static destructors")

LANGOPT(RegCall4, 1, 0, "Set __regcall4 as a default calling convention to respect __regcall ABI v.4")

Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,16 @@ class LangOptionsBase {
CX_None
};

/// Controls which variables have static destructors registered.
enum class RegisterStaticDestructorsKind {
/// Register static destructors for all variables.
All,
/// Register static destructors only for thread-local variables.
ThreadLocal,
/// Don't register static destructors for any variables.
None,
};

// Define simple language options (with no accessors).
#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits;
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,9 @@ KEYWORD(out , KEYHLSL)
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
#include "clang/Basic/HLSLIntangibleTypes.def"

// HLSL Type traits.
TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)

// OpenMP Type Traits
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)

Expand Down
3 changes: 1 addition & 2 deletions clang/include/clang/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,7 @@ class Driver {

/// Takes the path to a binary that's either in bin/ or lib/ and returns
/// the path to clang's resource directory.
static std::string GetResourcesPath(StringRef BinaryPath,
StringRef CustomResourceDir = "");
static std::string GetResourcesPath(StringRef BinaryPath);

Driver(StringRef ClangExecutable, StringRef TargetTriple,
DiagnosticsEngine &Diags, std::string Title = "clang LLVM compiler",
Expand Down
17 changes: 12 additions & 5 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2302,11 +2302,18 @@ defm fixed_point : BoolFOption<"fixed-point",
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Enable">,
NegFlag<SetFalse, [], [ClangOption], "Disable">,
BothFlags<[], [ClangOption], " fixed point types">>;
defm cxx_static_destructors : BoolFOption<"c++-static-destructors",
LangOpts<"RegisterStaticDestructors">, DefaultTrue,
NegFlag<SetFalse, [], [ClangOption, CC1Option],
"Disable C++ static destructor registration">,
PosFlag<SetTrue>>;
def cxx_static_destructors_EQ : Joined<["-"], "fc++-static-destructors=">, Group<f_Group>,
HelpText<"Controls which variables C++ static destructors are registered for">,
Values<"all,thread-local,none">,
NormalizedValues<["All", "ThreadLocal", "None"]>,
NormalizedValuesScope<"LangOptions::RegisterStaticDestructorsKind">,
MarshallingInfoEnum<LangOpts<"RegisterStaticDestructors">, "All">,
Visibility<[ClangOption, CC1Option]>;
def cxx_static_destructors : Flag<["-"], "fc++-static-destructors">, Group<f_Group>,
Alias<cxx_static_destructors_EQ>, AliasArgs<["all"]>;
def no_cxx_static_destructors : Flag<["-"], "fno-c++-static-destructors">, Group<f_Group>,
Alias<cxx_static_destructors_EQ>, AliasArgs<["none"]>,
HelpText<"Disable C++ static destructor registration">;
def fsymbol_partition_EQ : Joined<["-"], "fsymbol-partition=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoString<CodeGenOpts<"SymbolPartition">>;
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/ExtractAPI/DeclarationFragments.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,9 +411,9 @@ class DeclarationFragmentsBuilder {
/// Build DeclarationFragments for a macro.
///
/// \param Name name of the macro.
/// \param MD the associated MacroDirective.
/// \param MI the associated MacroInfo.
static DeclarationFragments getFragmentsForMacro(StringRef Name,
const MacroDirective *MD);
const MacroInfo *MI);

/// Build DeclarationFragments for a typedef \p TypedefNameDecl.
static DeclarationFragments
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {

StringRef getOwningModuleName(const Decl &D) {
if (auto *OwningModule = D.getImportedOwningModule())
return OwningModule->Name;
return OwningModule->getTopLevelModule()->Name;

return {};
}
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/Initialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -1384,6 +1384,11 @@ class InitializationSequence {

void AddParenthesizedListInitStep(QualType T);

/// Only used when initializing structured bindings from an array with
/// direct-list-initialization. Unwrap the initializer list to get the array
/// for array copy.
void AddUnwrapInitListInitStep(InitListExpr *Syntactic);

/// Add steps to unwrap a initializer list for a reference around a
/// single element and rewrap it at the end.
void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic);
Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -1806,6 +1806,9 @@ class Sema final : public SemaBase {
/// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types.
void inferGslOwnerPointerAttribute(CXXRecordDecl *Record);

/// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
void inferLifetimeBoundAttribute(FunctionDecl *FD);

/// Add [[gsl::Pointer]] attributes for std:: types.
void inferGslPointerAttribute(TypedefNameDecl *TD);

Expand Down Expand Up @@ -13280,6 +13283,10 @@ class Sema final : public SemaBase {
/// \param AllowDeducedTST Whether a DeducedTemplateSpecializationType is
/// acceptable as the top level type of the result.
///
/// \param IsIncompleteSubstitution If provided, the pointee will be set
/// whenever substitution would perform a replacement with a null or
/// non-existent template argument.
///
/// \returns If the instantiation succeeds, the instantiated
/// type. Otherwise, produces diagnostics and returns a NULL type.
TypeSourceInfo *SubstType(TypeSourceInfo *T,
Expand All @@ -13289,7 +13296,8 @@ class Sema final : public SemaBase {

QualType SubstType(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity);
SourceLocation Loc, DeclarationName Entity,
bool *IsIncompleteSubstitution = nullptr);

TypeSourceInfo *SubstType(TypeLoc TL,
const MultiLevelTemplateArgumentList &TemplateArgs,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class SemaHLSL : public SemaBase {
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);

bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);

// HLSL Type trait implementations
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
};

} // namespace clang
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines CheckerVisitor.
// This file defines various utilities used by checkers.
//
//===----------------------------------------------------------------------===//

Expand Down Expand Up @@ -114,6 +114,10 @@ OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK,

std::optional<SVal> getPointeeVal(SVal PtrSVal, ProgramStateRef State);

/// Returns true if declaration \p D is in std namespace or any nested namespace
/// or class scope.
bool isWithinStdNamespace(const Decl *D);

} // namespace ento

} // namespace clang
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@ class ExprEngine {
const Stmt *DiagnosticStmt = nullptr,
ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);

/// A tag to track convenience transitions, which can be removed at cleanup.
/// This tag applies to a node created after removeDead.
static const ProgramPointTag *cleanupNodeTag();

/// processCFGElement - Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a CFG element.
void processCFGElement(const CFGElement E, ExplodedNode *Pred,
Expand Down
106 changes: 106 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4991,6 +4991,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
const Expr *SubExpr = E->getSubExpr();
if (SubExpr->getType()->isAnyComplexType())
return this->VisitComplexUnaryOperator(E);
if (SubExpr->getType()->isVectorType())
return this->VisitVectorUnaryOperator(E);
std::optional<PrimType> T = classify(SubExpr->getType());

switch (E->getOpcode()) {
Expand Down Expand Up @@ -5312,6 +5314,110 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) {
return true;
}

template <class Emitter>
bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
const Expr *SubExpr = E->getSubExpr();
assert(SubExpr->getType()->isVectorType());

if (DiscardResult)
return this->discard(SubExpr);

auto UnaryOp = E->getOpcode();
if (UnaryOp != UO_Plus && UnaryOp != UO_Minus && UnaryOp != UO_LNot &&
UnaryOp != UO_Not)
return this->emitInvalid(E);

// Nothing to do here.
if (UnaryOp == UO_Plus)
return this->delegate(SubExpr);

if (!Initializing) {
std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}

// The offset of the temporary, if we created one.
unsigned SubExprOffset =
this->allocateLocalPrimitive(SubExpr, PT_Ptr, true, false);
if (!this->visit(SubExpr))
return false;
if (!this->emitSetLocal(PT_Ptr, SubExprOffset, E))
return false;

const auto *VecTy = SubExpr->getType()->getAs<VectorType>();
PrimType ElemT = classifyVectorElementType(SubExpr->getType());
auto getElem = [=](unsigned Offset, unsigned Index) -> bool {
if (!this->emitGetLocal(PT_Ptr, Offset, E))
return false;
return this->emitArrayElemPop(ElemT, Index, E);
};

switch (UnaryOp) {
case UO_Minus:
for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
if (!getElem(SubExprOffset, I))
return false;
if (!this->emitNeg(ElemT, E))
return false;
if (!this->emitInitElem(ElemT, I, E))
return false;
}
break;
case UO_LNot: { // !x
// In C++, the logic operators !, &&, || are available for vectors. !v is
// equivalent to v == 0.
//
// The result of the comparison is a vector of the same width and number of
// elements as the comparison operands with a signed integral element type.
//
// https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
QualType ResultVecTy = E->getType();
PrimType ResultVecElemT =
classifyPrim(ResultVecTy->getAs<VectorType>()->getElementType());
for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
if (!getElem(SubExprOffset, I))
return false;
// operator ! on vectors returns -1 for 'truth', so negate it.
if (!this->emitPrimCast(ElemT, PT_Bool, Ctx.getASTContext().BoolTy, E))
return false;
if (!this->emitInv(E))
return false;
if (!this->emitPrimCast(PT_Bool, ElemT, VecTy->getElementType(), E))
return false;
if (!this->emitNeg(ElemT, E))
return false;
if (ElemT != ResultVecElemT &&
!this->emitPrimCast(ElemT, ResultVecElemT, ResultVecTy, E))
return false;
if (!this->emitInitElem(ResultVecElemT, I, E))
return false;
}
break;
}
case UO_Not: // ~x
for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
if (!getElem(SubExprOffset, I))
return false;
if (ElemT == PT_Bool) {
if (!this->emitInv(E))
return false;
} else {
if (!this->emitComp(ElemT, E))
return false;
}
if (!this->emitInitElem(ElemT, I, E))
return false;
}
break;
default:
llvm_unreachable("Unsupported unary operators should be handled up front");
}
return true;
}

template <class Emitter>
bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
if (DiscardResult)
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
bool VisitGNUNullExpr(const GNUNullExpr *E);
bool VisitCXXThisExpr(const CXXThisExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitVectorUnaryOperator(const UnaryOperator *E);
bool VisitComplexUnaryOperator(const UnaryOperator *E);
bool VisitDeclRefExpr(const DeclRefExpr *E);
bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
Expand Down Expand Up @@ -349,6 +350,11 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
return *this->classify(ElemType);
}

PrimType classifyVectorElementType(QualType T) const {
assert(T->isVectorType());
return *this->classify(T->getAs<VectorType>()->getElementType());
}

bool emitComplexReal(const Expr *SubExpr);
bool emitComplexBoolCast(const Expr *E);
bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -517,12 +517,19 @@ inline bool Divc(InterpState &S, CodePtr OpPC) {

// Den = real(RHS)² + imag(RHS)²
T A, B;
if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B))
return false;
if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {
// Ignore overflow here, because that's what the current interpeter does.
}
T Den;
if (T::add(A, B, Bits, &Den))
return false;

if (Compare(Den, Zero) == ComparisonCategoryResult::Equal) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_expr_divide_by_zero);
return false;
}

// real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
T &ResultR = Result.atIndex(0).deref<T>();
T &ResultI = Result.atIndex(1).deref<T>();
Expand Down Expand Up @@ -2537,7 +2544,7 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
return false;

if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
S.Stk.push<Pointer>(Ptr.atIndex(0));
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ComputeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ ExprDependence clang::computeDependence(BinaryOperator *E) {
ExprDependence clang::computeDependence(ConditionalOperator *E) {
// The type of the conditional operator depends on the type of the conditional
// to support the GCC vector conditional extension. Additionally,
// [temp.dep.expr] does specify state that this should be dependent on ALL sub
// [temp.dep.expr] does specify that this should be dependent on ALL sub
// expressions.
return E->getCond()->getDependence() | E->getLHS()->getDependence() |
E->getRHS()->getDependence();
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2799,9 +2799,17 @@ bool VarDecl::isKnownToBeDefined() const {
}

bool VarDecl::isNoDestroy(const ASTContext &Ctx) const {
return hasGlobalStorage() && (hasAttr<NoDestroyAttr>() ||
(!Ctx.getLangOpts().RegisterStaticDestructors &&
!hasAttr<AlwaysDestroyAttr>()));
if (!hasGlobalStorage())
return false;
if (hasAttr<NoDestroyAttr>())
return true;
if (hasAttr<AlwaysDestroyAttr>())
return false;

using RSDKind = LangOptions::RegisterStaticDestructorsKind;
RSDKind K = Ctx.getLangOpts().getRegisterStaticDestructors();
return K == RSDKind::None ||
(K == RSDKind::ThreadLocal && getTLSKind() == TLS_None);
}

QualType::DestructionKind
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/DirectX.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
}

void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override {
TargetInfo::adjust(Diags, Opts);
// The static values this addresses do not apply outside of the same thread
// This protection is neither available nor needed
Opts.ThreadsafeStatics = false;
}
};

} // namespace targets
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20344,6 +20344,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
case NVPTX::BI__nvvm_atom_min_gen_ull:
return MakeBinaryAtomicValue(*this, llvm::AtomicRMWInst::UMin, E);

case NVPTX::BI__nvvm_atom_cas_gen_us:
case NVPTX::BI__nvvm_atom_cas_gen_i:
case NVPTX::BI__nvvm_atom_cas_gen_l:
case NVPTX::BI__nvvm_atom_cas_gen_ll:
Expand Down Expand Up @@ -20535,6 +20536,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
case NVPTX::BI__nvvm_atom_sys_xor_gen_l:
case NVPTX::BI__nvvm_atom_sys_xor_gen_ll:
return MakeScopedAtomic(Intrinsic::nvvm_atomic_xor_gen_i_sys, *this, E);
case NVPTX::BI__nvvm_atom_cta_cas_gen_us:
case NVPTX::BI__nvvm_atom_cta_cas_gen_i:
case NVPTX::BI__nvvm_atom_cta_cas_gen_l:
case NVPTX::BI__nvvm_atom_cta_cas_gen_ll: {
Expand All @@ -20546,6 +20548,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
Intrinsic::nvvm_atomic_cas_gen_i_cta, {ElemTy, Ptr->getType()}),
{Ptr, EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2))});
}
case NVPTX::BI__nvvm_atom_sys_cas_gen_us:
case NVPTX::BI__nvvm_atom_sys_cas_gen_i:
case NVPTX::BI__nvvm_atom_sys_cas_gen_l:
case NVPTX::BI__nvvm_atom_sys_cas_gen_ll: {
Expand Down
24 changes: 12 additions & 12 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4455,12 +4455,13 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
if (getTarget().supportsIFunc()) {
llvm::GlobalValue::LinkageTypes Linkage = getMultiversionLinkage(*this, GD);
auto *IFunc = cast<llvm::GlobalValue>(GetOrCreateMultiVersionResolver(GD));
unsigned AS = IFunc->getType()->getPointerAddressSpace();

// Fix up function declarations that were created for cpu_specific before
// cpu_dispatch was known
if (!isa<llvm::GlobalIFunc>(IFunc)) {
auto *GI = llvm::GlobalIFunc::create(DeclTy, 0, Linkage, "", ResolverFunc,
&getModule());
auto *GI = llvm::GlobalIFunc::create(DeclTy, AS, Linkage, "",
ResolverFunc, &getModule());
replaceDeclarationWith(IFunc, GI);
IFunc = GI;
}
Expand All @@ -4469,8 +4470,8 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
*this, GD, FD, /*OmitMultiVersionMangling=*/true);
llvm::Constant *AliasFunc = GetGlobalValue(AliasName);
if (!AliasFunc) {
auto *GA = llvm::GlobalAlias::create(DeclTy, 0, Linkage, AliasName, IFunc,
&getModule());
auto *GA = llvm::GlobalAlias::create(DeclTy, AS, Linkage, AliasName,
IFunc, &getModule());
SetCommonAttributes(GD, GA);
}
}
Expand Down Expand Up @@ -4542,15 +4543,14 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
// For cpu_specific, don't create an ifunc yet because we don't know if the
// cpu_dispatch will be emitted in this translation unit.
if (getTarget().supportsIFunc() && !FD->isCPUSpecificMultiVersion()) {
llvm::Type *ResolverType = llvm::FunctionType::get(
llvm::PointerType::get(DeclTy,
getTypes().getTargetAddressSpace(FD->getType())),
false);
unsigned AS = getTypes().getTargetAddressSpace(FD->getType());
llvm::Type *ResolverType =
llvm::FunctionType::get(llvm::PointerType::get(DeclTy, AS), false);
llvm::Constant *Resolver = GetOrCreateLLVMFunction(
MangledName + ".resolver", ResolverType, GlobalDecl{},
/*ForVTable=*/false);
llvm::GlobalIFunc *GIF =
llvm::GlobalIFunc::create(DeclTy, 0, getMultiversionLinkage(*this, GD),
llvm::GlobalIFunc::create(DeclTy, AS, getMultiversionLinkage(*this, GD),
"", Resolver, &getModule());
GIF->setName(ResolverName);
SetCommonAttributes(FD, GIF);
Expand Down Expand Up @@ -6160,9 +6160,9 @@ void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) {
GetOrCreateLLVMFunction(IFA->getResolver(), VoidTy, {},
/*ForVTable=*/false);
llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType());
llvm::GlobalIFunc *GIF =
llvm::GlobalIFunc::create(DeclTy, 0, llvm::Function::ExternalLinkage,
"", Resolver, &getModule());
unsigned AS = getTypes().getTargetAddressSpace(D->getType());
llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create(
DeclTy, AS, llvm::Function::ExternalLinkage, "", Resolver, &getModule());
if (Entry) {
if (GIF->getResolver() == Entry) {
Diags.Report(IFA->getLocation(), diag::err_cyclic_alias) << 1;
Expand Down
14 changes: 7 additions & 7 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,18 @@ getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) {
}

// static
std::string Driver::GetResourcesPath(StringRef BinaryPath,
StringRef CustomResourceDir) {
std::string Driver::GetResourcesPath(StringRef BinaryPath) {
// Since the resource directory is embedded in the module hash, it's important
// that all places that need it call this function, so that they get the
// exact same string ("a/../b/" and "b/" get different hashes, for example).

// Dir is bin/ or lib/, depending on where BinaryPath is.
std::string Dir = std::string(llvm::sys::path::parent_path(BinaryPath));

StringRef Dir = llvm::sys::path::parent_path(BinaryPath);
SmallString<128> P(Dir);
if (CustomResourceDir != "") {
llvm::sys::path::append(P, CustomResourceDir);

StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR);
if (!ConfiguredResourceDir.empty()) {
llvm::sys::path::append(P, ConfiguredResourceDir);
} else {
// On Windows, libclang.dll is in bin/.
// On non-Windows, libclang.so/.dylib is in lib/.
Expand Down Expand Up @@ -239,7 +239,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
#endif

// Compute the path to the resource directory.
ResourceDir = GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR);
ResourceDir = GetResourcesPath(ClangExecutable);
}

void Driver::setDriverMode(StringRef Value) {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7972,8 +7972,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_keep_persistent_storage_variables);
Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers,
options::OPT_fno_complete_member_pointers);
Args.addOptOutFlag(CmdArgs, options::OPT_fcxx_static_destructors,
options::OPT_fno_cxx_static_destructors);
if (Arg *A = Args.getLastArg(options::OPT_cxx_static_destructors_EQ))
A->render(Args, CmdArgs);

addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false);

Expand Down
4 changes: 1 addition & 3 deletions clang/lib/ExtractAPI/DeclarationFragments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1327,14 +1327,12 @@ DeclarationFragmentsBuilder::getFragmentsForFunctionTemplateSpecialization(

DeclarationFragments
DeclarationFragmentsBuilder::getFragmentsForMacro(StringRef Name,
const MacroDirective *MD) {
const MacroInfo *MI) {
DeclarationFragments Fragments;
Fragments.append("#define", DeclarationFragments::FragmentKind::Keyword)
.appendSpace();
Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier);

auto *MI = MD->getMacroInfo();

if (MI->isFunctionLike()) {
Fragments.append("(", DeclarationFragments::FragmentKind::Text);
unsigned numParameters = MI->getNumParams();
Expand Down
90 changes: 36 additions & 54 deletions clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,78 +286,59 @@ class MacroCallback : public PPCallbacks {
MacroCallback(const SourceManager &SM, APISet &API, Preprocessor &PP)
: SM(SM), API(API), PP(PP) {}

void MacroDefined(const Token &MacroNameToken,
const MacroDirective *MD) override {
auto *MacroInfo = MD->getMacroInfo();
void EndOfMainFile() override {
for (const auto &M : PP.macros()) {
auto *II = M.getFirst();
auto MD = PP.getMacroDefinition(II);
auto *MI = MD.getMacroInfo();

if (MacroInfo->isBuiltinMacro())
return;
if (!MI)
continue;

auto SourceLoc = MacroNameToken.getLocation();
if (SM.isWrittenInBuiltinFile(SourceLoc) ||
SM.isWrittenInCommandLineFile(SourceLoc))
return;
// Ignore header guard macros
if (MI->isUsedForHeaderGuard())
continue;

PendingMacros.emplace_back(MacroNameToken, MD);
}
// Ignore builtin macros and ones defined via the command line.
if (MI->isBuiltinMacro())
continue;

// If a macro gets undefined at some point during preprocessing of the inputs
// it means that it isn't an exposed API and we should therefore not add a
// macro definition for it.
void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD,
const MacroDirective *Undef) override {
// If this macro wasn't previously defined we don't need to do anything
// here.
if (!Undef)
return;

llvm::erase_if(PendingMacros, [&MD, this](const PendingMacro &PM) {
return MD.getMacroInfo()->isIdenticalTo(*PM.MD->getMacroInfo(), PP,
/*Syntactically*/ false);
});
}
auto DefLoc = MI->getDefinitionLoc();

void EndOfMainFile() override {
for (auto &PM : PendingMacros) {
// `isUsedForHeaderGuard` is only set when the preprocessor leaves the
// file so check for it here.
if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
if (SM.isWrittenInBuiltinFile(DefLoc) ||
SM.isWrittenInCommandLineFile(DefLoc))
continue;

if (!shouldMacroBeIncluded(PM))
auto AssociatedModuleMacros = MD.getModuleMacros();
StringRef OwningModuleName;
if (!AssociatedModuleMacros.empty())
OwningModuleName = AssociatedModuleMacros.back()
->getOwningModule()
->getTopLevelModuleName();

if (!shouldMacroBeIncluded(DefLoc, OwningModuleName))
continue;

StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation());
StringRef Name = II->getName();
PresumedLoc Loc = SM.getPresumedLoc(DefLoc);
SmallString<128> USR;
index::generateUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM,
USR);

index::generateUSRForMacro(Name, DefLoc, SM, USR);
API.createRecord<extractapi::MacroDefinitionRecord>(
USR, Name, SymbolReference(), Loc,
DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD),
DeclarationFragmentsBuilder::getFragmentsForMacro(Name, MI),
DeclarationFragmentsBuilder::getSubHeadingForMacro(Name),
SM.isInSystemHeader(PM.MacroNameToken.getLocation()));
SM.isInSystemHeader(DefLoc));
}

PendingMacros.clear();
}

protected:
struct PendingMacro {
Token MacroNameToken;
const MacroDirective *MD;

PendingMacro(const Token &MacroNameToken, const MacroDirective *MD)
: MacroNameToken(MacroNameToken), MD(MD) {}
};

virtual bool shouldMacroBeIncluded(const PendingMacro &PM) { return true; }
virtual bool shouldMacroBeIncluded(const SourceLocation &MacroLoc,
StringRef ModuleName) {
return true;
}

const SourceManager &SM;
APISet &API;
Preprocessor &PP;
llvm::SmallVector<PendingMacro> PendingMacros;
};

class APIMacroCallback : public MacroCallback {
Expand All @@ -366,9 +347,10 @@ class APIMacroCallback : public MacroCallback {
LocationFileChecker &LCF)
: MacroCallback(SM, API, PP), LCF(LCF) {}

bool shouldMacroBeIncluded(const PendingMacro &PM) override {
bool shouldMacroBeIncluded(const SourceLocation &MacroLoc,
StringRef ModuleName) override {
// Do not include macros from external files
return LCF(PM.MacroNameToken.getLocation());
return LCF(MacroLoc) || API.ProductName == ModuleName;
}

private:
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,8 +928,8 @@ bool SymbolGraphSerializer::traverseObjCCategoryRecord(
return true;

auto *CurrentModule = ModuleForCurrentSymbol;
if (Record->isExtendingExternalModule())
ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source];
if (auto ModuleExtendedByRecord = Record->getExtendedExternalModule())
ModuleForCurrentSymbol = &ExtendedModules[*ModuleExtendedByRecord];

if (!walkUpFromObjCCategoryRecord(Record))
return false;
Expand Down
10 changes: 4 additions & 6 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -894,10 +894,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
CurrentState.ContainsUnwrappedBuilder = true;
}

if (Current.is(TT_TrailingReturnArrow) &&
Style.Language == FormatStyle::LK_Java) {
if (Current.is(TT_LambdaArrow) && Style.Language == FormatStyle::LK_Java)
CurrentState.NoLineBreak = true;
}
if (Current.isMemberAccess() && Previous.is(tok::r_paren) &&
(Previous.MatchingParen &&
(Previous.TotalLength - Previous.MatchingParen->TotalLength > 10))) {
Expand Down Expand Up @@ -1052,7 +1050,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
//
// is common and should be formatted like a free-standing function. The same
// goes for wrapping before the lambda return type arrow.
if (Current.isNot(TT_TrailingReturnArrow) &&
if (Current.isNot(TT_LambdaArrow) &&
(!Style.isJavaScript() || Current.NestingLevel != 0 ||
!PreviousNonComment || PreviousNonComment->isNot(tok::equal) ||
!Current.isOneOf(Keywords.kw_async, Keywords.kw_function))) {
Expand Down Expand Up @@ -1312,7 +1310,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
}
return CurrentState.Indent;
}
if (Current.is(TT_TrailingReturnArrow) &&
if (Current.is(TT_LambdaArrow) &&
Previous.isOneOf(tok::kw_noexcept, tok::kw_mutable, tok::kw_constexpr,
tok::kw_consteval, tok::kw_static, TT_AttributeSquare)) {
return ContinuationIndent;
Expand Down Expand Up @@ -1646,7 +1644,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
}
if (Current.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && Newline)
CurrentState.NestedBlockIndent = State.Column + Current.ColumnWidth + 1;
if (Current.isOneOf(TT_LambdaLSquare, TT_TrailingReturnArrow))
if (Current.isOneOf(TT_LambdaLSquare, TT_LambdaArrow))
CurrentState.LastSpace = State.Column;
if (Current.is(TT_RequiresExpression) &&
Style.RequiresExpressionIndentation == FormatStyle::REI_Keyword) {
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace format {
TYPE(JsTypeColon) \
TYPE(JsTypeOperator) \
TYPE(JsTypeOptionalQuestion) \
TYPE(LambdaArrow) \
TYPE(LambdaDefinitionLParen) \
TYPE(LambdaLBrace) \
TYPE(LambdaLSquare) \
Expand Down Expand Up @@ -726,7 +727,7 @@ struct FormatToken {
bool isMemberAccess() const {
return isOneOf(tok::arrow, tok::period, tok::arrowstar) &&
!isOneOf(TT_DesignatedInitializerPeriod, TT_TrailingReturnArrow,
TT_LeadingJavaAnnotation);
TT_LambdaArrow, TT_LeadingJavaAnnotation);
}

bool isPointerOrReference() const {
Expand Down
37 changes: 21 additions & 16 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@ class AnnotatingParser {
}
// An arrow after an ObjC method expression is not a lambda arrow.
if (CurrentToken->is(TT_ObjCMethodExpr) && CurrentToken->Next &&
CurrentToken->Next->is(TT_TrailingReturnArrow)) {
CurrentToken->Next->is(TT_LambdaArrow)) {
CurrentToken->Next->overwriteFixedType(TT_Unknown);
}
Left->MatchingParen = CurrentToken;
Expand Down Expand Up @@ -1770,8 +1770,10 @@ class AnnotatingParser {
}
break;
case tok::arrow:
if (Tok->Previous && Tok->Previous->is(tok::kw_noexcept))
if (Tok->isNot(TT_LambdaArrow) && Tok->Previous &&
Tok->Previous->is(tok::kw_noexcept)) {
Tok->setType(TT_TrailingReturnArrow);
}
break;
case tok::equal:
// In TableGen, there must be a value after "=";
Expand Down Expand Up @@ -2057,11 +2059,11 @@ class AnnotatingParser {
TT_LambdaLSquare, TT_LambdaLBrace, TT_AttributeMacro, TT_IfMacro,
TT_ForEachMacro, TT_TypenameMacro, TT_FunctionLBrace,
TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_FatArrow,
TT_NamespaceMacro, TT_OverloadedOperator, TT_RegexLiteral,
TT_TemplateString, TT_ObjCStringLiteral, TT_UntouchableMacroFunc,
TT_StatementAttributeLikeMacro, TT_FunctionLikeOrFreestandingMacro,
TT_ClassLBrace, TT_EnumLBrace, TT_RecordLBrace, TT_StructLBrace,
TT_UnionLBrace, TT_RequiresClause,
TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator,
TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral,
TT_UntouchableMacroFunc, TT_StatementAttributeLikeMacro,
TT_FunctionLikeOrFreestandingMacro, TT_ClassLBrace, TT_EnumLBrace,
TT_RecordLBrace, TT_StructLBrace, TT_UnionLBrace, TT_RequiresClause,
TT_RequiresClauseInARequiresExpression, TT_RequiresExpression,
TT_RequiresExpressionLParen, TT_RequiresExpressionLBrace,
TT_BracedListLBrace)) {
Expand Down Expand Up @@ -2247,7 +2249,7 @@ class AnnotatingParser {
Contexts.back().IsExpression = true;
} else if (Current.is(TT_TrailingReturnArrow)) {
Contexts.back().IsExpression = false;
} else if (Current.is(Keywords.kw_assert)) {
} else if (Current.isOneOf(TT_LambdaArrow, Keywords.kw_assert)) {
Contexts.back().IsExpression = Style.Language == FormatStyle::LK_Java;
} else if (Current.Previous &&
Current.Previous->is(TT_CtorInitializerColon)) {
Expand Down Expand Up @@ -2382,7 +2384,7 @@ class AnnotatingParser {
AutoFound = true;
} else if (Current.is(tok::arrow) &&
Style.Language == FormatStyle::LK_Java) {
Current.setType(TT_TrailingReturnArrow);
Current.setType(TT_LambdaArrow);
} else if (Current.is(tok::arrow) && Style.isVerilog()) {
// The implication operator.
Current.setType(TT_BinaryOperator);
Expand Down Expand Up @@ -3288,7 +3290,7 @@ class ExpressionParser {
}
if (Current->is(TT_JsComputedPropertyName))
return prec::Assignment;
if (Current->is(TT_TrailingReturnArrow))
if (Current->is(TT_LambdaArrow))
return prec::Comma;
if (Current->is(TT_FatArrow))
return prec::Assignment;
Expand Down Expand Up @@ -4213,7 +4215,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
}
if (Right.is(TT_PointerOrReference))
return 190;
if (Right.is(TT_TrailingReturnArrow))
if (Right.is(TT_LambdaArrow))
return 110;
if (Left.is(tok::equal) && Right.is(tok::l_brace))
return 160;
Expand Down Expand Up @@ -4732,7 +4734,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Left.isOneOf(tok::kw_new, tok::kw_delete) &&
Right.isNot(TT_OverloadedOperatorLParen) &&
!(Line.MightBeFunctionDecl && Left.is(TT_FunctionDeclarationName))) {
return Style.SpaceBeforeParensOptions.AfterPlacementOperator;
const auto *RParen = Right.MatchingParen;
return Style.SpaceBeforeParensOptions.AfterPlacementOperator ||
(RParen && RParen->is(TT_CastRParen));
}
if (Line.Type == LT_ObjCDecl)
return true;
Expand Down Expand Up @@ -5291,9 +5295,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return false;
}

if (Right.is(TT_TrailingReturnArrow) || Left.is(TT_TrailingReturnArrow))
if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) ||
Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow)) {
return true;

}
if (Left.is(tok::comma) && Right.isNot(TT_OverloadedOperatorLParen) &&
// In an unexpanded macro call we only find the parentheses and commas
// in a line; the commas and closing parenthesis do not require a space.
Expand Down Expand Up @@ -6328,8 +6333,8 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
tok::kw_class, tok::kw_struct, tok::comment) ||
Right.isMemberAccess() ||
Right.isOneOf(TT_TrailingReturnArrow, tok::lessless, tok::colon,
tok::l_square, tok::at) ||
Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow, tok::lessless,
tok::colon, tok::l_square, tok::at) ||
(Left.is(tok::r_paren) &&
Right.isOneOf(tok::identifier, tok::kw_const)) ||
(Left.is(tok::l_paren) && Right.isNot(tok::r_paren)) ||
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2326,7 +2326,7 @@ bool UnwrappedLineParser::tryToParseLambda() {
// This might or might not actually be a lambda arrow (this could be an
// ObjC method invocation followed by a dereferencing arrow). We might
// reset this back to TT_Unknown in TokenAnnotator.
FormatTok->setFinalizedType(TT_TrailingReturnArrow);
FormatTok->setFinalizedType(TT_LambdaArrow);
SeenArrow = true;
nextToken();
break;
Expand Down Expand Up @@ -3992,6 +3992,9 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
auto IsNonMacroIdentifier = [](const FormatToken *Tok) {
return Tok->is(tok::identifier) && Tok->TokenText != Tok->TokenText.upper();
};
// JavaScript/TypeScript supports anonymous classes like:
// a = class extends foo { }
bool JSPastExtendsOrImplements = false;
// The actual identifier can be a nested name specifier, and in macros
// it is often token-pasted.
// An [[attribute]] can be before the identifier.
Expand All @@ -4002,6 +4005,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
FormatTok->isOneOf(tok::period, tok::comma))) {
if (Style.isJavaScript() &&
FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
JSPastExtendsOrImplements = true;
// JavaScript/TypeScript supports inline object types in
// extends/implements positions:
// class Foo implements {bar: number} { }
Expand All @@ -4027,8 +4031,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
case tok::coloncolon:
break;
default:
if (!ClassName && Previous->is(tok::identifier) &&
Previous->isNot(TT_AttributeMacro)) {
if (!JSPastExtendsOrImplements && !ClassName &&
Previous->is(tok::identifier) && Previous->isNot(TT_AttributeMacro)) {
ClassName = Previous;
}
}
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Format/WhitespaceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,9 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
// except if the token is equal, then a space is needed.
if ((Style.PointerAlignment == FormatStyle::PAS_Right ||
Style.ReferenceAlignment == FormatStyle::RAS_Right) &&
CurrentChange.Spaces != 0 && CurrentChange.Tok->isNot(tok::equal)) {
CurrentChange.Spaces != 0 &&
!CurrentChange.Tok->isOneOf(tok::equal, tok::r_paren,
TT_TemplateCloser)) {
const bool ReferenceNotRightAligned =
Style.ReferenceAlignment != FormatStyle::RAS_Right &&
Style.ReferenceAlignment != FormatStyle::RAS_Pointer;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3130,7 +3130,7 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
void *MainAddr) {
std::string ClangExecutable =
llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
return Driver::GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR);
return Driver::GetResourcesPath(ClangExecutable);
}

static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts,
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Headers/__clang_cuda_device_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,20 @@ __DEVICE__ void __threadfence(void) { __nvvm_membar_gl(); }
__DEVICE__ void __threadfence_block(void) { __nvvm_membar_cta(); };
__DEVICE__ void __threadfence_system(void) { __nvvm_membar_sys(); };
__DEVICE__ void __trap(void) { __asm__ __volatile__("trap;"); }
__DEVICE__ unsigned short
__usAtomicCAS(unsigned short *__p, unsigned short __cmp, unsigned short __v) {
return __nvvm_atom_cas_gen_us(__p, __cmp, __v);
}
__DEVICE__ unsigned short __usAtomicCAS_block(unsigned short *__p,
unsigned short __cmp,
unsigned short __v) {
return __nvvm_atom_cta_cas_gen_us(__p, __cmp, __v);
}
__DEVICE__ unsigned short __usAtomicCAS_system(unsigned short *__p,
unsigned short __cmp,
unsigned short __v) {
return __nvvm_atom_sys_cas_gen_us(__p, __cmp, __v);
}
__DEVICE__ unsigned int __uAtomicAdd(unsigned int *__p, unsigned int __v) {
return __nvvm_atom_add_gen_i((int *)__p, __v);
}
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2954,8 +2954,6 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
}
break;
}
case OMPD_reverse:
case OMPD_interchange:
case OMPD_declare_target: {
SourceLocation DTLoc = ConsumeAnyToken();
bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);
Expand Down
53 changes: 53 additions & 0 deletions clang/lib/Sema/SemaAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,59 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
inferGslPointerAttribute(Record, Record);
}

void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
if (FD->getNumParams() == 0)
return;

if (unsigned BuiltinID = FD->getBuiltinID()) {
// Add lifetime attribute to std::move, std::fowrard et al.
switch (BuiltinID) {
case Builtin::BIaddressof:
case Builtin::BI__addressof:
case Builtin::BI__builtin_addressof:
case Builtin::BIas_const:
case Builtin::BIforward:
case Builtin::BIforward_like:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
if (ParmVarDecl *P = FD->getParamDecl(0u);
!P->hasAttr<LifetimeBoundAttr>())
P->addAttr(
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
break;
default:
break;
}
return;
}
if (auto *CMD = dyn_cast<CXXMethodDecl>(FD)) {
const auto *CRD = CMD->getParent();
if (!CRD->isInStdNamespace() || !CRD->getIdentifier())
return;

if (isa<CXXConstructorDecl>(CMD)) {
auto *Param = CMD->getParamDecl(0);
if (Param->hasAttr<LifetimeBoundAttr>())
return;
if (CRD->getName() == "basic_string_view" &&
Param->getType()->isPointerType()) {
// construct from a char array pointed by a pointer.
// basic_string_view(const CharT* s);
// basic_string_view(const CharT* s, size_type count);
Param->addAttr(
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
} else if (CRD->getName() == "span") {
// construct from a reference of array.
// span(std::type_identity_t<element_type> (&arr)[N]);
const auto *LRT = Param->getType()->getAs<LValueReferenceType>();
if (LRT && LRT->getPointeeType().IgnoreParens()->isArrayType())
Param->addAttr(
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
}
}
}
}

void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
static const llvm::StringSet<> Nullable{
"auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",
Expand Down
20 changes: 1 addition & 19 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16608,27 +16608,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
default:
break;
}

// Add lifetime attribute to std::move, std::fowrard et al.
switch (BuiltinID) {
case Builtin::BIaddressof:
case Builtin::BI__addressof:
case Builtin::BI__builtin_addressof:
case Builtin::BIas_const:
case Builtin::BIforward:
case Builtin::BIforward_like:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
if (ParmVarDecl *P = FD->getParamDecl(0u);
!P->hasAttr<LifetimeBoundAttr>())
P->addAttr(
LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
break;
default:
break;
}
}

inferLifetimeBoundAttribute(FD);
AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);

// If C++ exceptions are enabled but we are told extern "C" functions cannot
Expand Down
17 changes: 14 additions & 3 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17463,11 +17463,22 @@ static void RemoveNestedImmediateInvocation(
ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) {
if (!Init)
return Init;

// We cannot use IgnoreImpCasts because we need to preserve
// full expressions.
while (true) {
if (auto *ICE = dyn_cast<ImplicitCastExpr>(Init))
Init = ICE->getSubExpr();
else if (auto *ICE = dyn_cast<MaterializeTemporaryExpr>(Init))
Init = ICE->getSubExpr();
else
break;
}
/// ConstantExpr are the first layer of implicit node to be removed so if
/// Init isn't a ConstantExpr, no ConstantExpr will be skipped.
if (auto *CE = dyn_cast<ConstantExpr>(Init))
if (CE->isImmediateInvocation())
RemoveImmediateInvocation(CE);
if (auto *CE = dyn_cast<ConstantExpr>(Init);
CE && CE->isImmediateInvocation())
RemoveImmediateInvocation(CE);
return Base::TransformInitializer(Init, NotCopyInit);
}
ExprResult TransformDeclRefExpr(DeclRefExpr *E) {
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/SemaObjC.h"
Expand Down Expand Up @@ -6248,6 +6249,23 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT,
Info) == TemplateDeductionResult::Success;
}
case BTT_IsScalarizedLayoutCompatible: {
if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() &&
Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
diag::err_incomplete_type))
return true;
if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() &&
Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
diag::err_incomplete_type))
return true;

DiagnoseVLAInCXXTypeTrait(
Self, Lhs, tok::kw___builtin_hlsl_is_scalarized_layout_compatible);
DiagnoseVLAInCXXTypeTrait(
Self, Rhs, tok::kw___builtin_hlsl_is_scalarized_layout_compatible);

return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
}
default:
llvm_unreachable("not a BTT");
}
Expand Down
82 changes: 82 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1524,3 +1524,85 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
return false;
}

static void BuildFlattenedTypeList(QualType BaseTy,
llvm::SmallVectorImpl<QualType> &List) {
llvm::SmallVector<QualType, 16> WorkList;
WorkList.push_back(BaseTy);
while (!WorkList.empty()) {
QualType T = WorkList.pop_back_val();
T = T.getCanonicalType().getUnqualifiedType();
assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL");
if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
llvm::SmallVector<QualType, 16> ElementFields;
// Generally I've avoided recursion in this algorithm, but arrays of
// structs could be time-consuming to flatten and churn through on the
// work list. Hopefully nesting arrays of structs containing arrays
// of structs too many levels deep is unlikely.
BuildFlattenedTypeList(AT->getElementType(), ElementFields);
// Repeat the element's field list n times.
for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
List.insert(List.end(), ElementFields.begin(), ElementFields.end());
continue;
}
// Vectors can only have element types that are builtin types, so this can
// add directly to the list instead of to the WorkList.
if (const auto *VT = dyn_cast<VectorType>(T)) {
List.insert(List.end(), VT->getNumElements(), VT->getElementType());
continue;
}
if (const auto *RT = dyn_cast<RecordType>(T)) {
const RecordDecl *RD = RT->getDecl();
if (RD->isUnion()) {
List.push_back(T);
continue;
}
const CXXRecordDecl *CXXD = dyn_cast<CXXRecordDecl>(RD);

llvm::SmallVector<QualType, 16> FieldTypes;
if (CXXD && CXXD->isStandardLayout())
RD = CXXD->getStandardLayoutBaseWithFields();

for (const auto *FD : RD->fields())
FieldTypes.push_back(FD->getType());
// Reverse the newly added sub-range.
std::reverse(FieldTypes.begin(), FieldTypes.end());
WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());

// If this wasn't a standard layout type we may also have some base
// classes to deal with.
if (CXXD && !CXXD->isStandardLayout()) {
FieldTypes.clear();
for (const auto &Base : CXXD->bases())
FieldTypes.push_back(Base.getType());
std::reverse(FieldTypes.begin(), FieldTypes.end());
WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
}
continue;
}
List.push_back(T);
}
}

bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
if (T1.isNull() || T2.isNull())
return false;

T1 = T1.getCanonicalType().getUnqualifiedType();
T2 = T2.getCanonicalType().getUnqualifiedType();

// If both types are the same canonical type, they're obviously compatible.
if (SemaRef.getASTContext().hasSameType(T1, T2))
return true;

llvm::SmallVector<QualType, 16> T1Types;
BuildFlattenedTypeList(T1, T1Types);
llvm::SmallVector<QualType, 16> T2Types;
BuildFlattenedTypeList(T2, T2Types);

// Check the flattened type list
return llvm::equal(T1Types, T2Types,
[this](QualType LHS, QualType RHS) -> bool {
return SemaRef.IsLayoutCompatible(LHS, RHS);
});
}
83 changes: 64 additions & 19 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4091,6 +4091,16 @@ void InitializationSequence::AddParenthesizedListInitStep(QualType T) {
Steps.push_back(S);
}

void InitializationSequence::AddUnwrapInitListInitStep(
InitListExpr *Syntactic) {
assert(Syntactic->getNumInits() == 1 &&
"Can only unwrap trivial init lists.");
Step S;
S.Kind = SK_UnwrapInitList;
S.Type = Syntactic->getInit(0)->getType();
Steps.insert(Steps.begin(), S);
}

void InitializationSequence::RewrapReferenceInitList(QualType T,
InitListExpr *Syntactic) {
assert(Syntactic->getNumInits() == 1 &&
Expand Down Expand Up @@ -4167,6 +4177,33 @@ static void MaybeProduceObjCObject(Sema &S,
}
}

/// Initialize an array from another array
static void TryArrayCopy(Sema &S, const InitializationKind &Kind,
const InitializedEntity &Entity, Expr *Initializer,
QualType DestType, InitializationSequence &Sequence,
bool TreatUnavailableAsInvalid) {
// If source is a prvalue, use it directly.
if (Initializer->isPRValue()) {
Sequence.AddArrayInitStep(DestType, /*IsGNUExtension*/ false);
return;
}

// Emit element-at-a-time copy loop.
InitializedEntity Element =
InitializedEntity::InitializeElement(S.Context, 0, Entity);
QualType InitEltT =
S.Context.getAsArrayType(Initializer->getType())->getElementType();
OpaqueValueExpr OVE(Initializer->getExprLoc(), InitEltT,
Initializer->getValueKind(),
Initializer->getObjectKind());
Expr *OVEAsExpr = &OVE;
Sequence.InitializeFrom(S, Element, Kind, OVEAsExpr,
/*TopLevelOfInitList*/ false,
TreatUnavailableAsInvalid);
if (Sequence)
Sequence.AddArrayInitLoopStep(Entity.getType(), InitEltT);
}

static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expand Down Expand Up @@ -4775,6 +4812,31 @@ static void TryListInitialization(Sema &S,
}
if (const ArrayType *DestAT = S.Context.getAsArrayType(DestType)) {
Expr *SubInit[1] = {InitList->getInit(0)};

// C++17 [dcl.struct.bind]p1:
// ... If the assignment-expression in the initializer has array type A
// and no ref-qualifier is present, e has type cv A and each element is
// copy-initialized or direct-initialized from the corresponding element
// of the assignment-expression as specified by the form of the
// initializer. ...
//
// This is a special case not following list-initialization.
if (isa<ConstantArrayType>(DestAT) &&
Entity.getKind() == InitializedEntity::EK_Variable &&
isa<DecompositionDecl>(Entity.getDecl())) {
assert(
S.Context.hasSameUnqualifiedType(SubInit[0]->getType(), DestType) &&
"Deduced to other type?");
TryArrayCopy(S,
InitializationKind::CreateCopy(Kind.getLocation(),
InitList->getLBraceLoc()),
Entity, SubInit[0], DestType, Sequence,
TreatUnavailableAsInvalid);
if (Sequence)
Sequence.AddUnwrapInitListInitStep(InitList);
return;
}

if (!isa<VariableArrayType>(DestAT) &&
IsStringInit(SubInit[0], DestAT, S.Context) == SIF_None) {
InitializationKind SubKind =
Expand Down Expand Up @@ -6461,25 +6523,8 @@ void InitializationSequence::InitializeFrom(Sema &S,
S.Context.hasSameUnqualifiedType(Initializer->getType(),
Entity.getType()) &&
canPerformArrayCopy(Entity)) {
// If source is a prvalue, use it directly.
if (Initializer->isPRValue()) {
AddArrayInitStep(DestType, /*IsGNUExtension*/false);
return;
}

// Emit element-at-a-time copy loop.
InitializedEntity Element =
InitializedEntity::InitializeElement(S.Context, 0, Entity);
QualType InitEltT =
Context.getAsArrayType(Initializer->getType())->getElementType();
OpaqueValueExpr OVE(Initializer->getExprLoc(), InitEltT,
Initializer->getValueKind(),
Initializer->getObjectKind());
Expr *OVEAsExpr = &OVE;
InitializeFrom(S, Element, Kind, OVEAsExpr, TopLevelOfInitList,
TreatUnavailableAsInvalid);
if (!Failed())
AddArrayInitLoopStep(Entity.getType(), InitEltT);
TryArrayCopy(S, Kind, Entity, Initializer, DestType, *this,
TreatUnavailableAsInvalid);
return;
}

Expand Down
828 changes: 571 additions & 257 deletions clang/lib/Sema/SemaTemplateDeduction.cpp

Large diffs are not rendered by default.

124 changes: 78 additions & 46 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeVisitor.h"
Expand Down Expand Up @@ -88,12 +89,19 @@ struct Response {
// than lambda classes.
const FunctionDecl *
getPrimaryTemplateOfGenericLambda(const FunctionDecl *LambdaCallOperator) {
if (!isLambdaCallOperator(LambdaCallOperator))
return LambdaCallOperator;
while (true) {
if (auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(
LambdaCallOperator->getDescribedTemplate());
FTD && FTD->getInstantiatedFromMemberTemplate()) {
LambdaCallOperator =
FTD->getInstantiatedFromMemberTemplate()->getTemplatedDecl();
} else if (LambdaCallOperator->getPrimaryTemplate()) {
// Cases where the lambda operator is instantiated in
// TemplateDeclInstantiator::VisitCXXMethodDecl.
LambdaCallOperator =
LambdaCallOperator->getPrimaryTemplate()->getTemplatedDecl();
} else if (auto *Prev = cast<CXXMethodDecl>(LambdaCallOperator)
->getInstantiatedFromMemberFunction())
LambdaCallOperator = Prev;
Expand Down Expand Up @@ -139,22 +147,28 @@ getEnclosingTypeAliasTemplateDecl(Sema &SemaRef) {
// Check if we are currently inside of a lambda expression that is
// surrounded by a using alias declaration. e.g.
// template <class> using type = decltype([](auto) { ^ }());
// By checking if:
// 1. The lambda expression and the using alias declaration share the
// same declaration context.
// 2. They have the same template depth.
// We have to do so since a TypeAliasTemplateDecl (or a TypeAliasDecl) is never
// a DeclContext, nor does it have an associated specialization Decl from which
// we could collect these template arguments.
bool isLambdaEnclosedByTypeAliasDecl(
const FunctionDecl *PrimaryLambdaCallOperator,
const FunctionDecl *LambdaCallOperator,
const TypeAliasTemplateDecl *PrimaryTypeAliasDecl) {
return cast<CXXRecordDecl>(PrimaryLambdaCallOperator->getDeclContext())
->getTemplateDepth() ==
PrimaryTypeAliasDecl->getTemplateDepth() &&
getLambdaAwareParentOfDeclContext(
const_cast<FunctionDecl *>(PrimaryLambdaCallOperator)) ==
PrimaryTypeAliasDecl->getDeclContext();
struct Visitor : RecursiveASTVisitor<Visitor> {
Visitor(const FunctionDecl *CallOperator) : CallOperator(CallOperator) {}
bool VisitLambdaExpr(const LambdaExpr *LE) {
// Return true to bail out of the traversal, implying the Decl contains
// the lambda.
return getPrimaryTemplateOfGenericLambda(LE->getCallOperator()) !=
CallOperator;
}
const FunctionDecl *CallOperator;
};

QualType Underlying =
PrimaryTypeAliasDecl->getTemplatedDecl()->getUnderlyingType();

return !Visitor(getPrimaryTemplateOfGenericLambda(LambdaCallOperator))
.TraverseType(Underlying);
}

// Add template arguments from a variable template instantiation.
Expand Down Expand Up @@ -293,23 +307,8 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,

// If this function is a generic lambda specialization, we are done.
if (!ForConstraintInstantiation &&
isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) {
// TypeAliasTemplateDecls should be taken into account, e.g.
// when we're deducing the return type of a lambda.
//
// template <class> int Value = 0;
// template <class T>
// using T = decltype([]<int U = 0>() { return Value<T>; }());
//
if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef)) {
if (isLambdaEnclosedByTypeAliasDecl(
/*PrimaryLambdaCallOperator=*/getPrimaryTemplateOfGenericLambda(
Function),
/*PrimaryTypeAliasDecl=*/TypeAlias.PrimaryTypeAliasDecl))
return Response::UseNextDecl(Function);
}
isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
return Response::Done();
}

} else if (Function->getDescribedFunctionTemplate()) {
assert(
Expand Down Expand Up @@ -421,10 +420,9 @@ Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
// Retrieve the template arguments for a using alias declaration.
// This is necessary for constraint checking, since we always keep
// constraints relative to the primary template.
if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef)) {
const FunctionDecl *PrimaryLambdaCallOperator =
getPrimaryTemplateOfGenericLambda(Rec->getLambdaCallOperator());
if (isLambdaEnclosedByTypeAliasDecl(PrimaryLambdaCallOperator,
if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef);
ForConstraintInstantiation && TypeAlias) {
if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(),
TypeAlias.PrimaryTypeAliasDecl)) {
Result.addOuterTemplateArguments(TypeAlias.Template,
TypeAlias.AssociatedTemplateArguments,
Expand Down Expand Up @@ -1346,15 +1344,21 @@ namespace {
DeclarationName Entity;
// Whether to evaluate the C++20 constraints or simply substitute into them.
bool EvaluateConstraints = true;
// Whether Substitution was Incomplete, that is, we tried to substitute in
// any user provided template arguments which were null.
bool IsIncomplete = false;
// Whether an incomplete substituion should be treated as an error.
bool BailOutOnIncomplete;

public:
typedef TreeTransform<TemplateInstantiator> inherited;

TemplateInstantiator(Sema &SemaRef,
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity)
SourceLocation Loc, DeclarationName Entity,
bool BailOutOnIncomplete = false)
: inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
Entity(Entity) {}
Entity(Entity), BailOutOnIncomplete(BailOutOnIncomplete) {}

void setEvaluateConstraints(bool B) {
EvaluateConstraints = B;
Expand All @@ -1376,6 +1380,9 @@ namespace {
/// Returns the name of the entity being instantiated, if any.
DeclarationName getBaseEntity() { return Entity; }

/// Returns whether any substitution so far was incomplete.
bool getIsIncomplete() const { return IsIncomplete; }

/// Sets the "base" location and entity when that
/// information is known based on another transformation.
void setBase(SourceLocation Loc, DeclarationName Entity) {
Expand Down Expand Up @@ -1422,6 +1429,10 @@ namespace {
if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
Result = TemplateArgs(Depth, Index);
TemplateArgs.setArgument(Depth, Index, TemplateArgument());
} else {
IsIncomplete = true;
if (BailOutOnIncomplete)
return TemplateArgument();
}
}

Expand Down Expand Up @@ -1647,12 +1658,17 @@ namespace {

CXXRecordDecl::LambdaDependencyKind
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
auto &CCS = SemaRef.CodeSynthesisContexts.back();
if (CCS.Kind ==
Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation) {
unsigned TypeAliasDeclDepth = CCS.Entity->getTemplateDepth();
if (auto TypeAlias =
TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
getSema());
TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
for (const TemplateArgument &TA : TypeAlias.AssociatedTemplateArguments)
if (TA.isDependent())
return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
}
return inherited::ComputeLambdaDependency(LSI);
}
Expand Down Expand Up @@ -1817,8 +1833,10 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
// template arguments in a function template, but there were some
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
TTP->getPosition()))
return D;
TTP->getPosition())) {
IsIncomplete = true;
return BailOutOnIncomplete ? nullptr : D;
}

TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());

Expand Down Expand Up @@ -1964,8 +1982,10 @@ TemplateName TemplateInstantiator::TransformTemplateName(
// template arguments in a function template, but there were some
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
TTP->getPosition()))
return Name;
TTP->getPosition())) {
IsIncomplete = true;
return BailOutOnIncomplete ? TemplateName() : Name;
}

TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());

Expand Down Expand Up @@ -2047,8 +2067,10 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
// template arguments in a function template, but there were some
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
NTTP->getPosition()))
return E;
NTTP->getPosition())) {
IsIncomplete = true;
return BailOutOnIncomplete ? ExprError() : E;
}

TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());

Expand Down Expand Up @@ -2467,6 +2489,10 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
// template arguments in a function template class, but there were some
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex())) {
IsIncomplete = true;
if (BailOutOnIncomplete)
return QualType();

TemplateTypeParmTypeLoc NewTL
= TLB.push<TemplateTypeParmTypeLoc>(TL.getType());
NewTL.setNameLoc(TL.getNameLoc());
Expand Down Expand Up @@ -2838,7 +2864,8 @@ TypeSourceInfo *Sema::SubstType(TypeLoc TL,
/// Deprecated form of the above.
QualType Sema::SubstType(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity) {
SourceLocation Loc, DeclarationName Entity,
bool *IsIncompleteSubstitution) {
assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
Expand All @@ -2848,8 +2875,13 @@ QualType Sema::SubstType(QualType T,
if (!T->isInstantiationDependentType() && !T->isVariablyModifiedType())
return T;

TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
return Instantiator.TransformType(T);
TemplateInstantiator Instantiator(
*this, TemplateArgs, Loc, Entity,
/*BailOutOnIncomplete=*/IsIncompleteSubstitution != nullptr);
QualType QT = Instantiator.TransformType(T);
if (IsIncompleteSubstitution && Instantiator.getIsIncomplete())
*IsIncompleteSubstitution = true;
return QT;
}

static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
Expand Down Expand Up @@ -241,12 +242,22 @@ BlockInCriticalSectionChecker::checkDescriptorMatch(const CallEvent &Call,
return std::nullopt;
}

static const MemRegion *skipStdBaseClassRegion(const MemRegion *Reg) {
while (Reg) {
const auto *BaseClassRegion = dyn_cast<CXXBaseObjectRegion>(Reg);
if (!BaseClassRegion || !isWithinStdNamespace(BaseClassRegion->getDecl()))
break;
Reg = BaseClassRegion->getSuperRegion();
}
return Reg;
}

static const MemRegion *getRegion(const CallEvent &Call,
const MutexDescriptor &Descriptor,
bool IsLock) {
return std::visit(
[&Call, IsLock](auto &&Descriptor) {
return Descriptor.getRegion(Call, IsLock);
[&Call, IsLock](auto &Descr) -> const MemRegion * {
return skipStdBaseClassRegion(Descr.getRegion(Call, IsLock));
},
Descriptor);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ bool PlacementNewChecker::checkPlaceCapacityIsSufficient(
"Storage provided to placement new is only {0} bytes, "
"whereas the allocated array type requires more space for "
"internal needs",
SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue()));
SizeOfPlaceCI->getValue()));
else
Msg = std::string(llvm::formatv(
"Storage provided to placement new is only {0} bytes, "
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,14 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
NullConstraint Nullness = getNullConstraint(*RetSVal, State);

Nullability RequiredNullability = getNullabilityAnnotation(RequiredRetType);
if (const auto *FunDecl = C.getLocationContext()->getDecl();
FunDecl && FunDecl->getAttr<ReturnsNonNullAttr>() &&
(RequiredNullability == Nullability::Unspecified ||
RequiredNullability == Nullability::Nullable)) {
// If a function is marked with the returns_nonnull attribute,
// the return value must be non-null.
RequiredNullability = Nullability::Nonnull;
}

// If the returned value is null but the type of the expression
// generating it is nonnull then we will suppress the diagnostic.
Expand All @@ -705,7 +713,7 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
Nullness == NullConstraint::IsNull);
if (ChecksEnabled[CK_NullReturnedFromNonnull] && NullReturnedFromNonNull &&
RetExprTypeLevelNullability != Nullability::Nonnull &&
!InSuppressedMethodFamily && C.getLocationContext()->inTopFrame()) {
!InSuppressedMethodFamily) {
static CheckerProgramPointTag Tag(this, "NullReturnedFromNonnull");
ExplodedNode *N = C.generateErrorNode(State, &Tag);
if (!N)
Expand Down
79 changes: 72 additions & 7 deletions clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,14 @@ static const MemSpaceRegion *getStackOrGlobalSpaceRegion(const MemRegion *R) {
return nullptr;
}

const MemRegion *getOriginBaseRegion(const MemRegion *Reg) {
Reg = Reg->getBaseRegion();
while (const auto *SymReg = dyn_cast<SymbolicRegion>(Reg)) {
Reg = SymReg->getSymbol()->getOriginRegion()->getBaseRegion();
}
return Reg;
}

std::optional<std::string> printReferrer(const MemRegion *Referrer) {
assert(Referrer);
const StringRef ReferrerMemorySpace = [](const MemSpaceRegion *Space) {
Expand All @@ -313,7 +321,8 @@ std::optional<std::string> printReferrer(const MemRegion *Referrer) {
if (isa<GlobalsSpaceRegion>(Space))
return "global";
assert(isa<StackSpaceRegion>(Space));
return "stack";
// This case covers top-level and inlined analyses.
return "caller";
}(getStackOrGlobalSpaceRegion(Referrer));

while (!Referrer->canPrintPretty()) {
Expand All @@ -326,7 +335,6 @@ std::optional<std::string> printReferrer(const MemRegion *Referrer) {
// warn_init_ptr_member_to_parameter_addr
return std::nullopt;
} else {
Referrer->dump();
assert(false && "Unexpected referrer region type.");
return std::nullopt;
}
Expand All @@ -341,19 +349,45 @@ std::optional<std::string> printReferrer(const MemRegion *Referrer) {
return buf;
}

/// Check whether \p Region refers to a freshly minted symbol after an opaque
/// function call.
bool isInvalidatedSymbolRegion(const MemRegion *Region) {
const auto *SymReg = Region->getAs<SymbolicRegion>();
if (!SymReg)
return false;
SymbolRef Symbol = SymReg->getSymbol();

const auto *DerS = dyn_cast<SymbolDerived>(Symbol);
return DerS && isa_and_nonnull<SymbolConjured>(DerS->getParentSymbol());
}

void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
CheckerContext &Ctx) const {
if (!ChecksEnabled[CK_StackAddrEscapeChecker])
return;

ExplodedNode *Node = Ctx.getPredecessor();

bool ExitingTopFrame =
Ctx.getPredecessor()->getLocationContext()->inTopFrame();

if (ExitingTopFrame &&
Node->getLocation().getTag() == ExprEngine::cleanupNodeTag() &&
Node->getFirstPred()) {
// When finishing analysis of a top-level function, engine proactively
// removes dead symbols thus preventing this checker from looking through
// the output parameters. Take 1 step back, to the node where these symbols
// and their bindings are still present
Node = Node->getFirstPred();
}

// Iterate over all bindings to global variables and see if it contains
// a memory region in the stack space.
class CallBack : public StoreManager::BindingsHandler {
private:
CheckerContext &Ctx;
const StackFrameContext *PoppedFrame;
const bool TopFrame;

/// Look for stack variables referring to popped stack variables.
/// Returns true only if it found some dangling stack variables
Expand All @@ -369,24 +403,51 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,

const auto *ReferrerStackSpace =
ReferrerMemSpace->getAs<StackSpaceRegion>();

if (!ReferrerStackSpace)
return false;

if (ReferredMemSpace->getStackFrame() == PoppedFrame &&
ReferrerStackSpace->getStackFrame()->isParentOf(PoppedFrame)) {
if (const auto *ReferredFrame = ReferredMemSpace->getStackFrame();
ReferredFrame != PoppedFrame) {
return false;
}

if (ReferrerStackSpace->getStackFrame()->isParentOf(PoppedFrame)) {
V.emplace_back(Referrer, Referred);
return true;
}
if (isa<StackArgumentsSpaceRegion>(ReferrerMemSpace) &&
ReferrerStackSpace->getStackFrame() == PoppedFrame && TopFrame) {
// Output parameter of a top-level function
V.emplace_back(Referrer, Referred);
return true;
}
return false;
}

// Keep track of the variables that were invalidated through an opaque
// function call. Even if the initial values of such variables were bound to
// an address of a local variable, we cannot claim anything now, at the
// function exit, so skip them to avoid false positives.
void recordInInvalidatedRegions(const MemRegion *Region) {
if (isInvalidatedSymbolRegion(Region))
ExcludedRegions.insert(getOriginBaseRegion(Region));
}

public:
SmallVector<std::pair<const MemRegion *, const MemRegion *>, 10> V;
// ExcludedRegions are skipped from reporting.
// I.e., if a referrer in this set, skip the related bug report.
// It is useful to avoid false positive for the variables that were
// reset to a conjured value after an opaque function call.
llvm::SmallPtrSet<const MemRegion *, 4> ExcludedRegions;

CallBack(CheckerContext &CC) : Ctx(CC), PoppedFrame(CC.getStackFrame()) {}
CallBack(CheckerContext &CC, bool TopFrame)
: Ctx(CC), PoppedFrame(CC.getStackFrame()), TopFrame(TopFrame) {}

bool HandleBinding(StoreManager &SMgr, Store S, const MemRegion *Region,
SVal Val) override {
recordInInvalidatedRegions(Region);
const MemRegion *VR = Val.getAsRegion();
if (!VR)
return true;
Expand All @@ -395,15 +456,16 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
return true;

// Check the globals for the same.
if (!isa<GlobalsSpaceRegion>(Region->getMemorySpace()))
if (!isa_and_nonnull<GlobalsSpaceRegion>(
getStackOrGlobalSpaceRegion(Region)))
return true;
if (VR && VR->hasStackStorage() && !isNotInCurrentFrame(VR, Ctx))
V.emplace_back(Region, VR);
return true;
}
};

CallBack Cb(Ctx);
CallBack Cb(Ctx, ExitingTopFrame);
ProgramStateRef State = Node->getState();
State->getStateManager().getStoreManager().iterBindings(State->getStore(),
Cb);
Expand All @@ -424,6 +486,9 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
for (const auto &P : Cb.V) {
const MemRegion *Referrer = P.first->getBaseRegion();
const MemRegion *Referred = P.second;
if (Cb.ExcludedRegions.contains(getOriginBaseRegion(Referrer))) {
continue;
}

// Generate a report for this bug.
const StringRef CommonSuffix =
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/StaticAnalyzer/Core/BugReporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2436,8 +2436,19 @@ PathSensitiveBugReport::getLocation() const {
if (auto FE = P.getAs<FunctionExitPoint>()) {
if (const ReturnStmt *RS = FE->getStmt())
return PathDiagnosticLocation::createBegin(RS, SM, LC);

// If we are exiting a destructor call, it is more useful to point to the
// next stmt which is usually the temporary declaration.
// For non-destructor and non-top-level calls, the next stmt will still
// refer to the last executed stmt of the body.
S = ErrorNode->getNextStmtForDiagnostics();
// If next stmt is not found, it is likely the end of a top-level function
// analysis. find the last execution statement then.
if (!S)
S = ErrorNode->getPreviousStmtForDiagnostics();
}
S = ErrorNode->getNextStmtForDiagnostics();
if (!S)
S = ErrorNode->getNextStmtForDiagnostics();
}

if (S) {
Expand Down
12 changes: 1 addition & 11 deletions clang/lib/StaticAnalyzer/Core/CallEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
Expand Down Expand Up @@ -923,17 +924,6 @@ SVal AnyCXXConstructorCall::getCXXThisVal() const {
return UnknownVal();
}

static bool isWithinStdNamespace(const Decl *D) {
const DeclContext *DC = D->getDeclContext();
while (DC) {
if (const auto *NS = dyn_cast<NamespaceDecl>(DC);
NS && NS->isStdNamespace())
return true;
DC = DC->getParent();
}
return false;
}

void AnyCXXConstructorCall::getExtraInvalidatedValues(ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const {
SVal V = getCXXThisVal();
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,5 +190,16 @@ std::optional<SVal> getPointeeVal(SVal PtrSVal, ProgramStateRef State) {
return std::nullopt;
}

bool isWithinStdNamespace(const Decl *D) {
const DeclContext *DC = D->getDeclContext();
while (DC) {
if (const auto *NS = dyn_cast<NamespaceDecl>(DC);
NS && NS->isStdNamespace())
return true;
DC = DC->getParent();
}
return false;
}

} // namespace ento
} // namespace clang
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ const Stmt *ExplodedNode::getNextStmtForDiagnostics() const {

const Stmt *ExplodedNode::getPreviousStmtForDiagnostics() const {
for (const ExplodedNode *N = getFirstPred(); N; N = N->getFirstPred())
if (const Stmt *S = N->getStmtForDiagnostics())
if (const Stmt *S = N->getStmtForDiagnostics(); S && !isa<CompoundStmt>(S))
return S;

return nullptr;
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,8 +1072,6 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
CleanedState, SFC, SymReaper);

// Process any special transfer function for dead symbols.
// A tag to track convenience transitions, which can be removed at cleanup.
static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node");
// Call checkers with the non-cleaned state so that they could query the
// values of the soon to be dead symbols.
ExplodedNodeSet CheckedSet;
Expand Down Expand Up @@ -1102,10 +1100,15 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// generate a transition to that state.
ProgramStateRef CleanedCheckerSt =
StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
Bldr.generateNode(DiagnosticStmt, I, CleanedCheckerSt, &cleanupTag, K);
Bldr.generateNode(DiagnosticStmt, I, CleanedCheckerSt, cleanupNodeTag(), K);
}
}

const ProgramPointTag *ExprEngine::cleanupNodeTag() {
static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node");
return &cleanupTag;
}

void ExprEngine::ProcessStmt(const Stmt *currStmt, ExplodedNode *Pred) {
// Reclaim any unnecessary nodes in the ExplodedGraph.
G.reclaimRecentlyAllocatedNodes();
Expand Down
9 changes: 9 additions & 0 deletions clang/test/AST/ByteCode/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,15 @@ namespace Incomplete {
constexpr int C = *F.a; // both-error {{must be initialized by a constant expression}} \
// both-note {{array-to-pointer decay of array member without known bound}}

struct X {
int a;
int b[];
};
extern X x;
constexpr int *xb = x.b; // both-error {{must be initialized by a constant expression}} \
// both-note {{array-to-pointer decay of array member without known bound}}


/// These are from test/SemaCXX/constant-expression-cxx11.cpp
extern int arr[];
constexpr int *c = &arr[1]; // both-error {{must be initialized by a constant expression}} \
Expand Down
3 changes: 3 additions & 0 deletions clang/test/AST/ByteCode/complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ constexpr _Complex float getComplexFloat() {
static_assert(__real(getComplexFloat()) == 1, "");
static_assert(__imag(getComplexFloat()) == 2, "");

constexpr auto GH55390 = 1 / 65536j; // both-note {{division by zero}} \
// both-error {{constexpr variable 'GH55390' must be initialized by a constant expression}}

namespace CastToBool {
constexpr _Complex int F = {0, 1};
static_assert(F, "");
Expand Down
Loading