Skip to content

Commit

Permalink
Vendor import of llvm-project main llvmorg-18-init-15692-g007ed0dccd6a.
Browse files Browse the repository at this point in the history
  • Loading branch information
DimitryAndric committed Dec 25, 2023
1 parent 312c0ed commit 99aabd7
Show file tree
Hide file tree
Showing 989 changed files with 80,005 additions and 92,083 deletions.
27 changes: 2 additions & 25 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,8 @@ class NamedDecl : public Decl {
///
/// \param IsKnownNewer \c true if this declaration is known to be newer
/// than \p OldD (for instance, if this declaration is newly-created).
bool declarationReplaces(NamedDecl *OldD, bool IsKnownNewer = true) const;
bool declarationReplaces(const NamedDecl *OldD,
bool IsKnownNewer = true) const;

/// Determine whether this declaration has linkage.
bool hasLinkage() const;
Expand Down Expand Up @@ -4332,30 +4333,6 @@ class RecordDecl : public TagDecl {
return field_begin() == field_end();
}

FieldDecl *getLastField() {
FieldDecl *FD = nullptr;
for (FieldDecl *Field : fields())
FD = Field;
return FD;
}
const FieldDecl *getLastField() const {
return const_cast<RecordDecl *>(this)->getLastField();
}

template <typename Functor>
const FieldDecl *findFieldIf(Functor &Pred) const {
for (const Decl *D : decls()) {
if (const auto *FD = dyn_cast<FieldDecl>(D); FD && Pred(FD))
return FD;

if (const auto *RD = dyn_cast<RecordDecl>(D))
if (const FieldDecl *FD = RD->findFieldIf(Pred))
return FD;
}

return nullptr;
}

/// Note that the definition of this type is now complete.
virtual void completeDefinition();

Expand Down
10 changes: 0 additions & 10 deletions clang/include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include "clang/AST/SelectorLocationsKind.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/ArrayRef.h"
Expand Down Expand Up @@ -489,15 +488,6 @@ class alignas(8) Decl {
// Return true if this is a FileContext Decl.
bool isFileContextDecl() const;

/// Whether it resembles a flexible array member. This is a static member
/// because we want to be able to call it with a nullptr. That allows us to
/// perform non-Decl specific checks based on the object's type and strict
/// flex array level.
static bool isFlexibleArrayMemberLike(
ASTContext &Context, const Decl *D, QualType Ty,
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
bool IgnoreTemplateOrMacroSubstitution);

ASTContext &getASTContext() const LLVM_READONLY;

/// Helper to get the language options from the ASTContext.
Expand Down
7 changes: 1 addition & 6 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2036,12 +2036,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
/* The partial specialization. */ \
if (TemplateParameterList *TPL = D->getTemplateParameters()) { \
for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); \
I != E; ++I) { \
TRY_TO(TraverseDecl(*I)); \
} \
} \
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \
/* The args that remains unspecialized. */ \
TRY_TO(TraverseTemplateArgumentLocsHelper( \
D->getTemplateArgsAsWritten()->getTemplateArgs(), \
Expand Down
80 changes: 44 additions & 36 deletions clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,22 @@ class Environment {
/// `E` must be a glvalue or a `BuiltinType::BuiltinFn`
StorageLocation *getStorageLocation(const Expr &E) const;

/// Returns the result of casting `getStorageLocation(...)` to a subclass of
/// `StorageLocation` (using `cast_or_null<T>`).
/// This assert-fails if the result of `getStorageLocation(...)` is not of
/// type `T *`; if the storage location is not guaranteed to have type `T *`,
/// consider using `dyn_cast_or_null<T>(getStorageLocation(...))` instead.
template <typename T>
std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
get(const ValueDecl &D) const {
return cast_or_null<T>(getStorageLocation(D));
}
template <typename T>
std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
get(const Expr &E) const {
return cast_or_null<T>(getStorageLocation(E));
}

/// Returns the storage location assigned to the `this` pointee in the
/// environment or null if the `this` pointee has no assigned storage location
/// in the environment.
Expand Down Expand Up @@ -325,7 +341,8 @@ class Environment {
///
/// Requirements:
/// `E` must be a prvalue of record type.
RecordStorageLocation &getResultObjectLocation(const Expr &RecordPRValue);
RecordStorageLocation &
getResultObjectLocation(const Expr &RecordPRValue) const;

/// Returns the return value of the current function. This can be null if:
/// - The function has a void return type
Expand Down Expand Up @@ -434,24 +451,14 @@ class Environment {

/// Assigns `Val` as the value of the prvalue `E` in the environment.
///
/// If `E` is not yet associated with a storage location, associates it with
/// a newly created storage location. In any case, associates the storage
/// location of `E` with `Val`.
///
/// Once the migration to strict handling of value categories is complete
/// (see https://discourse.llvm.org/t/70086), this function will be renamed to
/// `setValue()`. At this point, prvalue expressions will be associated
/// directly with `Value`s, and the legacy behavior of associating prvalue
/// expressions with storage locations (as described above) will be
/// eliminated.
///
/// Requirements:
///
/// `E` must be a prvalue
/// If `Val` is a `RecordValue`, its `RecordStorageLocation` must be the
/// same as that of any `RecordValue` that has already been associated with
/// `E`. This is to guarantee that the result object initialized by a prvalue
/// `RecordValue` has a durable storage location.
/// - `E` must be a prvalue
/// - If `Val` is a `RecordValue`, its `RecordStorageLocation` must be
/// `getResultObjectLocation(E)`. An exception to this is if `E` is an
/// expression that originally creates a `RecordValue` (such as a
/// `CXXConstructExpr` or `CallExpr`), as these establish the location of
/// the result object in the first place.
void setValue(const Expr &E, Value &Val);

/// Returns the value assigned to `Loc` in the environment or null if `Loc`
Expand All @@ -466,6 +473,26 @@ class Environment {
/// storage location in the environment, otherwise returns null.
Value *getValue(const Expr &E) const;

/// Returns the result of casting `getValue(...)` to a subclass of `Value`
/// (using `cast_or_null<T>`).
/// This assert-fails if the result of `getValue(...)` is not of type `T *`;
/// if the value is not guaranteed to have type `T *`, consider using
/// `dyn_cast_or_null<T>(getValue(...))` instead.
template <typename T>
std::enable_if_t<std::is_base_of_v<Value, T>, T *>
get(const StorageLocation &Loc) const {
return cast_or_null<T>(getValue(Loc));
}
template <typename T>
std::enable_if_t<std::is_base_of_v<Value, T>, T *>
get(const ValueDecl &D) const {
return cast_or_null<T>(getValue(D));
}
template <typename T>
std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const Expr &E) const {
return cast_or_null<T>(getValue(E));
}

// FIXME: should we deprecate the following & call arena().create() directly?

/// Creates a `T` (some subclass of `Value`), forwarding `args` to the
Expand Down Expand Up @@ -608,14 +635,6 @@ class Environment {
// The copy-constructor is for use in fork() only.
Environment(const Environment &) = default;

/// Internal version of `setStorageLocation()` that doesn't check if the
/// expression is a prvalue.
void setStorageLocationInternal(const Expr &E, StorageLocation &Loc);

/// Internal version of `getStorageLocation()` that doesn't check if the
/// expression is a prvalue.
StorageLocation *getStorageLocationInternal(const Expr &E) const;

/// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
/// return null.
///
Expand Down Expand Up @@ -708,20 +727,9 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD);

/// Associates a new `RecordValue` with `Loc` and returns the new value.
/// It is not defined whether the field values remain the same or not.
///
/// This function is primarily intended for use by checks that set custom
/// properties on `RecordValue`s to model the state of these values. Such checks
/// should avoid modifying the properties of an existing `RecordValue` because
/// these changes would be visible to other `Environment`s that share the same
/// `RecordValue`. Instead, call `refreshRecordValue()`, then set the properties
/// on the new `RecordValue` that it returns. Typical usage:
///
/// refreshRecordValue(Loc, Env).setProperty("my_prop", MyPropValue);
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);

/// Associates a new `RecordValue` with `Expr` and returns the new value.
/// See also documentation for the overload above.
RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env);

} // namespace dataflow
Expand Down
12 changes: 2 additions & 10 deletions clang/include/clang/Analysis/FlowSensitive/RecordOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,13 @@ namespace dataflow {
/// Copies a record (struct, class, or union) from `Src` to `Dst`.
///
/// This performs a deep copy, i.e. it copies every field (including synthetic
/// fields) and recurses on fields of record type. It also copies properties
/// from the `RecordValue` associated with `Src` to the `RecordValue` associated
/// with `Dst` (if these `RecordValue`s exist).
/// fields) and recurses on fields of record type.
///
/// If there is a `RecordValue` associated with `Dst` in the environment, this
/// function creates a new `RecordValue` and associates it with `Dst`; clients
/// need to be aware of this and must not assume that the `RecordValue`
/// associated with `Dst` remains the same after the call.
///
/// We create a new `RecordValue` rather than modifying properties on the old
/// `RecordValue` because the old `RecordValue` may be shared with other
/// `Environment`s, and we don't want changes to properties to be visible there.
///
/// Requirements:
///
/// `Src` and `Dst` must have the same canonical unqualified type.
Expand All @@ -49,9 +43,7 @@ void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst,
///
/// This performs a deep comparison, i.e. it compares every field (including
/// synthetic fields) and recurses on fields of record type. Fields of reference
/// type compare equal if they refer to the same storage location. If
/// `RecordValue`s are associated with `Loc1` and Loc2`, it also compares the
/// properties on those `RecordValue`s.
/// type compare equal if they refer to the same storage location.
///
/// Note on how to interpret the result:
/// - If this returns true, the records are guaranteed to be equal at runtime.
Expand Down
40 changes: 17 additions & 23 deletions clang/include/clang/Analysis/FlowSensitive/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ class Value {

/// Assigns `Val` as the value of the synthetic property with the given
/// `Name`.
///
/// Properties may not be set on `RecordValue`s; use synthetic fields instead
/// (for details, see documentation for `RecordStorageLocation`).
void setProperty(llvm::StringRef Name, Value &Val) {
assert(getKind() != Kind::Record);
Properties.insert_or_assign(Name, &Val);
}

Expand Down Expand Up @@ -184,33 +188,23 @@ class PointerValue final : public Value {
/// In C++, prvalues of class type serve only a limited purpose: They can only
/// be used to initialize a result object. It is not possible to access member
/// variables or call member functions on a prvalue of class type.
/// Correspondingly, `RecordValue` also serves only two limited purposes:
/// - It conveys a prvalue of class type from the place where the object is
/// constructed to the result object that it initializes.
/// Correspondingly, `RecordValue` also serves only a limited purpose: It
/// conveys a prvalue of class type from the place where the object is
/// constructed to the result object that it initializes.
///
/// When creating a prvalue of class type, we already need a storage location
/// for `this`, even though prvalues are otherwise not associated with storage
/// locations. `RecordValue` is therefore essentially a wrapper for a storage
/// location, which is then used to set the storage location for the result
/// object when we process the AST node for that result object.
/// When creating a prvalue of class type, we already need a storage location
/// for `this`, even though prvalues are otherwise not associated with storage
/// locations. `RecordValue` is therefore essentially a wrapper for a storage
/// location, which is then used to set the storage location for the result
/// object when we process the AST node for that result object.
///
/// For example:
/// MyStruct S = MyStruct(3);
/// For example:
/// MyStruct S = MyStruct(3);
///
/// In this example, `MyStruct(3) is a prvalue, which is modeled as a
/// `RecordValue` that wraps a `RecordStorageLocation`. This
// `RecordStorageLocation` is then used as the storage location for `S`.
/// In this example, `MyStruct(3) is a prvalue, which is modeled as a
/// `RecordValue` that wraps a `RecordStorageLocation`. This
/// `RecordStorageLocation` is then used as the storage location for `S`.
///
/// - It allows properties to be associated with an object of class type.
/// Note that when doing so, you should avoid mutating the properties of an
/// existing `RecordValue` in place, as these changes would be visible to
/// other `Environment`s that share the same `RecordValue`. Instead, associate
/// a new `RecordValue` with the `RecordStorageLocation` and set the
/// properties on this new `RecordValue`. (See also `refreshRecordValue()` in
/// DataflowEnvironment.h, which makes this easy.)
/// Note also that this implies that it is common for the same
/// `RecordStorageLocation` to be associated with different `RecordValue`s
/// in different environments.
/// Over time, we may eliminate `RecordValue` entirely. See also the discussion
/// here: https://reviews.llvm.org/D155204#inline-1503204
class RecordValue final : public Value {
Expand Down
18 changes: 0 additions & 18 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -4331,24 +4331,6 @@ def AvailableOnlyInDefaultEvalMethod : InheritableAttr {
let Documentation = [Undocumented];
}

def CountedBy : InheritableAttr {
let Spellings = [Clang<"counted_by">];
let Subjects = SubjectList<[Field]>;
let Args = [IdentifierArgument<"CountedByField">];
let Documentation = [CountedByDocs];
let LangOpts = [COnly];
// FIXME: This is ugly. Let using a DeclArgument would be nice, but a Decl
// isn't yet available due to the fact that we're still parsing the
// structure. Maybe that code could be changed sometime in the future.
code AdditionalMembers = [{
private:
SourceRange CountedByFieldLoc;
public:
SourceRange getCountedByFieldLoc() const { return CountedByFieldLoc; }
void setCountedByFieldLoc(SourceRange Loc) { CountedByFieldLoc = Loc; }
}];
}

def PreferredType: InheritableAttr {
let Spellings = [Clang<"preferred_type">];
let Subjects = SubjectList<[BitField], ErrorDiag>;
Expand Down
66 changes: 0 additions & 66 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -7500,72 +7500,6 @@ attribute, they default to the value ``65535``.
}];
}

def CountedByDocs : Documentation {
let Category = DocCatField;
let Content = [{
Clang supports the ``counted_by`` attribute on the flexible array member of a
structure in C. The argument for the attribute is the name of a field member in
the same structure holding the count of elements in the flexible array. This
information can be used to improve the results of the array bound sanitizer and
the ``__builtin_dynamic_object_size`` builtin.

For example, the following code:

.. code-block:: c

struct bar;

struct foo {
size_t count;
char other;
struct bar *array[] __attribute__((counted_by(count)));
};

specifies that the flexible array member ``array`` has the number of elements
allocated for it stored in ``count``. This establishes a relationship between
``array`` and ``count``. Specifically, ``p->array`` must have at least
``p->count`` number of elements available. It's the user's responsibility to
ensure that this relationship is maintained through changes to the structure.

In the following example, the allocated array erroneously has fewer elements
than what's specified by ``p->count``. This would result in an out-of-bounds
access not being detected.

.. code-block:: c

#define SIZE_INCR 42

struct foo *p;

void foo_alloc(size_t count) {
p = malloc(MAX(sizeof(struct foo),
offsetof(struct foo, array[0]) + count * sizeof(struct bar *)));
p->count = count + SIZE_INCR;
}

The next example updates ``p->count``, breaking the relationship requirement
that ``p->array`` must have at least ``p->count`` number of elements available:

.. code-block:: c

#define SIZE_INCR 42

struct foo *p;

void foo_alloc(size_t count) {
p = malloc(MAX(sizeof(struct foo),
offsetof(struct foo, array[0]) + count * sizeof(struct bar *)));
p->count = count;
}

void use_foo(int index) {
p->count += SIZE_INCR + 1; /* 'count' is now larger than the number of elements of 'array'. */
p->array[index] = 0; /* the sanitizer can't properly check if this is an out-of-bounds access. */
}

}];
}

def CoroOnlyDestroyWhenCompleteDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
Expand Down
Loading

0 comments on commit 99aabd7

Please sign in to comment.