This is attempt 2 to merge this, the first one is #117622. This properly
disables the tests when building for playstation, since the warning is
disabled there.
When a hidden object is built into multiple shared libraries, each
instance of the library will get its own copy. If
the object was supposed to be globally unique (e.g. a global variable or
static data member), this can cause very subtle bugs.
An object might be incorrectly duplicated if it:
Is defined in a header (so it might appear in multiple TUs), and
Has external linkage (otherwise it's supposed to be duplicated), and
Has hidden visibility (or else the dynamic linker will handle it)
The duplication is only a problem semantically if one of the following
is true:
The object is mutable (the copies won't be in sync), or
Its initialization has side effects (it may now run more than once), or
The value of its address is used (different copies have different
addresses).
To detect this, we add a new -Wunique-object-duplication warning. It
warns on cases (1) and (2) above. To be conservative, we only warn in
case (2) if we are certain the initializer has side effects, and we
don't warn on new because the only side effect is some extra memory
usage.
We don't currently warn on case (3) because doing so is prone to false
positives: there are many reasons for taking the address which aren't
inherently problematic (e.g. passing to a function that expects a
pointer). We only run into problems if the code inspects the value of
the address.
The check is currently disabled for windows, which uses its own analogue
of visibility (declimport/declexport). The check is also disabled inside
templates, since it can give false positives if a template is never
instantiated.
Resolving the warning
The warning can be fixed in several ways:
If the object in question doesn't need to be mutable, it should be made
const. Note that the variable must be completely immutable, e.g. we'll
warn on const int* p because the pointer itself is mutable. To silence
the warning, it should instead be const int* const p.
If the object must be mutable, it (or the enclosing function, in the
case of static local variables) should be made visible using
__attribute((visibility("default")))
If the object is supposed to be duplicated, it should be be given
internal linkage.
Testing
I've tested the warning by running it on clang itself, as well as on
chromium. Compiling clang resulted in [10 warnings across 6
files](https://github.com/user-attachments/files/17908069/clang-warnings.txt),
while Chromium resulted in [160 warnings across 85
files](https://github.com/user-attachments/files/17908072/chromium-warnings.txt),
mostly in third-party code. Almost all warnings were due to mutable
variables.
I evaluated the warnings by manual inspection. I believe all the
resulting warnings are true positives, i.e. they represent
potentially-problematic code where duplication might cause a problem.
For the clang warnings, I also validated them by either adding const or
visibility annotations as appropriate.
Limitations
I am aware of four main limitations with the current warning:
We do not warn when the address of a duplicated object is taken, since
doing so is prone to false positives. I'm hopeful that we can create a
refined version in the future, however.
We only warn for side-effectful initialization if we are certain side
effects exist. Warning on potential side effects produced a huge number
of false positives; I don't expect there's much that can be done about
this in modern C++ code bases, since proving a lack of side effects is
difficult.
Windows uses a different system (declexport/import) instead of
visibility. From manual testing, it seems to behave analogously to the
visibility system for the purposes of this warning, but to keep things
simple the warning is disabled on windows for now.
We don't warn on code inside templates. This is unfortuate, since it
masks many real issues, e.g. a templated variable which is implicitly
instantiated the same way in multiple TUs should be globally unique, but
may accidentally be duplicated. Unfortunately, we found some potential
false positives during testing that caused us to disable the warning for
now.
When a hidden object is built into multiple shared libraries, each
instance of the library will get its own copy. If
the object was supposed to be globally unique (e.g. a global variable or
static data member), this can cause very subtle bugs.
An object might be incorrectly duplicated if it:
- Is defined in a header (so it might appear in multiple TUs), and
- Has external linkage (otherwise it's supposed to be duplicated), and
- Has hidden visibility (or else the dynamic linker will handle it)
The duplication is only a problem semantically if one of the following
is true:
1. The object is mutable (the copies won't be in sync), or
2. Its initialization has side effects (it may now run more than once),
or
3. The value of its address is used (different copies have different
addresses).
To detect this, we add a new -Wunique-object-duplication warning. It
warns on cases (1) and (2) above. To be conservative, we only warn in
case (2) if we are certain the initializer has side effects, and we
don't warn on `new` because the only side effect is some extra memory
usage.
We don't currently warn on case (3) because doing so is prone to false
positives: there are many reasons for taking the address which aren't
inherently problematic (e.g. passing to a function that expects a
pointer). We only run into problems if the code inspects the value of
the address.
The check is currently disabled for windows, which uses its own analogue
of visibility (declimport/declexport). The check is also disabled inside
templates, since it can give false positives if a template is never
instantiated.
### Resolving the warning
The warning can be fixed in several ways:
- If the object in question doesn't need to be mutable, it should be
made const. Note that the variable must be completely immutable, e.g.
we'll warn on `const int* p` because the pointer itself is mutable. To
silence the warning, it should instead be `const int* const p`.
- If the object must be mutable, it (or the enclosing function, in the
case of static local variables) should be made visible using
`__attribute((visibility("default")))`
- If the object is supposed to be duplicated, it should be be given
internal linkage.
### Testing
I've tested the warning by running it on clang itself, as well as on
chromium. Compiling clang resulted in [10 warnings across 6
files](https://github.com/user-attachments/files/17908069/clang-warnings.txt),
while Chromium resulted in [160 warnings across 85
files](https://github.com/user-attachments/files/17908072/chromium-warnings.txt),
mostly in third-party code. Almost all warnings were due to mutable
variables.
I evaluated the warnings by manual inspection. I believe all the
resulting warnings are true positives, i.e. they represent
potentially-problematic code where duplication might cause a problem.
For the clang warnings, I also validated them by either adding `const`
or visibility annotations as appropriate.
### Limitations
I am aware of four main limitations with the current warning:
1. We do not warn when the address of a duplicated object is taken,
since doing so is prone to false positives. I'm hopeful that we can
create a refined version in the future, however.
2. We only warn for side-effectful initialization if we are certain side
effects exist. Warning on potential side effects produced a huge number
of false positives; I don't expect there's much that can be done about
this in modern C++ code bases, since proving a lack of side effects is
difficult.
3. Windows uses a different system (declexport/import) instead of
visibility. From manual testing, it seems to behave analogously to the
visibility system for the purposes of this warning, but to keep things
simple the warning is disabled on windows for now.
4. We don't warn on code inside templates. This is unfortuate, since it
masks many real issues, e.g. a templated variable which is implicitly
instantiated the same way in multiple TUs should be globally unique, but
may accidentally be duplicated. Unfortunately, we found some potential
false positives during testing that caused us to disable the warning for
now.
Microsoft allows the 'inline' specifier on a typedef of a function type
in C modes. This is used by a system header (ufxclient.h), so instead
of giving a hard error, we diagnose with a warning. C++ mode and non-
Microsoft compatibility modes are not impacted.
Fixes https://github.com/llvm/llvm-project/issues/124869
Note that PointerUnion::dyn_cast has been soft deprecated in
PointerUnion.h:
// FIXME: Replace the uses of is(), get() and dyn_cast() with
// isa<T>, cast<T> and the llvm::dyn_cast<T>
Literal migration would result in dyn_cast_if_present (see the
definition of PointerUnion::dyn_cast), but this patch uses dyn_cast
because we expect Entry to be nonnull.
HandleImmediateInvocation can call MarkExpressionAsImmediateEscalating
and should always be called before
CheckImmediateEscalatingFunctionDefinition.
However, we were not doing that in `ActFunctionBody`.
Fixes#119046
HandleImmediateInvocation can call MarkExpressionAsImmediateEscalating
and should always be called before
CheckImmediateEscalatingFunctionDefinition.
However, we were not doing that in `ActFunctionBody`.
We simply move CheckImmediateEscalatingFunctionDefinition to
PopExpressionEvaluationContext.
Fixes#119046
Note that PointerUnion::dyn_cast has been soft deprecated in
PointerUnion.h:
// FIXME: Replace the uses of is(), get() and dyn_cast() with
// isa<T>, cast<T> and the llvm::dyn_cast<T>
This patch migrates uses of PointerUnion::dyn_cast to
dyn_cast_if_present (see the definition of PointerUnion::dyn_cast).
Note that we cannot use dyn_cast in any of the migrations in this
patch; placing
assert(!X.isNull());
just before any of dyn_cast_if_present in this patch triggers some
failure in check-clang.
A SYCL kernel entry point function is a non-member function or a static
member function declared with the `sycl_kernel_entry_point` attribute.
Such functions define a pattern for an offload kernel entry point
function to be generated to enable execution of a SYCL kernel on a
device. A SYCL library implementation orchestrates the invocation of
these functions with corresponding SYCL kernel arguments in response to
calls to SYCL kernel invocation functions specified by the SYCL 2020
specification.
The offload kernel entry point function (sometimes referred to as the
SYCL kernel caller function) is generated from the SYCL kernel entry
point function by a transformation of the function parameters followed
by a transformation of the function body to replace references to the
original parameters with references to the transformed ones. Exactly how
parameters are transformed will be explained in a future change that
implements non-trivial transformations. For now, it suffices to state
that a given parameter of the SYCL kernel entry point function may be
transformed to multiple parameters of the offload kernel entry point as
needed to satisfy offload kernel argument passing requirements.
Parameters that are decomposed in this way are reconstituted as local
variables in the body of the generated offload kernel entry point
function.
For example, given the following SYCL kernel entry point function
definition:
```
template<typename KernelNameType, typename KernelType>
[[clang::sycl_kernel_entry_point(KernelNameType)]]
void sycl_kernel_entry_point(KernelType kernel) {
kernel();
}
```
and the following call:
```
struct Kernel {
int dm1;
int dm2;
void operator()() const;
};
Kernel k;
sycl_kernel_entry_point<class kernel_name>(k);
```
the corresponding offload kernel entry point function that is generated
might look as follows (assuming `Kernel` is a type that requires
decomposition):
```
void offload_kernel_entry_point_for_kernel_name(int dm1, int dm2) {
Kernel kernel{dm1, dm2};
kernel();
}
```
Other details of the generated offload kernel entry point function, such
as its name and calling convention, are implementation details that need
not be reflected in the AST and may differ across target devices. For
that reason, only the transformation described above is represented in
the AST; other details will be filled in during code generation.
These transformations are represented using new AST nodes introduced
with this change. `OutlinedFunctionDecl` holds a sequence of
`ImplicitParamDecl` nodes and a sequence of statement nodes that
correspond to the transformed parameters and function body.
`SYCLKernelCallStmt` wraps the original function body and associates it
with an `OutlinedFunctionDecl` instance. For the example above, the AST
generated for the `sycl_kernel_entry_point<kernel_name>` specialization
would look as follows:
```
FunctionDecl 'sycl_kernel_entry_point<kernel_name>(Kernel)'
TemplateArgument type 'kernel_name'
TemplateArgument type 'Kernel'
ParmVarDecl kernel 'Kernel'
SYCLKernelCallStmt
CompoundStmt
<original statements>
OutlinedFunctionDecl
ImplicitParamDecl 'dm1' 'int'
ImplicitParamDecl 'dm2' 'int'
CompoundStmt
VarDecl 'kernel' 'Kernel'
<initialization of 'kernel' with 'dm1' and 'dm2'>
<transformed statements with redirected references of 'kernel'>
```
Any ODR-use of the SYCL kernel entry point function will (with future
changes) suffice for the offload kernel entry point to be emitted. An
actual call to the SYCL kernel entry point function will result in a
call to the function. However, evaluation of a `SYCLKernelCallStmt`
statement is a no-op, so such calls will have no effect other than to
trigger emission of the offload kernel entry point.
Additionally, as a related change inspired by code review feedback,
these changes disallow use of the `sycl_kernel_entry_point` attribute
with functions defined with a _function-try-block_. The SYCL 2020
specification prohibits the use of C++ exceptions in device functions.
Even if exceptions were not prohibited, it is unclear what the semantics
would be for an exception that escapes the SYCL kernel entry point
function; the boundary between host and device code could be an implicit
noexcept boundary that results in program termination if violated, or
the exception could perhaps be propagated to host code via the SYCL
library. Pending support for C++ exceptions in device code and clear
semantics for handling them at the host-device boundary, this change
makes use of the `sycl_kernel_entry_point` attribute with a function
defined with a _function-try-block_ an error.
Note that PointerUnion::dyn_cast has been soft deprecated in
PointerUnion.h:
// FIXME: Replace the uses of is(), get() and dyn_cast() with
// isa<T>, cast<T> and the llvm::dyn_cast<T>
Literal migration would result in dyn_cast_if_present (see the
definition of PointerUnion::dyn_cast), but this patch uses dyn_cast
because we expect EnumUnderlying to be nonnull.
This is a new Clang-specific attribute to ensure that field
initializations are performed explicitly.
For example, if we have
```
struct B {
[[clang::explicit]] int f1;
};
```
then the diagnostic would trigger if we do `B b{};`:
```
field 'f1' is left uninitialized, but was marked as requiring initialization
```
This prevents callers from accidentally forgetting to initialize fields,
particularly when new fields are added to the class.
This partially fixes#62072 by making sure that re-declarations of a
function do not have the effect of removing lifetimebound from the
canonical declaration.
It doesn't handle the implicit 'this' parameter, but that can be
addressed in a separate fix.
CheckFunctionDeclaration emits diagnostics if any SME attributes are used
by a function definition without the required +sme or +sme2 target features.
This patch moves these diagnostics to a new function in SemaARM and
also adds a call to this from ActOnStartOfLambdaDefinition.
The `sycl_kernel_entry_point` attribute is used to declare a function that
defines a pattern for an offload kernel entry point. The attribute requires
a single type argument that specifies a class type that meets the requirements
for a SYCL kernel name as described in section 5.2, "Naming of kernels", of
the SYCL 2020 specification. A unique kernel name type is required for each
function declared with the attribute. The attribute may not first appear on a
declaration that follows a definition of the function. The function is
required to have a non-deduced `void` return type. The function must not be
a non-static member function, be deleted or defaulted, be declared with the
`constexpr` or `consteval` specifiers, be declared with the `[[noreturn]]`
attribute, be a coroutine, or accept variadic arguments.
Diagnostics are not yet provided for the following:
- Use of a type as a kernel name that does not satisfy the forward
declarability requirements specified in section 5.2, "Naming of kernels",
of the SYCL 2020 specification.
- Use of a type as a parameter of the attributed function that does not
satisfy the kernel parameter requirements specified in section 4.12.4,
"Rules for parameter passing to kernels", of the SYCL 2020 specification
(each such function parameter constitutes a kernel parameter).
- Use of language features that are not permitted in device functions as
specified in section 5.4, "Language restrictions for device functions",
of the SYCL 2020 specification.
There are several issues noted by various FIXME comments.
- The diagnostic generated for kernel name conflicts needs additional work
to better detail the relevant source locations; such as the location of
each declaration as well as the original source of each kernel name.
- A number of the tests illustrate spurious errors being produced due to
attributes that appertain to function templates being instantiated too
early (during overload resolution as opposed to after an overload is
selected).
Included changes allow the `SYCLKernelEntryPointAttr` attribute to be
marked as invalid if a `sycl_kernel_entry_point` attribute is used incorrectly.
This is intended to prevent trying to emit an offload kernel entry point
without having to mark the associated function as invalid since doing so
would affect overload resolution; which this attribute should not do.
Unfortunately, Clang eagerly instantiates attributes that appertain to
functions with the result that errors might be issued for function
declarations that are never selected by overload resolution. Tests have
been added to demonstrate this. Further work will be needed to address
these issues (for this and other attributes).
This reverts commit 81fc3add1e627c23b7270fe2739cdacc09063e54.
This breaks some LLDB tests, e.g.
SymbolFile/DWARF/x86/no_unique_address-with-bitfields.cpp:
lldb: ../llvm-project/clang/lib/AST/Decl.cpp:4604: unsigned int clang::FieldDecl::getBitWidthValue() const: Assertion `isa<ConstantExpr>(getBitWidth())' failed.
Save the bitwidth value as a `ConstantExpr` with the value set. Remove
the `ASTContext` parameter from `getBitWidthValue()`, so the latter
simply returns the value from the `ConstantExpr` instead of
constant-evaluating the bitwidth expression every time it is called.
Currently we need at least one more version other than the default to
trigger FMV. However we would like a header file declaration
__attribute__((target_version("default"))) void f(void);
to guarantee that there will be f.default
Since:
commit d076608d58d1ec55016eb747a995511e3a3f72aa
Author: Richard Trieu <rtrieu@google.com>
Date: Sat Dec 8 05:05:03 2018 +0000
clang/AST/CommentDiagnostic.h has been forwarding to
clang/Basic/DiagnosticComment.h. This patch includes
clang/Basic/DiagnosticComment.h instead of
clang/AST/CommentDiagnostic.h.
The NTTP argument appearing inside a trailing return type of a generic
lambda would have us check for potential lambda captures, where the
function needs GLTemplateParameterList of the current LSI to tell
whether the lambda is generic.
The lambda scope in this context is rebuilt by the
LambdaScopeForCallOperatorInstantiationRAII when substituting the lambda
operator during template argument deduction. Thus, I think the template
parameter list should be preserved in the rebuilding process, as it
seems otherwise innocuous to me.
Fixes#115931
Added diagnosis to throw error when zero sized arrays are used in the
HIP device code. SWDEV-449592
---------
Co-authored-by: vigneshwar jayakumar <vigneshwar.jayakumar@amd.com>
Note that PointerUnion::{is,get} have been soft deprecated in
PointerUnion.h:
// FIXME: Replace the uses of is(), get() and dyn_cast() with
// isa<T>, cast<T> and the llvm::dyn_cast<T>
I'm not touching PointerUnion::dyn_cast for now because it's a bit
complicated; we could blindly migrate it to dyn_cast_if_present, but
we should probably use dyn_cast when the operand is known to be
non-null.
This implements the RFC
https://discourse.llvm.org/t/rfc-introduce-clang-lifetime-capture-by-x/81371
In this PR, we introduce `[[clang::lifetime_capture_by(X)]]` attribute
as discussed in the RFC.
As an implementation detail of this attribute, we store and use param
indices instead of raw param expressions. The parameter indices are
computed lazily at the end of function declaration since the function
decl (and therefore the subsequent parameters) are not visible yet while
parsing a parameter annotation.
In subsequent PR, we will infer this attribute for STL containers and
perform lifetime analysis to detect dangling cases.
This paper made empty structures and unions implementation-defined. We
have always supported this as a GNU extension, so now we're documenting
our behavior and removing the extension warning in C2y mode.
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3344.pdf
This paper disallows a single `void` parameter from having qualifiers or
storage class specifiers. Clang has diagnosed most of these as an error
for a long time, but `register void` was previously accepted in all C
language modes and is now being rejected in all C language modes.
LLVM support for the attribute has been implemented already, so it just
plumbs it through to the CUDA front-end.
One notable difference from NVCC is that the attribute can be used
regardless of the targeted GPU. On the older GPUs it will just be
ignored. The attribute is a performance hint, and does not warrant a
hard error if compiler can't benefit from it on a particular GPU
variant.
The `sycl_kernel_entry_point` attribute is used to declare a function that
defines a pattern for an offload kernel to be emitted. The attribute requires
a single type argument that specifies the type used as a SYCL kernel name as
described in section 5.2, "Naming of kernels", of the SYCL 2020 specification.
Properties of the offload kernel are collected when a function declared with
the `sycl_kernel_entry_point` attribute is parsed or instantiated. These
properties, such as the kernel name type, are stored in the AST context where
they are (or will be) used for diagnostic purposes and to facilitate reflection
to a SYCL run-time library. These properties are not serialized with the AST
but are recreated upon deserialization.
The `sycl_kernel_entry_point` attribute is intended to replace the existing
`sycl_kernel` attribute which is intended to be deprecated in a future change
and removed following an appropriate deprecation period. The new attribute
differs in that it is enabled for both SYCL host and device compilation, may
be used with non-template functions, explicitly indicates the type used as
the kernel name type, and will impact AST generation.
This change adds the basic infrastructure for the new attribute. Future
changes will add diagnostics and new AST support that will be used to drive
generation of the corresponding offload kernel.
This patch reapplies #114258, fixing an infinite recursion bug in
`ASTImporter` that occurs when importing the primary template of a class
template specialization when the latest redeclaration of that template
is a friend declaration in the primary template.
This PR resolves a crash triggered by a forward reference to an enum
type in a function parameter list. The fix includes setting `Invalid`
when `TagUseKind` is `Declaration` to ensure correct error handling.
Fixes#112208
Swift ClangImporter now supports concurrency annotations on imported
declarations and their parameters/results, to make it possible to use
imported APIs in Swift safely there has to be a way to annotate
individual parameters and result types with relevant attributes that
indicate that e.g. a block is called on a particular actor or it accepts
a `Sendable` parameter.
To faciliate that `SwiftAttr` is switched from `InheritableAttr` which
is a declaration attribute to `DeclOrTypeAttr`. To support this
attribute in type context we need access to its "Attribute" argument
which requires `AttributedType` to be extended to include `Attr *` when
available instead of just `attr::Kind` otherwise it won't be possible to
determine what attribute should be imported.
This patch fixes a couple of regressions introduced in #111852.
Consider:
```
template<typename T>
struct A
{
template<bool U>
static constexpr bool f() requires U
{
return true;
}
};
template<>
template<bool U>
constexpr bool A<short>::f() requires U
{
return A<long>::f<U>();
}
template<>
template<bool U>
constexpr bool A<long>::f() requires U
{
return true;
}
static_assert(A<short>::f<true>()); // crash here
```
This crashes because when collecting template arguments from the _first_
declaration of `A<long>::f<true>` for constraint checking, we don't add
the template arguments from the enclosing class template specialization
because there exists another redeclaration that is a member
specialization.
This also fixes the following example, which happens for a similar
reason:
```
// input.cppm
export module input;
export template<int N>
constexpr int f();
template<int N>
struct A {
template<int J>
friend constexpr int f();
};
template struct A<0>;
template<int N>
constexpr int f() {
return N;
}
```
```
// input.cpp
import input;
static_assert(f<1>() == 1); // error: static assertion failed
```