Skip to main content

Decl

Struct Decl 

Source
pub struct Decl {
Show 18 fields pub name: Option<Symbol>, pub ty: TypeId, pub kind: DeclKind, pub linkage: Linkage, pub duration: StorageDuration, pub state: Definition, pub alignment: Option<u32>, pub constant: bool, pub retained: bool, pub asm_label: Option<StrId>, pub alias: Option<StrId>, pub inline: Emission, pub gnu_inline: bool, pub init: Option<InitList>, pub noreturn: bool, pub visibility: Option<Visibility>, pub params: DeclList, pub body: Option<StmtId>,
}
Expand description

An object or a function, as it was declared.

Fields§

§name: Option<Symbol>

The name, absent for a compound literal and for a parameter that was not given one.

§ty: TypeId

The type, after the adjustments a declaration performs: an array parameter has already become a pointer, and a function parameter a function pointer.

§kind: DeclKind

Whether it is an object or a function.

§linkage: Linkage

Whether the name is shared with other translation units, and how.

§duration: StorageDuration

How long the object lives.

§state: Definition

How much of a definition this declaration is.

§alignment: Option<u32>

The alignment alignas asked for, absent when the type’s own alignment stands.

§constant: bool

Whether constexpr was written, which makes the object a named constant.

C23 6.6p8 puts a named constant of an integer type among the things an integer constant expression may be built out of, and a member of one of a structure or union type with it. That is the whole reason the keyword exists and it is why this is a fact about the declaration rather than something a reader could work out: a const object with a constant initializer is not one of them, so const int n = 1; int a[n]; is a variable length array and the same two lines with constexpr are an array of one.

§retained: bool

Whether an attribute asks for this to exist where nothing in the file refers to it.

used, retain, constructor, destructor and alias each say that something reaches the definition from where the compiler cannot see it, which is the only reason a program ever writes one of them. Nothing else in the tree says that, and a static function nothing refers to is not emitted, so this is how a program keeps one that has to be.

§asm_label: Option<StrId>

The symbol this name stands for in the object file, when a declaration of it wrote an assembler name of its own.

extern int f (int) __asm__ ("g"); says that f here is the symbol g, which is how the C library redirects a name: open under _FILE_OFFSET_BITS=64 is declared this way and reaches open64, and every _FORTIFY_SOURCE wrapper is the same trick. It is a fact about the name rather than about one declaration of it, so it is kept where the declarations of a name are merged, and the first one written is the one that stands.

§alias: Option<StrId>

The symbol this name is a second spelling of, when __attribute__((alias("target"))) was written on a declaration of it.

A declaration with one of these defines the name rather than declaring it: nothing is emitted for the declaration itself and the object file gets a second symbol pointing at whatever the string names. extern int b __attribute__((alias("a"))); is how a program gives a the name b, and weak, alias beside it is the form glibc writes so that a program may define the name itself instead.

The string is the symbol the linker sees rather than an identifier this resolves, which is why it is a StrId and not a Symbol. Whether anything defines it is settled where the whole translation unit is known.

§inline: Emission

Whether a definition of this name here is emitted, which inline is the only thing that changes.

C 6.7.4p7: where every file-scope declaration of a function writes inline and none of them writes extern, the definition in this unit is an inline definition, no external definition is emitted for it, and a call goes to the definition some other unit holds. One declaration without inline, or one with extern, makes the whole thing an external definition again, which is why this is a fact about the name and is settled where the declarations of a name are merged.

The two readings of inline swap over under Self::gnu_inline, where it is the definition alone that decides and extern inline is the one that is not emitted.

§gnu_inline: bool

Whether this name is under GNU’s reading of inline rather than C’s.

__attribute__((__gnu_inline__)) asks for it by name, and the C89 dialects are under it throughout, which is what __GNUC_GNU_INLINE__ tells a header. It is kept because the two readings fold differently over the declarations of a name, and because gcc refuses a name whose declarations disagree about which one they are under.

§init: Option<InitList>

The initializer, flattened, absent when there was none. An empty list is = {}, which C23 added and which zero-initializes, and is not the same as no initializer at all.

§noreturn: bool

Whether control does not come back from a call to this function.

_Noreturn, __attribute__((noreturn)) and [[noreturn]] all say it and all land here. What a caller does with it is put an unreachable after the call, so a program that tests its allocation with if (!p) abort(); stops having a path where the block after the test is reached carrying a null pointer. Nothing else in the compiler can work that out, because what abort does belongs to abort.

A fact about the name rather than about one declaration of it, so one declaration saying it is enough and the merge keeps it. That is the same rule Self::retained is under and it is there for the same reason: the usual place to write it is a header, and the definition in the file below writes nothing.

§visibility: Option<Visibility>

How far outside a shared library the name reaches, when a declaration of it said, and nothing when none did.

__attribute__((visibility("hidden"))) and the other three strings it takes. What is kept here is only what was written, because the other way a name gets a visibility is -fvisibility= and that is a fact about the compilation rather than about the declaration. The two meet where the IR is built, which is also the only place that has both.

A fact about the name rather than about one declaration of it, like Self::asm_label, and merged the way that one is: the first declaration to say something stands. gcc warns and keeps the first when a later one disagrees, since the calls above it have already been compiled against the answer it gave.

§params: DeclList

The parameters of a function definition, in order, and empty for everything else.

A parameter is an object with automatic storage like any other, and the body refers to one the same way it refers to a local. What is different is that nothing in the body declares it, so without this there is no way to ask which objects a definition takes and in what order, which is the first question the walk to the IR has: the entry block’s parameters are these, in this order.

A declaration that is not a definition has none of these even when it was written with a prototype, because int f(int a); declares no object called a. The types are in the function type, which is where a call reads them.

§body: Option<StmtId>

The body of a function definition.

Trait Implementations§

Source§

impl Clone for Decl

Source§

fn clone(&self) -> Decl

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Decl

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Decl

Source§

impl PartialEq for Decl

Source§

fn eq(&self, other: &Decl) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Decl

Auto Trait Implementations§

§

impl Freeze for Decl

§

impl RefUnwindSafe for Decl

§

impl Send for Decl

§

impl Sync for Decl

§

impl Unpin for Decl

§

impl UnsafeUnpin for Decl

§

impl UnwindSafe for Decl

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.