Table of Contents

Names and scopes

A scope is the region in which a name must be unique. Portable uses a small set of scopes and compares every name case-sensitively.

Global declarations

Named structs, unions, enums, typedef aliases, and #define constants share one global declaration scope. Two of them cannot use the same spelling, even when they are different declaration kinds.

Built-in primitive and string names are reserved in that scope. For example, struct byte { ... }; is rejected so that type lookup cannot interpret byte differently in different operations.

Portable does not implement C's separate tag namespace. A completed declaration is referenced directly:

struct child {
    uint8 value;
};

struct root {
    child item;
};

Fields and union members

Field names are local to their containing struct or union. One container cannot define the same exact spelling twice. A different struct may reuse it, and value remains different from Value.

An inline struct belongs to its containing field:

struct root {
    struct {
        uint8 code;
    } item;
};

The public path is root.item.code. The anonymous inner declaration has no reusable global type name, and - because this declarator has its own name (item) - its member is not promoted to root.code.

Dropping item's own name instead (struct { uint8 code; };, no trailing identifier) makes this an anonymous promoted member: code becomes directly addressable as root.code, and the "one container cannot define the same spelling twice" rule above extends to include every promoted member's own names in that same flat namespace. See inline structs for the full rules.

Enum members

Enum member names are local to the enum. A later member in the same enum may refer to an earlier member in an expression. The member is not exported as a global #define, so another enum or field may use the same spelling.

Typedef struct names

In the supported form:

typedef struct backing {
    uint8 code;
}; packet;

packet is the global type name applications use. backing is retained for diagnostics but is not a second referenceable type. Another typedef-struct declaration may reuse that backing spelling.

Type references and recursion

A field type must be a built-in type or an exported global declaration/alias. An inline declaration cannot be named later as a type.

Recursive by-value storage would have no finite size and is rejected:

struct node {
    node next;
};

Recursion through a pointer to a real named declaration can be finite in the stored layout. Following it remains limited by ReadOptions.

Duplicate or unresolved names fail while constructing CStruct, before a stream or output value is touched.