55 changes: 46 additions & 9 deletions clang/include/clang/AST/StmtOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
#ifndef LLVM_CLANG_AST_STMTOPENACC_H
#define LLVM_CLANG_AST_STMTOPENACC_H

#include "clang/AST/OpenACCClause.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/OpenACCKinds.h"
#include "clang/Basic/SourceLocation.h"
#include <memory>

namespace clang {
/// This is the base class for an OpenACC statement-level construct, other
Expand All @@ -30,13 +32,23 @@ class OpenACCConstructStmt : public Stmt {
/// the directive.
SourceRange Range;

// TODO OPENACC: Clauses should probably be collected in this class.
/// The list of clauses. This is stored here as an ArrayRef, as this is the
/// most convienient place to access the list, however the list itself should
/// be stored in leaf nodes, likely in trailing-storage.
MutableArrayRef<const OpenACCClause *> Clauses;

protected:
OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K,
SourceLocation Start, SourceLocation End)
: Stmt(SC), Kind(K), Range(Start, End) {}

// Used only for initialization, the leaf class can initialize this to
// trailing storage.
void setClauseList(MutableArrayRef<const OpenACCClause *> NewClauses) {
assert(Clauses.empty() && "Cannot change clause list");
Clauses = NewClauses;
}

public:
OpenACCDirectiveKind getDirectiveKind() const { return Kind; }

Expand All @@ -47,6 +59,7 @@ class OpenACCConstructStmt : public Stmt {

SourceLocation getBeginLoc() const { return Range.getBegin(); }
SourceLocation getEndLoc() const { return Range.getEnd(); }
ArrayRef<const OpenACCClause *> clauses() const { return Clauses; }

child_range children() {
return child_range(child_iterator(), child_iterator());
Expand Down Expand Up @@ -101,24 +114,46 @@ class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt {
/// those three, as they are semantically identical, and have only minor
/// differences in the permitted list of clauses, which can be differentiated by
/// the 'Kind'.
class OpenACCComputeConstruct : public OpenACCAssociatedStmtConstruct {
class OpenACCComputeConstruct final
: public OpenACCAssociatedStmtConstruct,
public llvm::TrailingObjects<OpenACCComputeConstruct,
const OpenACCClause *> {
friend class ASTStmtWriter;
friend class ASTStmtReader;
friend class ASTContext;
OpenACCComputeConstruct()
: OpenACCAssociatedStmtConstruct(
OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid,
SourceLocation{}, SourceLocation{}, /*AssociatedStmt=*/nullptr) {}
OpenACCComputeConstruct(unsigned NumClauses)
: OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass,
OpenACCDirectiveKind::Invalid,
SourceLocation{}, SourceLocation{},
/*AssociatedStmt=*/nullptr) {
// We cannot send the TrailingObjects storage to the base class (which holds
// a reference to the data) until it is constructed, so we have to set it
// separately here.
std::uninitialized_value_construct(
getTrailingObjects<const OpenACCClause *>(),
getTrailingObjects<const OpenACCClause *>() + NumClauses);
setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
NumClauses));
}

OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start,
SourceLocation End, Stmt *StructuredBlock)
SourceLocation End,
ArrayRef<const OpenACCClause *> Clauses,
Stmt *StructuredBlock)
: OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start,
End, StructuredBlock) {
assert((K == OpenACCDirectiveKind::Parallel ||
K == OpenACCDirectiveKind::Serial ||
K == OpenACCDirectiveKind::Kernels) &&
"Only parallel, serial, and kernels constructs should be "
"represented by this type");

// Initialize the trailing storage.
std::uninitialized_copy(Clauses.begin(), Clauses.end(),
getTrailingObjects<const OpenACCClause *>());

setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
Clauses.size()));
}

void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
Expand All @@ -128,10 +163,12 @@ class OpenACCComputeConstruct : public OpenACCAssociatedStmtConstruct {
return T->getStmtClass() == OpenACCComputeConstructClass;
}

static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C, EmptyShell);
static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C,
unsigned NumClauses);
static OpenACCComputeConstruct *
Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,
SourceLocation EndLoc, Stmt *StructuredBlock);
SourceLocation EndLoc, ArrayRef<const OpenACCClause *> Clauses,
Stmt *StructuredBlock);

Stmt *getStructuredBlock() { return getAssociatedStmt(); }
const Stmt *getStructuredBlock() const {
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/TextNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ class TextNodeDumper

void Visit(const OMPClause *C);

void Visit(const OpenACCClause *C);

void Visit(const BlockDecl::Capture &C);

void Visit(const GenericSelectionExpr::ConstAssociation &A);
Expand Down Expand Up @@ -352,6 +354,7 @@ class TextNodeDumper
void VisitEnumConstantDecl(const EnumConstantDecl *D);
void VisitIndirectFieldDecl(const IndirectFieldDecl *D);
void VisitFunctionDecl(const FunctionDecl *D);
void VisitCXXDeductionGuideDecl(const CXXDeductionGuideDecl *D);
void VisitFieldDecl(const FieldDecl *D);
void VisitVarDecl(const VarDecl *D);
void VisitBindingDecl(const BindingDecl *D);
Expand Down
45 changes: 40 additions & 5 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -2300,6 +2300,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isConstantArrayType() const;
bool isIncompleteArrayType() const;
bool isVariableArrayType() const;
bool isArrayParameterType() const;
bool isDependentSizedArrayType() const;
bool isRecordType() const;
bool isClassType() const;
Expand Down Expand Up @@ -3334,14 +3335,15 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
return T->getTypeClass() == ConstantArray ||
T->getTypeClass() == VariableArray ||
T->getTypeClass() == IncompleteArray ||
T->getTypeClass() == DependentSizedArray;
T->getTypeClass() == DependentSizedArray ||
T->getTypeClass() == ArrayParameter;
}
};

/// Represents the canonical version of C arrays with a specified constant size.
/// For example, the canonical type for 'int A[4 + 4*100]' is a
/// ConstantArrayType where the element type is 'int' and the size is 404.
class ConstantArrayType final : public ArrayType {
class ConstantArrayType : public ArrayType {
friend class ASTContext; // ASTContext creates these.

struct ExternalSize {
Expand Down Expand Up @@ -3382,6 +3384,19 @@ class ConstantArrayType final : public ArrayType {
const Expr *SzExpr, ArraySizeModifier SzMod,
unsigned Qual);

protected:
ConstantArrayType(TypeClass Tc, const ConstantArrayType *ATy, QualType Can)
: ArrayType(Tc, ATy->getElementType(), Can, ATy->getSizeModifier(),
ATy->getIndexTypeQualifiers().getAsOpaqueValue(), nullptr) {
ConstantArrayTypeBits.HasExternalSize =
ATy->ConstantArrayTypeBits.HasExternalSize;
if (!ConstantArrayTypeBits.HasExternalSize) {
ConstantArrayTypeBits.SizeWidth = ATy->ConstantArrayTypeBits.SizeWidth;
Size = ATy->Size;
} else
SizePtr = ATy->SizePtr;
}

public:
/// Return the constant array size as an APInt.
llvm::APInt getSize() const {
Expand Down Expand Up @@ -3453,7 +3468,22 @@ class ConstantArrayType final : public ArrayType {
ArraySizeModifier SizeMod, unsigned TypeQuals);

static bool classof(const Type *T) {
return T->getTypeClass() == ConstantArray;
return T->getTypeClass() == ConstantArray ||
T->getTypeClass() == ArrayParameter;
}
};

/// Represents a constant array type that does not decay to a pointer when used
/// as a function parameter.
class ArrayParameterType : public ConstantArrayType {
friend class ASTContext; // ASTContext creates these.

ArrayParameterType(const ConstantArrayType *ATy, QualType CanTy)
: ConstantArrayType(ArrayParameter, ATy, CanTy) {}

public:
static bool classof(const Type *T) {
return T->getTypeClass() == ArrayParameter;
}
};

Expand Down Expand Up @@ -7185,7 +7215,8 @@ inline bool QualType::isCanonicalAsParam() const {
if (T->isVariablyModifiedType() && T->hasSizedVLAType())
return false;

return !isa<FunctionType>(T) && !isa<ArrayType>(T);
return !isa<FunctionType>(T) &&
(!isa<ArrayType>(T) || isa<ArrayParameterType>(T));
}

inline bool QualType::isConstQualified() const {
Expand Down Expand Up @@ -7450,6 +7481,10 @@ inline bool Type::isVariableArrayType() const {
return isa<VariableArrayType>(CanonicalType);
}

inline bool Type::isArrayParameterType() const {
return isa<ArrayParameterType>(CanonicalType);
}

inline bool Type::isDependentSizedArrayType() const {
return isa<DependentSizedArrayType>(CanonicalType);
}
Expand Down Expand Up @@ -7813,7 +7848,7 @@ inline bool Type::isTypedefNameType() const {

/// Determines whether this type can decay to a pointer type.
inline bool Type::canDecayToPointerType() const {
return isFunctionType() || isArrayType();
return isFunctionType() || (isArrayType() && !isArrayParameterType());
}

inline bool Type::hasPointerRepresentation() const {
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,11 @@ class ConstantArrayTypeLoc :
ConstantArrayType> {
};

/// Wrapper for source info for array parameter types.
class ArrayParameterTypeLoc
: public InheritingConcreteTypeLoc<
ConstantArrayTypeLoc, ArrayParameterTypeLoc, ArrayParameterType> {};

class IncompleteArrayTypeLoc :
public InheritingConcreteTypeLoc<ArrayTypeLoc,
IncompleteArrayTypeLoc,
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ let Class = ConstantArrayType in {
}]>;
}

let Class = ArrayParameterType in {
def : Creator<[{ return ctx.getAdjustedParameterType(
ctx.getConstantArrayType(elementType,sizeValue,
size,sizeModifier,
indexQualifiers.getCVRQualifiers())); }]>;
}

let Class = IncompleteArrayType in {
def : Creator<[{
return ctx.getIncompleteArrayType(elementType, sizeModifier,
Expand Down
79 changes: 61 additions & 18 deletions clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ enum class ComparisonResult {
Unknown,
};

/// The result of a `widen` operation.
struct WidenResult {
/// Non-null pointer to a potentially widened version of the input value.
Value *V;
/// Whether `V` represents a "change" (that is, a different value) with
/// respect to the previous value in the sequence.
LatticeEffect Effect;
};

/// Holds the state of the program (store and heap) at a given program point.
///
/// WARNING: Symbolic values that are created by the environment for static
Expand Down Expand Up @@ -104,14 +113,17 @@ class Environment {
/// serve as a comparison operation, by indicating whether the widened value
/// is equivalent to the previous value.
///
/// Returns either:
///
/// `nullptr`, if this value is not of interest to the model, or
///
/// `&Prev`, if the widened value is equivalent to `Prev`, or
///
/// A non-null value that approximates `Current`. `Prev` is available to
/// inform the chosen approximation.
/// Returns one of the folowing:
/// * `std::nullopt`, if this value is not of interest to the
/// model.
/// * A `WidenResult` with:
/// * A non-null `Value *` that points either to `Current` or a widened
/// version of `Current`. This value must be consistent with
/// the flow condition of `CurrentEnv`. We particularly caution
/// against using `Prev`, which is rarely consistent.
/// * A `LatticeEffect` indicating whether the value should be
/// considered a new value (`Changed`) or one *equivalent* (if not
/// necessarily equal) to `Prev` (`Unchanged`).
///
/// `PrevEnv` and `CurrentEnv` can be used to query child values and path
/// condition implications of `Prev` and `Current`, respectively.
Expand All @@ -122,17 +134,19 @@ class Environment {
///
/// `Prev` and `Current` must be assigned to the same storage location in
/// `PrevEnv` and `CurrentEnv`, respectively.
virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv,
Value &Current, Environment &CurrentEnv) {
virtual std::optional<WidenResult> widen(QualType Type, Value &Prev,
const Environment &PrevEnv,
Value &Current,
Environment &CurrentEnv) {
// The default implementation reduces to just comparison, since comparison
// is required by the API, even if no widening is performed.
switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
case ComparisonResult::Same:
return &Prev;
case ComparisonResult::Different:
return &Current;
case ComparisonResult::Unknown:
return nullptr;
case ComparisonResult::Unknown:
return std::nullopt;
case ComparisonResult::Same:
return WidenResult{&Current, LatticeEffect::Unchanged};
case ComparisonResult::Different:
return WidenResult{&Current, LatticeEffect::Changed};
}
llvm_unreachable("all cases in switch covered");
}
Expand Down Expand Up @@ -236,8 +250,8 @@ class Environment {
///
/// `PrevEnv` must be the immediate previous version of the environment.
/// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`.
LatticeJoinEffect widen(const Environment &PrevEnv,
Environment::ValueModel &Model);
LatticeEffect widen(const Environment &PrevEnv,
Environment::ValueModel &Model);

// FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`,
// `getStableStorageLocation`, or something more appropriate.
Expand Down Expand Up @@ -744,6 +758,35 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
std::vector<const FieldDecl *>
getFieldsForInitListExpr(const InitListExpr *InitList);

/// Helper class for initialization of a record with an `InitListExpr`.
/// `InitListExpr::inits()` contains the initializers for both the base classes
/// and the fields of the record; this helper class separates these out into two
/// different lists. In addition, it deals with special cases associated with
/// unions.
class RecordInitListHelper {
public:
// `InitList` must have record type.
RecordInitListHelper(const InitListExpr *InitList);

// Base classes with their associated initializer expressions.
ArrayRef<std::pair<const CXXBaseSpecifier *, Expr *>> base_inits() const {
return BaseInits;
}

// Fields with their associated initializer expressions.
ArrayRef<std::pair<const FieldDecl *, Expr *>> field_inits() const {
return FieldInits;
}

private:
SmallVector<std::pair<const CXXBaseSpecifier *, Expr *>> BaseInits;
SmallVector<std::pair<const FieldDecl *, Expr *>> FieldInits;

// We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a
// member variable because we store a pointer to it in `FieldInits`.
std::optional<ImplicitValueInitExpr> ImplicitValueInitForUnion;
};

/// Associates a new `RecordValue` with `Loc` and returns the new value.
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);

Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
namespace clang {
namespace dataflow {

/// Effect indicating whether a lattice join operation resulted in a new value.
// FIXME: Rename to `LatticeEffect` since `widen` uses it as well, and we are
// likely removing it from `join`.
enum class LatticeJoinEffect {
/// Effect indicating whether a lattice operation resulted in a new value.
enum class LatticeEffect {
Unchanged,
Changed,
};
// DEPRECATED. Use `LatticeEffect`.
using LatticeJoinEffect = LatticeEffect;

} // namespace dataflow
} // namespace clang
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2178,9 +2178,10 @@ def TypeNonNull : TypeAttr {
let Documentation = [TypeNonNullDocs];
}

def TypeNullable : TypeAttr {
def TypeNullable : DeclOrTypeAttr {
let Spellings = [CustomKeyword<"_Nullable">];
let Documentation = [TypeNullableDocs];
// let Subjects = SubjectList<[CXXRecord], ErrorDiag>;
}

def TypeNullableResult : TypeAttr {
Expand Down
25 changes: 25 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -4151,6 +4151,20 @@ non-underscored keywords. For example:
@property (assign, nullable) NSView *superview;
@property (readonly, nonnull) NSArray *subviews;
@end

As well as built-in pointer types, the nullability attributes can be attached
to C++ classes marked with the ``_Nullable`` attribute.

The following C++ standard library types are considered nullable:
``unique_ptr``, ``shared_ptr``, ``auto_ptr``, ``exception_ptr``, ``function``,
``move_only_function`` and ``coroutine_handle``.

Types should be marked nullable only where the type itself leaves nullability
ambiguous. For example, ``std::optional`` is not marked ``_Nullable``, because
``optional<int> _Nullable`` is redundant and ``optional<int> _Nonnull`` is
not a useful type. ``std::weak_ptr`` is not nullable, because its nullability
can change with no visible modification, so static annotation is unlikely to be
unhelpful.
}];
}

Expand Down Expand Up @@ -4185,6 +4199,17 @@ The ``_Nullable`` nullability qualifier indicates that a value of the
int fetch_or_zero(int * _Nullable ptr);

a caller of ``fetch_or_zero`` can provide null.

The ``_Nullable`` attribute on classes indicates that the given class can
represent null values, and so the ``_Nullable``, ``_Nonnull`` etc qualifiers
make sense for this type. For example:

.. code-block:: c

class _Nullable ArenaPointer { ... };

ArenaPointer _Nonnull x = ...;
ArenaPointer _Nullable y = nullptr;
}];
}

Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -4587,6 +4587,12 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> {
}

// HLSL
def HLSLAll : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_all"];
let Attributes = [NoThrow, Const];
let Prototype = "bool(...)";
}

def HLSLAny : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_any"];
let Attributes = [NoThrow, Const];
Expand All @@ -4599,6 +4605,12 @@ def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> {
let Prototype = "unsigned int(bool)";
}

def HLSLWaveGetLaneIndex : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_wave_get_lane_index"];
let Attributes = [NoThrow, Const];
let Prototype = "unsigned int()";
}

def HLSLClamp : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_clamp"];
let Attributes = [NoThrow, Const];
Expand Down
13 changes: 12 additions & 1 deletion clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ def warn_drv_unsupported_diag_option_for_flang : Warning<
def warn_drv_unsupported_option_for_processor : Warning<
"ignoring '%0' option as it is not currently supported for processor '%1'">,
InGroup<OptionIgnored>;
def warn_drv_unsupported_openmp_library : Warning<
"The library '%0=%1' is not supported, openmp is not be enabled">,
InGroup<OptionIgnored>;

def err_drv_invalid_thread_model_for_target : Error<
"invalid thread model '%0' in '%1' for this target">;
Expand Down Expand Up @@ -548,6 +551,12 @@ def err_drv_extract_api_wrong_kind : Error<
"header file '%0' input '%1' does not match the type of prior input "
"in api extraction; use '-x %2' to override">;

def err_drv_missing_symbol_graph_dir: Error<
"Must provide a symbol graph output directory using --symbol-graph-dir=<directory>">;

def err_drv_unexpected_symbol_graph_output : Error<
"Unexpected output symbol graph '%1'; please provide --symbol-graph-dir=<directory> instead">;

def warn_slash_u_filename : Warning<"'/U%0' treated as the '/U' option">,
InGroup<DiagGroup<"slash-u-filename">>;
def note_use_dashdash : Note<
Expand Down Expand Up @@ -657,6 +666,7 @@ def warn_drv_darwin_sdk_invalid_settings : Warning<
"SDK settings were ignored as 'SDKSettings.json' could not be parsed">,
InGroup<DiagGroup<"darwin-sdk-settings">>;

def err_missing_sysroot : Error<"no such sysroot directory: '%0'">;
def err_drv_darwin_sdk_missing_arclite : Error<
"SDK does not contain 'libarclite' at the path '%0'; try increasing the minimum deployment target">;

Expand Down Expand Up @@ -753,7 +763,8 @@ def err_drv_hlsl_unsupported_target : Error<
"HLSL code generation is unsupported for target '%0'">;
def err_drv_hlsl_bad_shader_required_in_target : Error<
"%select{shader model|Vulkan environment|shader stage}0 is required as %select{OS|environment}1 in target '%2' for HLSL code generation">;

def err_drv_hlsl_16bit_types_unsupported: Error<
"'%0' option requires target HLSL Version >= 2018%select{| and shader model >= 6.2}1, but HLSL Version is '%2'%select{| and shader model is '%3'}1">;
def err_drv_hlsl_bad_shader_unsupported : Error<
"%select{shader model|Vulkan environment|shader stage}0 '%1' in target '%2' is invalid for HLSL code generation">;
def warn_drv_dxc_missing_dxv : Warning<"dxv not found. "
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -366,4 +366,8 @@ def warn_profile_data_misexpect : Warning<
def err_extract_api_ignores_file_not_found :
Error<"file '%0' specified by '--extract-api-ignores=' not found">, DefaultFatal;

def warn_missing_symbol_graph_dir : Warning<
"Missing symbol graph output directory, defaulting to working directory">,
InGroup<ExtractAPIMisuse>;

}
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,7 @@ def FormatSecurity : DiagGroup<"format-security">;
def FormatNonStandard : DiagGroup<"format-non-iso">;
def FormatY2K : DiagGroup<"format-y2k">;
def FormatPedantic : DiagGroup<"format-pedantic">;
def FormatSignedness : DiagGroup<"format-signedness">;
def FormatTypeConfusion : DiagGroup<"format-type-confusion">;

def FormatOverflowNonKprintf: DiagGroup<"format-overflow-non-kprintf">;
Expand Down Expand Up @@ -1516,3 +1517,5 @@ def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInCon
// Warnings and notes InstallAPI verification.
def InstallAPIViolation : DiagGroup<"installapi-violation">;

// Warnings about misuse of ExtractAPI options.
def ExtractAPIMisuse : DiagGroup<"extractapi-misuse">;
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace clang {
enum {
DIAG_SIZE_COMMON = 300,
DIAG_SIZE_DRIVER = 400,
DIAG_SIZE_FRONTEND = 150,
DIAG_SIZE_FRONTEND = 200,
DIAG_SIZE_SERIALIZATION = 120,
DIAG_SIZE_LEX = 400,
DIAG_SIZE_PARSE = 700,
Expand Down
21 changes: 21 additions & 0 deletions clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ def err_no_such_header_file : Error<"no such %select{public|private|project}1 he
def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup<InstallAPIViolation>;
def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup<InstallAPIViolation>;
def err_no_such_umbrella_header_file : Error<"%select{public|private|project}1 umbrella header file not found in input: '%0'">;
def err_cannot_find_reexport : Error<"cannot find re-exported %select{framework|library}0: '%1'">;
} // end of command line category.

let CategoryName = "Verification" in {
// Diagnostics about symbols.
def warn_target: Warning<"violations found for %0">, InGroup<InstallAPIViolation>;
def err_library_missing_symbol : Error<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">;
def warn_library_missing_symbol : Warning<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">, InGroup<InstallAPIViolation>;
Expand All @@ -43,6 +45,25 @@ def err_dylib_symbol_flags_mismatch : Error<"dynamic library symbol '%0' is "
"%select{weak defined|thread local}1, but its declaration is not">;
def err_header_symbol_flags_mismatch : Error<"declaration '%0' is "
"%select{weak defined|thread local}1, but symbol is not in dynamic library">;

// Diagnostics about load commands.
def err_architecture_mismatch : Error<"architectures do not match: '%0' (provided) vs '%1' (found)">;
def warn_platform_mismatch : Warning<"platform does not match: '%0' (provided) vs '%1' (found)">, InGroup<InstallAPIViolation>;
def err_platform_mismatch : Error<"platform does not match: '%0' (provided) vs '%1' (found)">;
def err_install_name_mismatch : Error<"install_name does not match: '%0' (provided) vs '%1' (found)">;
def err_current_version_mismatch : Error<"current_version does not match: '%0' (provided) vs '%1' (found)">;
def err_compatibility_version_mismatch : Error<"compatibility_version does not match: '%0' (provided) vs '%1' (found)">;
def err_appextension_safe_mismatch : Error<"ApplicationExtensionSafe flag does not match: '%0' (provided) vs '%1' (found)">;
def err_shared_cache_eligiblity_mismatch : Error<"NotForDyldSharedCache flag does not match: '%0' (provided) vs '%1' (found)">;
def err_no_twolevel_namespace : Error<"flat namespace libraries are not supported">;
def err_parent_umbrella_missing: Error<"parent umbrella missing from %0: '%1'">;
def err_parent_umbrella_mismatch : Error<"parent umbrella does not match: '%0' (provided) vs '%1' (found)">;
def err_reexported_libraries_missing : Error<"re-exported library missing from %0: '%1'">;
def err_reexported_libraries_mismatch : Error<"re-exported libraries do not match: '%0' (provided) vs '%1' (found)">;
def err_allowable_clients_missing : Error<"allowable client missing from %0: '%1'">;
def err_allowable_clients_mismatch : Error<"allowable clients do not match: '%0' (provided) vs '%1' (found)">;
def warn_rpaths_missing : Warning<"runpath search paths missing from %0: '%1'">, InGroup<InstallAPIViolation>;
def warn_rpaths_mismatch : Warning<"runpath search paths do not match: '%0' (provided) vs '%1' (found)">, InGroup<InstallAPIViolation>;
} // end of Verification category.

} // end of InstallAPI component
7 changes: 5 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1748,8 +1748,8 @@ def err_type_defined_in_condition : Error<
def err_type_defined_in_enum : Error<
"%0 cannot be defined in an enumeration">;
def ext_type_defined_in_offsetof : Extension<
"defining a type within '%select{__builtin_offsetof|offsetof}0' is a Clang "
"extension">, InGroup<GNUOffsetofExtensions>;
"defining a type within '%select{__builtin_offsetof|offsetof}0' is a C23 "
"extension">, InGroup<C23>;

def note_pure_virtual_function : Note<
"unimplemented pure virtual method %0 in %1">;
Expand Down Expand Up @@ -9821,6 +9821,9 @@ def warn_format_conversion_argument_type_mismatch : Warning<
def warn_format_conversion_argument_type_mismatch_pedantic : Extension<
warn_format_conversion_argument_type_mismatch.Summary>,
InGroup<FormatPedantic>;
def warn_format_conversion_argument_type_mismatch_signedness : Warning<
warn_format_conversion_argument_type_mismatch.Summary>,
InGroup<FormatSignedness>, DefaultIgnore;
def warn_format_conversion_argument_type_mismatch_confusion : Warning<
warn_format_conversion_argument_type_mismatch.Summary>,
InGroup<FormatTypeConfusion>, DefaultIgnore;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ EXTENSION(define_target_os_macros,
FEATURE(enumerator_attributes, true)
FEATURE(nullability, true)
FEATURE(nullability_on_arrays, true)
FEATURE(nullability_on_classes, true)
FEATURE(nullability_nullable_result, true)
FEATURE(memory_sanitizer,
LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |
Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ class TargetInfo : public TransferrableTargetInfo,
LLVM_PREFERRED_TYPE(bool)
unsigned AllowAMDGPUUnsafeFPAtomics : 1;

LLVM_PREFERRED_TYPE(bool)
unsigned HasUnalignedAccess : 1;

unsigned ARMCDECoprocMask : 8;

unsigned MaxOpenCLWorkGroupSize;
Expand Down Expand Up @@ -859,6 +862,18 @@ class TargetInfo : public TransferrableTargetInfo,
return PointerWidth;
}

/// Return true iff unaligned accesses are a single instruction (rather than
/// a synthesized sequence).
bool hasUnalignedAccess() const { return HasUnalignedAccess; }

/// Return true iff unaligned accesses are cheap. This affects placement and
/// size of bitfield loads/stores. (Not the ABI-mandated placement of
/// the bitfields themselves.)
bool hasCheapUnalignedBitFieldAccess() const {
// Simply forward to the unaligned access getter.
return hasUnalignedAccess();
}

/// \brief Returns the default value of the __USER_LABEL_PREFIX__ macro,
/// which is the prefix given to user symbols by default.
///
Expand Down
46 changes: 24 additions & 22 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -665,28 +665,30 @@ KEYWORD(__kindof , KEYOBJC)

// Alternate spelling for various tokens. There are GCC extensions in all
// languages, but should not be disabled in strict conformance mode.
ALIAS("__alignof__" , __alignof , KEYALL)
ALIAS("__asm" , asm , KEYALL)
ALIAS("__asm__" , asm , KEYALL)
ALIAS("__attribute__", __attribute, KEYALL)
ALIAS("__complex" , _Complex , KEYALL)
ALIAS("__complex__" , _Complex , KEYALL)
ALIAS("__const" , const , KEYALL)
ALIAS("__const__" , const , KEYALL)
ALIAS("__decltype" , decltype , KEYCXX)
ALIAS("__imag__" , __imag , KEYALL)
ALIAS("__inline" , inline , KEYALL)
ALIAS("__inline__" , inline , KEYALL)
ALIAS("__nullptr" , nullptr , KEYCXX)
ALIAS("__real__" , __real , KEYALL)
ALIAS("__restrict" , restrict , KEYALL)
ALIAS("__restrict__" , restrict , KEYALL)
ALIAS("__signed" , signed , KEYALL)
ALIAS("__signed__" , signed , KEYALL)
ALIAS("__typeof" , typeof , KEYALL)
ALIAS("__typeof__" , typeof , KEYALL)
ALIAS("__volatile" , volatile , KEYALL)
ALIAS("__volatile__" , volatile , KEYALL)
ALIAS("__alignof__" , __alignof , KEYALL)
ALIAS("__asm" , asm , KEYALL)
ALIAS("__asm__" , asm , KEYALL)
ALIAS("__attribute__" , __attribute , KEYALL)
ALIAS("__complex" , _Complex , KEYALL)
ALIAS("__complex__" , _Complex , KEYALL)
ALIAS("__const" , const , KEYALL)
ALIAS("__const__" , const , KEYALL)
ALIAS("__decltype" , decltype , KEYCXX)
ALIAS("__imag__" , __imag , KEYALL)
ALIAS("__inline" , inline , KEYALL)
ALIAS("__inline__" , inline , KEYALL)
ALIAS("__nullptr" , nullptr , KEYCXX)
ALIAS("__real__" , __real , KEYALL)
ALIAS("__restrict" , restrict , KEYALL)
ALIAS("__restrict__" , restrict , KEYALL)
ALIAS("__signed" , signed , KEYALL)
ALIAS("__signed__" , signed , KEYALL)
ALIAS("__typeof" , typeof , KEYALL)
ALIAS("__typeof__" , typeof , KEYALL)
ALIAS("__typeof_unqual" , typeof_unqual, KEYALL)
ALIAS("__typeof_unqual__", typeof_unqual, KEYALL)
ALIAS("__volatile" , volatile , KEYALL)
ALIAS("__volatile__" , volatile , KEYALL)

// Type nullability.
KEYWORD(_Nonnull , KEYALL)
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TypeNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def ConstantArrayType : TypeNode<ArrayType>;
def IncompleteArrayType : TypeNode<ArrayType>;
def VariableArrayType : TypeNode<ArrayType>;
def DependentSizedArrayType : TypeNode<ArrayType>, AlwaysDependent;
def ArrayParameterType : TypeNode<ConstantArrayType>;
def DependentSizedExtVectorType : TypeNode<Type>, AlwaysDependent;
def DependentAddressSpaceType : TypeNode<Type>, AlwaysDependent;
def VectorType : TypeNode<Type>;
Expand Down
31 changes: 15 additions & 16 deletions clang/include/clang/Basic/arm_neon.td
Original file line number Diff line number Diff line change
Expand Up @@ -1758,24 +1758,21 @@ let TargetGuard = "fullfp16" in {
// Mul lane
def VMUL_LANEH : IOpInst<"vmul_lane", "..qI", "hQh", OP_MUL_LN>;
def VMUL_NH : IOpInst<"vmul_n", "..1", "hQh", OP_MUL_N>;
}

// Data processing intrinsics - section 5

// Logical operations
let isHiddenLInst = 1 in
def VBSLH : SInst<"vbsl", ".U..", "hQh">;

// Transposition operations
def VZIPH : WInst<"vzip", "2..", "hQh">;
def VUZPH : WInst<"vuzp", "2..", "hQh">;
def VTRNH : WInst<"vtrn", "2..", "hQh">;

// Vector Extract
def VEXTH : WInst<"vext", "...I", "hQh">;
// Data processing intrinsics - section 5. Do not require fullfp16.

// Reverse vector elements
def VREV64H : WOpInst<"vrev64", "..", "hQh", OP_REV64>;
}
// Logical operations
let isHiddenLInst = 1 in
def VBSLH : SInst<"vbsl", ".U..", "hQh">;
// Transposition operations
def VZIPH : WInst<"vzip", "2..", "hQh">;
def VUZPH : WInst<"vuzp", "2..", "hQh">;
def VTRNH : WInst<"vtrn", "2..", "hQh">;
// Vector Extract
def VEXTH : WInst<"vext", "...I", "hQh">;
// Reverse vector elements
def VREV64H : WOpInst<"vrev64", "..", "hQh", OP_REV64>;

// ARMv8.2-A FP16 vector intrinsics for A64 only.
let ArchGuard = "defined(__aarch64__)", TargetGuard = "fullfp16" in {
Expand Down Expand Up @@ -1857,7 +1854,9 @@ let ArchGuard = "defined(__aarch64__)", TargetGuard = "fullfp16" in {
def VMINVH : SInst<"vminv", "1.", "hQh">;
def FMAXNMVH : SInst<"vmaxnmv", "1.", "hQh">;
def FMINNMVH : SInst<"vminnmv", "1.", "hQh">;
}

let ArchGuard = "defined(__aarch64__)" in {
// Permutation
def VTRN1H : SOpInst<"vtrn1", "...", "hQh", OP_TRN1>;
def VZIP1H : SOpInst<"vzip1", "...", "hQh", OP_ZIP1>;
Expand Down
41 changes: 36 additions & 5 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -802,9 +802,11 @@ def B : JoinedOrSeparate<["-"], "B">, MetaVarName<"<prefix>">,
HelpText<"Search $prefix$file for executables, libraries, and data files. "
"If $prefix is a directory, search $prefix/$file">;
def gcc_install_dir_EQ : Joined<["--"], "gcc-install-dir=">,
Visibility<[ClangOption, FlangOption]>,
HelpText<"Use GCC installation in the specified directory. The directory ends with path components like 'lib{,32,64}/gcc{,-cross}/$triple/$version'. "
"Note: executables (e.g. ld) used by the compiler are not overridden by the selected GCC installation">;
def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[NoXarchOption]>,
Visibility<[ClangOption, FlangOption]>,
HelpText<"Specify a directory where Clang can find 'include' and 'lib{,32,64}/gcc{,-cross}/$triple/$version'. "
"Clang will use the GCC installation with the largest version">;
def gcc_triple_EQ : Joined<["--"], "gcc-triple=">,
Expand Down Expand Up @@ -1507,14 +1509,29 @@ def extract_api : Flag<["-"], "extract-api">,
def product_name_EQ: Joined<["--"], "product-name=">,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoString<FrontendOpts<"ProductName">>;
def emit_symbol_graph_EQ: JoinedOrSeparate<["--"], "emit-symbol-graph=">,
def emit_symbol_graph: Flag<["-"], "emit-symbol-graph">,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Generate Extract API information as a side effect of compilation.">,
MarshallingInfoFlag<FrontendOpts<"EmitSymbolGraph">>;
def emit_extension_symbol_graphs: Flag<["--"], "emit-extension-symbol-graphs">,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Generate Extract API information as a side effect of compilation.">,
MarshallingInfoString<FrontendOpts<"SymbolGraphOutputDir">>;
HelpText<"Generate additional symbol graphs for extended modules.">,
MarshallingInfoFlag<FrontendOpts<"EmitExtensionSymbolGraphs">>;
def extract_api_ignores_EQ: CommaJoined<["--"], "extract-api-ignores=">,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Comma separated list of files containing a new line separated list of API symbols to ignore when extracting API information.">,
MarshallingInfoStringVector<FrontendOpts<"ExtractAPIIgnoresFileList">>;
def symbol_graph_dir_EQ: Joined<["--"], "symbol-graph-dir=">,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Directory in which to emit symbol graphs.">,
MarshallingInfoString<FrontendOpts<"SymbolGraphOutputDir">>;
def emit_pretty_sgf: Flag<["--"], "pretty-sgf">,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Emit pretty printed symbol graphs">,
MarshallingInfoFlag<FrontendOpts<"EmitPrettySymbolGraphs">>;
def emit_sgf_symbol_labels_for_testing: Flag<["--"], "emit-sgf-symbol-labels-for-testing">,
Visibility<[CC1Option]>,
MarshallingInfoFlag<FrontendOpts<"EmitSymbolGraphSymbolLabelsForTesting">>;
def e : Separate<["-"], "e">, Flags<[LinkerInput]>, Group<Link_Group>;
def fmax_tokens_EQ : Joined<["-"], "fmax-tokens=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
Expand Down Expand Up @@ -3392,17 +3409,24 @@ def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>,
HelpText<"Parse OpenMP pragmas and generate parallel code.">;
def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>,
Flags<[NoArgumentUnused]>;
class OpenMPVersionHelp<string program, string default> {
string str = !strconcat(
"Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is ",
default, " for ", program);
}
def fopenmp_version_EQ : Joined<["-"], "fopenmp-version=">, Group<f_Group>,
Flags<[NoArgumentUnused]>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is 51 for Clang">;
HelpText<OpenMPVersionHelp<"Clang", "51">.str>,
HelpTextForVariants<[FlangOption, FC1Option], OpenMPVersionHelp<"Flang", "11">.str>;
defm openmp_extensions: BoolFOption<"openmp-extensions",
LangOpts<"OpenMPExtensions">, DefaultTrue,
PosFlag<SetTrue, [NoArgumentUnused], [ClangOption, CC1Option],
"Enable all Clang extensions for OpenMP directives and clauses">,
NegFlag<SetFalse, [NoArgumentUnused], [ClangOption, CC1Option],
"Disable all Clang extensions for OpenMP directives and clauses">>;
def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>;
def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>;
def fopenmp_use_tls : Flag<["-"], "fopenmp-use-tls">, Group<f_Group>,
Flags<[NoArgumentUnused, HelpHidden]>;
def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group<f_Group>,
Expand Down Expand Up @@ -3635,6 +3659,9 @@ defm preserve_as_comments : BoolFOption<"preserve-as-comments",
"Do not preserve comments in inline assembly">,
PosFlag<SetTrue>>;
def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>;
def reexport_framework : Separate<["-"], "reexport_framework">, Flags<[LinkerInput]>;
def reexport_l : Joined<["-"], "reexport-l">, Flags<[LinkerInput]>;
def reexport_library : JoinedOrSeparate<["-"], "reexport_library">, Flags<[LinkerInput]>;
def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group<clang_ignored_f_Group>;
def freg_struct_return : Flag<["-"], "freg-struct-return">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
Expand Down Expand Up @@ -4507,6 +4534,9 @@ def mwindows : Joined<["-"], "mwindows">, Group<m_Group>;
def mdll : Joined<["-"], "mdll">, Group<m_Group>;
def municode : Joined<["-"], "municode">, Group<m_Group>;
def mthreads : Joined<["-"], "mthreads">, Group<m_Group>;
def marm64x : Joined<["-"], "marm64x">, Group<m_Group>,
Visibility<[ClangOption, CLOption]>,
HelpText<"Link as a hybrid ARM64X image">;
def mguard_EQ : Joined<["-"], "mguard=">, Group<m_Group>,
HelpText<"Enable or disable Control Flow Guard checks and guard tables emission">,
Values<"none,cf,cf-nochecks">;
Expand Down Expand Up @@ -8307,6 +8337,7 @@ def _SLASH_Fi : CLCompileJoined<"Fi">,
def _SLASH_Fo : CLCompileJoined<"Fo">,
HelpText<"Set output object file (with /c)">,
MetaVarName<"<file or dir/>">;
def _SLASH_Fo_COLON : CLCompileJoined<"Fo:">, Alias<_SLASH_Fo>;
def _SLASH_guard : CLJoined<"guard:">,
HelpText<"Enable Control Flow Guard with /guard:cf, or only the table with /guard:cf,nochecks. "
"Enable EH Continuation Guard with /guard:ehcont">;
Expand Down
1,547 changes: 713 additions & 834 deletions clang/include/clang/ExtractAPI/API.h

Large diffs are not rendered by default.

103 changes: 103 additions & 0 deletions clang/include/clang/ExtractAPI/APIRecords.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//===- ExtractAPI/APIRecords.inc --------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the classes defined from ExtractAPI's APIRecord
///
//===----------------------------------------------------------------------===//

#ifndef ABSTRACT_RECORD
#define ABSTRACT_RECORD(CLASS, BASE) RECORD(CLASS, BASE)
#endif
#ifndef CONCRETE_RECORD
#define CONCRETE_RECORD(CLASS, BASE, KIND) RECORD(CLASS, BASE)
#endif
#ifndef RECORD
#define RECORD(CLASS, BASE)
#endif

CONCRETE_RECORD(NamespaceRecord, APIRecord, RK_Namespace)
CONCRETE_RECORD(GlobalFunctionRecord, APIRecord, RK_GlobalFunction)
CONCRETE_RECORD(GlobalFunctionTemplateRecord, GlobalFunctionRecord,
RK_GlobalFunctionTemplate)
CONCRETE_RECORD(GlobalFunctionTemplateSpecializationRecord,
GlobalFunctionRecord, RK_GlobalFunctionTemplateSpecialization)
CONCRETE_RECORD(GlobalVariableRecord, APIRecord, RK_GlobalVariable)
CONCRETE_RECORD(GlobalVariableTemplateRecord, GlobalVariableRecord,
RK_GlobalVariableTemplate)
CONCRETE_RECORD(GlobalVariableTemplateSpecializationRecord,
GlobalVariableRecord, RK_GlobalVariableTemplateSpecialization)
CONCRETE_RECORD(GlobalVariableTemplatePartialSpecializationRecord,
GlobalVariableRecord,
RK_GlobalVariableTemplatePartialSpecialization)
CONCRETE_RECORD(EnumConstantRecord, APIRecord, RK_EnumConstant)
CONCRETE_RECORD(EnumRecord, APIRecord, RK_Enum)
ABSTRACT_RECORD(RecordFieldRecord, APIRecord)
ABSTRACT_RECORD(RecordRecord, APIRecord)
CONCRETE_RECORD(StructFieldRecord, RecordFieldRecord, RK_StructField)
CONCRETE_RECORD(StructRecord, APIRecord, RK_Struct)
CONCRETE_RECORD(UnionFieldRecord, RecordFieldRecord, RK_UnionField)
CONCRETE_RECORD(UnionRecord, APIRecord, RK_Union)
CONCRETE_RECORD(CXXFieldRecord, APIRecord, RK_CXXField)
CONCRETE_RECORD(CXXFieldTemplateRecord, CXXFieldRecord, RK_CXXFieldTemplate)
ABSTRACT_RECORD(CXXMethodRecord, APIRecord)
CONCRETE_RECORD(CXXConstructorRecord, CXXMethodRecord, RK_CXXConstructorMethod)
CONCRETE_RECORD(CXXDestructorRecord, CXXMethodRecord, RK_CXXDestructorMethod)
CONCRETE_RECORD(CXXStaticMethodRecord, CXXMethodRecord, RK_CXXStaticMethod)
CONCRETE_RECORD(CXXInstanceMethodRecord, CXXMethodRecord, RK_CXXInstanceMethod)
CONCRETE_RECORD(CXXMethodTemplateRecord, CXXMethodRecord, RK_CXXMethodTemplate)
CONCRETE_RECORD(CXXMethodTemplateSpecializationRecord, CXXMethodRecord,
RK_CXXMethodTemplateSpecialization)
ABSTRACT_RECORD(ObjCPropertyRecord, APIRecord)
CONCRETE_RECORD(ObjCInstancePropertyRecord, ObjCPropertyRecord,
RK_ObjCInstanceProperty)
CONCRETE_RECORD(ObjCClassPropertyRecord, ObjCPropertyRecord,
RK_ObjCClassProperty)
CONCRETE_RECORD(ObjCInstanceVariableRecord, APIRecord, RK_ObjCIvar)
ABSTRACT_RECORD(ObjCMethodRecord, APIRecord)
CONCRETE_RECORD(ObjCInstanceMethodRecord, ObjCMethodRecord,
RK_ObjCInstanceMethod)
CONCRETE_RECORD(ObjCClassMethodRecord, ObjCMethodRecord, RK_ObjCClassMethod)
CONCRETE_RECORD(StaticFieldRecord, CXXFieldRecord, RK_StaticField)
ABSTRACT_RECORD(ObjCContainerRecord, APIRecord)
CONCRETE_RECORD(CXXClassRecord, APIRecord, RK_CXXClass)
CONCRETE_RECORD(ClassTemplateRecord, CXXClassRecord, RK_ClassTemplate)
CONCRETE_RECORD(ClassTemplateSpecializationRecord, CXXClassRecord,
RK_ClassTemplateSpecialization)
CONCRETE_RECORD(ClassTemplatePartialSpecializationRecord, CXXClassRecord,
RK_ClassTemplatePartialSpecialization)
CONCRETE_RECORD(ConceptRecord, APIRecord, RK_Concept)
CONCRETE_RECORD(ObjCCategoryRecord, ObjCContainerRecord, RK_ObjCCategory)
CONCRETE_RECORD(ObjCInterfaceRecord, ObjCContainerRecord, RK_ObjCInterface)
CONCRETE_RECORD(ObjCProtocolRecord, ObjCContainerRecord, RK_ObjCProtocol)
CONCRETE_RECORD(MacroDefinitionRecord, APIRecord, RK_MacroDefinition)
CONCRETE_RECORD(TypedefRecord, APIRecord, RK_Typedef)

#undef CONCRETE_RECORD
#undef ABSTRACT_RECORD
#undef RECORD

#ifndef RECORD_CONTEXT
#define RECORD_CONTEXT(CLASS, KIND)
#endif

RECORD_CONTEXT(NamespaceRecord, RK_Namespace)
RECORD_CONTEXT(EnumRecord, RK_Enum)
RECORD_CONTEXT(StructRecord, RK_Struct)
RECORD_CONTEXT(UnionRecord, RK_Union)
RECORD_CONTEXT(ObjCCategoryRecord, RK_ObjCCategory)
RECORD_CONTEXT(ObjCInterfaceRecord, RK_ObjCInterface)
RECORD_CONTEXT(ObjCProtocolRecord, RK_ObjCProtocol)
RECORD_CONTEXT(CXXClassRecord, RK_CXXClass)
RECORD_CONTEXT(ClassTemplateRecord, RK_ClassTemplate)
RECORD_CONTEXT(ClassTemplateSpecializationRecord,
RK_ClassTemplateSpecialization)
RECORD_CONTEXT(ClassTemplatePartialSpecializationRecord,
RK_ClassTemplatePartialSpecialization)

#undef RECORD_CONTEXT
33 changes: 18 additions & 15 deletions clang/include/clang/ExtractAPI/DeclarationFragments.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/MacroInfo.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <vector>

namespace clang {
Expand Down Expand Up @@ -182,6 +180,18 @@ class DeclarationFragments {
/// appending to chain up consecutive appends.
DeclarationFragments &appendSpace();

/// Append a text Fragment of a semicolon character.
///
/// \returns a reference to the DeclarationFragments object itself after
/// appending to chain up consecutive appends.
DeclarationFragments &appendSemicolon();

/// Removes a trailing semicolon character if present.
///
/// \returns a reference to the DeclarationFragments object itself after
/// removing to chain up consecutive operations.
DeclarationFragments &removeTrailingSemicolon();

/// Get the string description of a FragmentKind \p Kind.
static StringRef getFragmentKindString(FragmentKind Kind);

Expand All @@ -194,12 +204,14 @@ class DeclarationFragments {
static DeclarationFragments getStructureTypeFragment(const RecordDecl *Decl);

private:
DeclarationFragments &appendUnduplicatedTextCharacter(char Character);
std::vector<Fragment> Fragments;
};

class AccessControl {
public:
AccessControl(std::string Access) : Access(Access) {}
AccessControl() : Access("public") {}

const std::string &getAccess() const { return Access; }

Expand Down Expand Up @@ -315,13 +327,9 @@ class DeclarationFragmentsBuilder {
static DeclarationFragments
getFragmentsForTemplateParameters(ArrayRef<NamedDecl *>);

static std::string
getNameForTemplateArgument(const ArrayRef<NamedDecl *>, std::string);

static DeclarationFragments
getFragmentsForTemplateArguments(const ArrayRef<TemplateArgument>,
ASTContext &,
const std::optional<ArrayRef<NamedDecl *>>);
static DeclarationFragments getFragmentsForTemplateArguments(
const ArrayRef<TemplateArgument>, ASTContext &,
const std::optional<ArrayRef<TemplateArgumentLoc>>);

static DeclarationFragments getFragmentsForConcept(const ConceptDecl *);

Expand Down Expand Up @@ -430,12 +438,7 @@ DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) {
if (isa<FunctionDecl>(Function) &&
dyn_cast<FunctionDecl>(Function)->getDescribedFunctionTemplate() &&
StringRef(ReturnType.begin()->Spelling).starts_with("type-parameter")) {
std::string ProperArgName =
getNameForTemplateArgument(dyn_cast<FunctionDecl>(Function)
->getDescribedFunctionTemplate()
->getTemplateParameters()
->asArray(),
ReturnType.begin()->Spelling);
std::string ProperArgName = Function->getReturnType().getAsString();
ReturnType.begin()->Spelling.swap(ProperArgName);
}
ReturnType.append(std::move(After));
Expand Down
8 changes: 5 additions & 3 deletions clang/include/clang/ExtractAPI/ExtractAPIActionBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#include "clang/ExtractAPI/API.h"
#include "clang/ExtractAPI/APIIgnoresList.h"
#include "clang/Frontend/CompilerInstance.h"
#include "llvm/Support/raw_ostream.h"

namespace clang {

Expand All @@ -29,8 +31,8 @@ class ExtractAPIActionBase {
/// A representation of the APIs this action extracts.
std::unique_ptr<extractapi::APISet> API;

/// A stream to the output file of this action.
std::unique_ptr<raw_pwrite_stream> OS;
/// A stream to the main output file of this action.
std::unique_ptr<llvm::raw_pwrite_stream> OS;

/// The product this action is extracting API information for.
std::string ProductName;
Expand All @@ -46,7 +48,7 @@ class ExtractAPIActionBase {
///
/// Use the serializer to generate output symbol graph files from
/// the information gathered during the execution of Action.
void ImplEndSourceFileAction();
void ImplEndSourceFileAction(CompilerInstance &CI);
};

} // namespace clang
Expand Down
674 changes: 346 additions & 328 deletions clang/include/clang/ExtractAPI/ExtractAPIVisitor.h

Large diffs are not rendered by default.

6 changes: 0 additions & 6 deletions clang/include/clang/ExtractAPI/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ class ExtractAPIAction : public ASTFrontendAction,
void EndSourceFileAction() override;

static StringRef getInputBufferName() { return "<extract-api-includes>"; }

static std::unique_ptr<llvm::raw_pwrite_stream>
CreateOutputFile(CompilerInstance &CI, StringRef InFile);
};

/// Wrap ExtractAPIAction on top of a pre-existing action
Expand Down Expand Up @@ -85,9 +82,6 @@ class WrappingExtractAPIAction : public WrapperFrontendAction,
/// actions. This is the place where all the gathered symbol graph
/// information is emited.
void EndSourceFileAction() override;

static std::unique_ptr<llvm::raw_pwrite_stream>
CreateOutputFile(CompilerInstance &CI, StringRef InFile);
};

} // namespace clang
Expand Down
172 changes: 172 additions & 0 deletions clang/include/clang/ExtractAPI/Serialization/APISetVisitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//===- ExtractAPI/Serialization/APISetVisitor.h ----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the ExtractAPI APISetVisitor interface.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H

#include "clang/ExtractAPI/API.h"

namespace clang {
namespace extractapi {

// A helper macro to implement short-circuiting when recursing. It
// invokes CALL_EXPR, which must be a method call, on the derived
// object (s.t. a user of RecursiveASTVisitor can override the method
// in CALL_EXPR).
#define TRY_TO(CALL_EXPR) \
do { \
if (!getDerived()->CALL_EXPR) \
return false; \
} while (false)

/// The base interface of visitors for API information, the interface and usage
/// is almost identical to RecurisveASTVistor. This class performs three
/// distinct tasks:
/// 1. traverse the APISet (i.e. go to every record);
/// 2. at a given record, walk up the class hierarchy starting from the record's
/// dynamic type until APIRecord is reached.
/// 3. given a (record, class) combination where 'class' is some base class of
/// the dynamic type of 'record', call a user-overridable function to actually
/// visit the record.
///
/// These tasks are done by three groups of methods, respectively:
/// 1. traverseRecord(APIRecord *x) does task #1, it is the entry point for
/// traversing the records starting from x. This method simply forwards to
/// traverseFoo(Foo *x) where Foo is the dynamic type of *x, which calls
/// walkUpFromFoo(x) and then recursively visits the child records of x.
/// 2. walkUpFromFoo(Foo *x) does task #2. It doesn't visit children records of
/// x, instead it first calls walkUpFromBar(x) where Bar is the direct parent
/// class of Foo (unless Foo has no parent) and then calls visitFoo(x).
/// 3. visitFoo(Foo *x) does task #3.
///
/// These three method groups are tiered (traverse* > walkUpFrom* >
/// visit*). A method (e.g. traverse*) may call methods from the same
/// tier (e.g. other traverse*) or one tier lower (e.g. walkUpFrom*).
/// It may not call methods from a higher tier.
///
/// Note that since walkUpFromFoo() calls walkUpFromBar() (where Bar
/// is Foo's super class) before calling visitFoo(), the result is
/// that the visit*() methods for a given record are called in the
/// top-down order (e.g. for a record of type ObjCInstancePropertyRecord, the
/// order will be visitRecord(), visitObjCPropertyRecord(), and then
/// visitObjCInstancePropertyRecord()).
///
/// This scheme guarantees that all visit*() calls for the same record
/// are grouped together. In other words, visit*() methods for different
/// records are never interleaved.
///
/// Clients of this visitor should subclass the visitor (providing
/// themselves as the template argument, using the curiously recurring
/// template pattern) and override any of the traverse*, walkUpFrom*,
/// and visit* methods for records where the visitor should customize
/// behavior. Most users only need to override visit*. Advanced
/// users may override traverse* and walkUpFrom* to implement custom
/// traversal strategies. Returning false from one of these overridden
/// functions will abort the entire traversal.
template <typename Derived> class APISetVisitor {
public:
bool traverseAPISet() {
for (const APIRecord *TLR : API.getTopLevelRecords()) {
TRY_TO(traverseAPIRecord(TLR));
}
return true;
}

bool traverseAPIRecord(const APIRecord *Record);
bool walkUpFromAPIRecord(const APIRecord *Record) {
TRY_TO(visitAPIRecord(Record));
return true;
}
bool visitAPIRecord(const APIRecord *Record) { return true; }

#define GENERATE_TRAVERSE_METHOD(CLASS, BASE) \
bool traverse##CLASS(const CLASS *Record) { \
TRY_TO(walkUpFrom##CLASS(Record)); \
TRY_TO(traverseRecordContext(dyn_cast<RecordContext>(Record))); \
return true; \
}

#define GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE) \
bool walkUpFrom##CLASS(const CLASS *Record) { \
TRY_TO(walkUpFrom##BASE(Record)); \
TRY_TO(visit##CLASS(Record)); \
return true; \
} \
bool visit##CLASS(const CLASS *Record) { return true; }

#define CONCRETE_RECORD(CLASS, BASE, KIND) \
GENERATE_TRAVERSE_METHOD(CLASS, BASE) \
GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)

#define ABSTRACT_RECORD(CLASS, BASE) \
GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE)

#include "../APIRecords.inc"

#undef GENERATE_WALKUP_AND_VISIT_METHODS
#undef GENERATE_TRAVERSE_METHOD

bool traverseRecordContext(const RecordContext *);

protected:
const APISet &API;

public:
APISetVisitor() = delete;
APISetVisitor(const APISetVisitor &) = delete;
APISetVisitor(APISetVisitor &&) = delete;
APISetVisitor &operator=(const APISetVisitor &) = delete;
APISetVisitor &operator=(APISetVisitor &&) = delete;

protected:
APISetVisitor(const APISet &API) : API(API) {}
~APISetVisitor() = default;

Derived *getDerived() { return static_cast<Derived *>(this); };
};

template <typename Derived>
bool APISetVisitor<Derived>::traverseRecordContext(
const RecordContext *Context) {
if (!Context)
return true;

for (auto *Child : Context->records())
TRY_TO(traverseAPIRecord(Child));

return true;
}

template <typename Derived>
bool APISetVisitor<Derived>::traverseAPIRecord(const APIRecord *Record) {
switch (Record->getKind()) {
#define CONCRETE_RECORD(CLASS, BASE, KIND) \
case APIRecord::KIND: { \
TRY_TO(traverse##CLASS(static_cast<const CLASS *>(Record))); \
break; \
}
#include "../APIRecords.inc"
case APIRecord::RK_Unknown: {
TRY_TO(walkUpFromAPIRecord(static_cast<const APIRecord *>(Record)));
break;
}
default:
llvm_unreachable("API Record with uninstantiable kind");
}
return true;
}

} // namespace extractapi
} // namespace clang

#endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
314 changes: 0 additions & 314 deletions clang/include/clang/ExtractAPI/Serialization/SerializerBase.h

This file was deleted.

254 changes: 147 additions & 107 deletions clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,17 @@
#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H
#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H

#include "clang/Basic/Module.h"
#include "clang/ExtractAPI/API.h"
#include "clang/ExtractAPI/APIIgnoresList.h"
#include "clang/ExtractAPI/Serialization/SerializerBase.h"
#include "clang/ExtractAPI/Serialization/APISetVisitor.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/raw_ostream.h"
Expand All @@ -35,7 +41,30 @@ using namespace llvm::json;
/// Common options to customize the visitor output.
struct SymbolGraphSerializerOption {
/// Do not include unnecessary whitespaces to save space.
bool Compact;
bool Compact = true;
bool EmitSymbolLabelsForTesting = false;
};

/// A representation of the contents of a given module symbol graph
struct ExtendedModule {
ExtendedModule() = default;
ExtendedModule(ExtendedModule &&EM) = default;
ExtendedModule &operator=(ExtendedModule &&EM) = default;
// Copies are expensive so disable them.
ExtendedModule(const ExtendedModule &EM) = delete;
ExtendedModule &operator=(const ExtendedModule &EM) = delete;

/// Add a symbol to the module, do not store the resulting pointer or use it
/// across insertions.
Object *addSymbol(Object &&Symbol);

void addRelationship(Object &&Relationship);

/// A JSON array of formatted symbols from an \c APISet.
Array Symbols;

/// A JSON array of formatted symbol relationships from an \c APISet.
Array Relationships;
};

/// The visitor that organizes API information in the Symbol Graph format.
Expand All @@ -44,28 +73,54 @@ struct SymbolGraphSerializerOption {
/// models an API set as a directed graph, where nodes are symbol declarations,
/// and edges are relationships between the connected symbols.
class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
/// A JSON array of formatted symbols in \c APISet.
Array Symbols;
private:
using Base = APISetVisitor<SymbolGraphSerializer>;
/// The main symbol graph that contains symbols that are either top-level or a
/// are related to symbols defined in this product/module.
ExtendedModule MainModule;

/// A JSON array of formatted symbol relationships in \c APISet.
Array Relationships;
/// Additional symbol graphs that contain symbols that are related to symbols
/// defined in another product/module. The key of this map is the module name
/// of the extended module.
llvm::StringMap<ExtendedModule> ExtendedModules;

/// The Symbol Graph format version used by this serializer.
static const VersionTuple FormatVersion;

/// Indicates whether child symbols should be visited. This is mainly
/// Indicates whether to take into account the extended module. This is only
/// useful for \c serializeSingleSymbolSGF.
bool ShouldRecurse;
bool ForceEmitToMainModule;

public:
/// Serialize the APIs in \c APISet in the Symbol Graph format.
// Stores the references required to construct path components for the
// currently visited APIRecord.
llvm::SmallVector<SymbolReference, 8> Hierarchy;

/// The list of symbols to ignore.
///
/// \returns a JSON object that contains the root of the formatted
/// Symbol Graph.
Object serialize();
/// Note: This should be consulted before emitting a symbol.
const APIIgnoresList &IgnoresList;

/// Wrap serialize(void) and write out the serialized JSON object to \p os.
void serialize(raw_ostream &os);
const bool EmitSymbolLabelsForTesting = false;

/// The object instantiated by the last call to serializeAPIRecord.
Object *CurrentSymbol = nullptr;

/// The module to which \p CurrentSymbol belongs too.
ExtendedModule *ModuleForCurrentSymbol = nullptr;

public:
static void
serializeMainSymbolGraph(raw_ostream &OS, const APISet &API,
const APIIgnoresList &IgnoresList,
SymbolGraphSerializerOption Options = {});

static void serializeWithExtensionGraphs(
raw_ostream &MainOutput, const APISet &API,
const APIIgnoresList &IgnoresList,
llvm::function_ref<
std::unique_ptr<llvm::raw_pwrite_stream>(llvm::Twine BaseFileName)>
CreateOutputStream,
SymbolGraphSerializerOption Options = {});

/// Serialize a single symbol SGF. This is primarily used for libclang.
///
Expand All @@ -75,6 +130,7 @@ class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
static std::optional<Object> serializeSingleSymbolSGF(StringRef USR,
const APISet &API);

private:
/// The kind of a relationship between two symbols.
enum RelationshipKind {
/// The source symbol is a member of the target symbol.
Expand All @@ -94,16 +150,32 @@ class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
ExtensionTo,
};

/// Serialize a single record.
void serializeSingleRecord(const APIRecord *Record);

/// Get the string representation of the relationship kind.
static StringRef getRelationshipString(RelationshipKind Kind);

void serializeRelationship(RelationshipKind Kind,
const SymbolReference &Source,
const SymbolReference &Target,
ExtendedModule &Into);

enum ConstraintKind { Conformance, ConditionalConformance };

static StringRef getConstraintString(ConstraintKind Kind);

private:
/// Just serialize the currently recorded objects in Symbol Graph format.
Object serializeCurrentGraph();
/// Serialize the APIs in \c ExtendedModule.
///
/// \returns a JSON object that contains the root of the formatted
/// Symbol Graph.
Object serializeGraph(StringRef ModuleName, ExtendedModule &&EM);

/// Serialize the APIs in \c ExtendedModule in the Symbol Graph format and
/// write them to the provide stream.
void serializeGraphToStream(raw_ostream &OS,
SymbolGraphSerializerOption Options,
StringRef ModuleName, ExtendedModule &&EM);

/// Synthesize the metadata section of the Symbol Graph format.
///
Expand All @@ -117,124 +189,92 @@ class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
/// by the given API set.
/// Note that "module" here is not to be confused with the Clang/C++ module
/// concept.
Object serializeModule() const;
Object serializeModuleObject(StringRef ModuleName) const;

Array serializePathComponents(const APIRecord *Record) const;

/// Determine if the given \p Record should be skipped during serialization.
bool shouldSkip(const APIRecord &Record) const;
bool shouldSkip(const APIRecord *Record) const;

ExtendedModule &getModuleForCurrentSymbol();

/// Format the common API information for \p Record.
///
/// This handles the shared information of all kinds of API records,
/// for example identifier and source location. The resulting object is then
/// augmented with kind-specific symbol information by the caller.
/// This method also checks if the given \p Record should be skipped during
/// serialization.
/// for example identifier, source location and path components. The resulting
/// object is then augmented with kind-specific symbol information in
/// subsequent visit* methods by accessing the \p State member variable. This
/// method also checks if the given \p Record should be skipped during
/// serialization. This should be called only once per concrete APIRecord
/// instance and the first visit* method to be called is responsible for
/// calling this. This is normally visitAPIRecord unless a walkUpFromFoo
/// method is implemented along the inheritance hierarchy in which case the
/// visitFoo method needs to call this.
///
/// \returns \c std::nullopt if this \p Record should be skipped, or a JSON
/// object containing common symbol information of \p Record.
template <typename RecordTy>
std::optional<Object> serializeAPIRecord(const RecordTy &Record) const;

/// Helper method to serialize second-level member records of \p Record and
/// the member-of relationships.
template <typename MemberTy>
void serializeMembers(const APIRecord &Record,
const SmallVector<std::unique_ptr<MemberTy>> &Members);

/// Serialize the \p Kind relationship between \p Source and \p Target.
///
/// Record the relationship between the two symbols in
/// SymbolGraphSerializer::Relationships.
void serializeRelationship(RelationshipKind Kind, SymbolReference Source,
SymbolReference Target);

protected:
/// The list of symbols to ignore.
///
/// Note: This should be consulted before emitting a symbol.
const APIIgnoresList &IgnoresList;

SymbolGraphSerializerOption Options;

llvm::StringSet<> visitedCategories;
/// \returns \c nullptr if this \p Record should be skipped, or a pointer to
/// JSON object containing common symbol information of \p Record. Do not
/// store the returned pointer only use it to augment the object with record
/// specific information as it directly points to the object in the
/// \p ExtendedModule, the pointer won't be valid as soon as another object is
/// inserted into the module.
void serializeAPIRecord(const APIRecord *Record);

public:
void visitNamespaceRecord(const NamespaceRecord &Record);

/// Visit a global function record.
void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record);

/// Visit a global variable record.
void visitGlobalVariableRecord(const GlobalVariableRecord &Record);

/// Visit an enum record.
void visitEnumRecord(const EnumRecord &Record);

/// Visit a record record.
void visitRecordRecord(const RecordRecord &Record);

void visitStaticFieldRecord(const StaticFieldRecord &Record);
// Handle if records should be skipped at this level of the traversal to
// ensure that children of skipped records aren't serialized.
bool traverseAPIRecord(const APIRecord *Record);

void visitCXXClassRecord(const CXXClassRecord &Record);
bool visitAPIRecord(const APIRecord *Record);

void visitClassTemplateRecord(const ClassTemplateRecord &Record);

void visitClassTemplateSpecializationRecord(
const ClassTemplateSpecializationRecord &Record);

void visitClassTemplatePartialSpecializationRecord(
const ClassTemplatePartialSpecializationRecord &Record);

void visitCXXInstanceMethodRecord(const CXXInstanceMethodRecord &Record);
/// Visit a global function record.
bool visitGlobalFunctionRecord(const GlobalFunctionRecord *Record);

void visitCXXStaticMethodRecord(const CXXStaticMethodRecord &Record);
bool visitCXXClassRecord(const CXXClassRecord *Record);

void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record);
bool visitClassTemplateRecord(const ClassTemplateRecord *Record);

void visitMethodTemplateSpecializationRecord(
const CXXMethodTemplateSpecializationRecord &Record);
bool visitClassTemplatePartialSpecializationRecord(
const ClassTemplatePartialSpecializationRecord *Record);

void visitCXXFieldRecord(const CXXFieldRecord &Record);
bool visitCXXMethodRecord(const CXXMethodRecord *Record);

void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record);
bool visitCXXMethodTemplateRecord(const CXXMethodTemplateRecord *Record);

void visitConceptRecord(const ConceptRecord &Record);
bool visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord *Record);

void
visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord &Record);
bool visitConceptRecord(const ConceptRecord *Record);

void visitGlobalVariableTemplateSpecializationRecord(
const GlobalVariableTemplateSpecializationRecord &Record);
bool
visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord *Record);

void visitGlobalVariableTemplatePartialSpecializationRecord(
const GlobalVariableTemplatePartialSpecializationRecord &Record);
bool visitGlobalVariableTemplatePartialSpecializationRecord(
const GlobalVariableTemplatePartialSpecializationRecord *Record);

void
visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord &Record);
bool
visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord *Record);

void visitGlobalFunctionTemplateSpecializationRecord(
const GlobalFunctionTemplateSpecializationRecord &Record);
bool visitObjCContainerRecord(const ObjCContainerRecord *Record);

/// Visit an Objective-C container record.
void visitObjCContainerRecord(const ObjCContainerRecord &Record);
bool visitObjCInterfaceRecord(const ObjCInterfaceRecord *Record);

/// Visit an Objective-C category record.
void visitObjCCategoryRecord(const ObjCCategoryRecord &Record);
bool traverseObjCCategoryRecord(const ObjCCategoryRecord *Record);
bool walkUpFromObjCCategoryRecord(const ObjCCategoryRecord *Record);
bool visitObjCCategoryRecord(const ObjCCategoryRecord *Record);

/// Visit a macro definition record.
void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record);
bool visitObjCMethodRecord(const ObjCMethodRecord *Record);

/// Visit a typedef record.
void visitTypedefRecord(const TypedefRecord &Record);
bool
visitObjCInstanceVariableRecord(const ObjCInstanceVariableRecord *Record);

/// Serialize a single record.
void serializeSingleRecord(const APIRecord *Record);
bool walkUpFromTypedefRecord(const TypedefRecord *Record);
bool visitTypedefRecord(const TypedefRecord *Record);

SymbolGraphSerializer(const APISet &API, const APIIgnoresList &IgnoresList,
SymbolGraphSerializerOption Options = {},
bool ShouldRecurse = true)
: APISetVisitor(API), ShouldRecurse(ShouldRecurse),
IgnoresList(IgnoresList), Options(Options) {}
bool EmitSymbolLabelsForTesting = false,
bool ForceEmitToMainModule = false)
: Base(API), ForceEmitToMainModule(ForceEmitToMainModule),
IgnoresList(IgnoresList),
EmitSymbolLabelsForTesting(EmitSymbolLabelsForTesting) {}
};

} // namespace extractapi
Expand Down
16 changes: 16 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,20 @@ struct FormatStyle {
/// \version 5
BreakConstructorInitializersStyle BreakConstructorInitializers;

/// If ``true``, clang-format will always break before function definition
/// parameters.
/// \code
/// true:
/// void functionDefinition(
/// int A, int B) {}
///
/// false:
/// void functionDefinition(int A, int B) {}
///
/// \endcode
/// \version 19
bool BreakFunctionDefinitionParameters;

/// Break after each annotation on a field in Java files.
/// \code{.java}
/// true: false:
Expand Down Expand Up @@ -4938,6 +4952,8 @@ struct FormatStyle {
BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon &&
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
BreakConstructorInitializers == R.BreakConstructorInitializers &&
BreakFunctionDefinitionParameters ==
R.BreakFunctionDefinitionParameters &&
BreakInheritanceList == R.BreakInheritanceList &&
BreakStringLiterals == R.BreakStringLiterals &&
BreakTemplateDeclarations == R.BreakTemplateDeclarations &&
Expand Down
36 changes: 36 additions & 0 deletions clang/include/clang/Frontend/CompilerInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,24 @@ class CompilerInstance : public ModuleLoader {

std::vector<std::shared_ptr<DependencyCollector>> DependencyCollectors;

/// Records the set of modules
class FailedModulesSet {
llvm::StringSet<> Failed;

public:
bool hasAlreadyFailed(StringRef module) { return Failed.count(module) > 0; }

void addFailed(StringRef module) { Failed.insert(module); }
};

/// The set of modules that failed to build.
///
/// This pointer will be shared among all of the compiler instances created
/// to (re)build modules, so that once a module fails to build anywhere,
/// other instances will see that the module has failed and won't try to
/// build it again.
std::shared_ptr<FailedModulesSet> FailedModules;

/// The set of top-level modules that has already been built on the
/// fly as part of this overall compilation action.
std::map<std::string, std::string, std::less<>> BuiltModules;
Expand Down Expand Up @@ -619,6 +637,24 @@ class CompilerInstance : public ModuleLoader {
}

/// @}
/// @name Failed modules set
/// @{

bool hasFailedModulesSet() const { return (bool)FailedModules; }

void createFailedModulesSet() {
FailedModules = std::make_shared<FailedModulesSet>();
}

std::shared_ptr<FailedModulesSet> getFailedModulesSetPtr() const {
return FailedModules;
}

void setFailedModulesSet(std::shared_ptr<FailedModulesSet> FMS) {
FailedModules = FMS;
}

/// }
/// @name Output Files
/// @{

Expand Down
14 changes: 12 additions & 2 deletions clang/include/clang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,18 @@ class InitOnlyAction : public FrontendAction {

/// Preprocessor-based frontend action that also loads PCH files.
class ReadPCHAndPreprocessAction : public FrontendAction {
llvm::unique_function<void(CompilerInstance &)> AdjustCI;

void ExecuteAction() override;

std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;

public:
ReadPCHAndPreprocessAction(
llvm::unique_function<void(CompilerInstance &)> AdjustCI)
: AdjustCI(std::move(AdjustCI)) {}

bool usesPreprocessorOnly() const override { return false; }
};

Expand Down Expand Up @@ -321,11 +327,15 @@ class PrintPreprocessedAction : public PreprocessorFrontendAction {

class GetDependenciesByModuleNameAction : public PreprocessOnlyAction {
StringRef ModuleName;
llvm::unique_function<void(CompilerInstance &)> AdjustCI;

void ExecuteAction() override;

public:
GetDependenciesByModuleNameAction(StringRef ModuleName)
: ModuleName(ModuleName) {}
GetDependenciesByModuleNameAction(
StringRef ModuleName,
llvm::unique_function<void(CompilerInstance &)> AdjustCI)
: ModuleName(ModuleName), AdjustCI(std::move(AdjustCI)) {}
};

} // end namespace clang
Expand Down
25 changes: 21 additions & 4 deletions clang/include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "clang/Sema/CodeCompleteOptions.h"
#include "clang/Serialization/ModuleFileExtension.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cassert>
#include <map>
Expand Down Expand Up @@ -387,6 +388,22 @@ class FrontendOptions {
LLVM_PREFERRED_TYPE(bool)
unsigned ModulesShareFileManager : 1;

/// Whether to emit symbol graph files as a side effect of compilation.
LLVM_PREFERRED_TYPE(bool)
unsigned EmitSymbolGraph : 1;

/// Whether to emit additional symbol graphs for extended modules.
LLVM_PREFERRED_TYPE(bool)
unsigned EmitExtensionSymbolGraphs : 1;

/// Whether to emit symbol labels for testing in generated symbol graphs
LLVM_PREFERRED_TYPE(bool)
unsigned EmitSymbolGraphSymbolLabelsForTesting : 1;

/// Whether to emit symbol labels for testing in generated symbol graphs
LLVM_PREFERRED_TYPE(bool)
unsigned EmitPrettySymbolGraphs : 1;

CodeCompleteOptions CodeCompleteOpts;

/// Specifies the output format of the AST.
Expand Down Expand Up @@ -496,10 +513,8 @@ class FrontendOptions {
// ignore when extracting documentation.
std::vector<std::string> ExtractAPIIgnoresFileList;

// Currently this is only used as part of the `-emit-symbol-graph`
// action.
// Location of output directory where symbol graph information would
// be dumped
// be dumped. This overrides regular -o output file specification
std::string SymbolGraphOutputDir;

/// Args to pass to the plugins
Expand Down Expand Up @@ -565,7 +580,9 @@ class FrontendOptions {
BuildingImplicitModuleUsesLock(true), ModulesEmbedAllFiles(false),
IncludeTimestamps(true), UseTemporary(true),
AllowPCMWithCompilerErrors(false), ModulesShareFileManager(true),
TimeTraceGranularity(500) {}
EmitSymbolGraph(false), EmitExtensionSymbolGraphs(false),
EmitSymbolGraphSymbolLabelsForTesting(false),
EmitPrettySymbolGraphs(false), TimeTraceGranularity(500) {}

/// getInputKindForExtension - Return the appropriate input kind for a file
/// extension. For example, "c" would return Language::C.
Expand Down
17 changes: 17 additions & 0 deletions clang/include/clang/InstallAPI/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ struct InstallAPIContext {
/// Library attributes that are typically passed as linker inputs.
BinaryAttrs BA;

/// Install names of reexported libraries of a library.
LibAttrs Reexports;

/// All headers that represent a library.
HeaderSeq InputHeaders;

Expand Down Expand Up @@ -80,6 +83,20 @@ struct InstallAPIContext {
llvm::DenseMap<StringRef, HeaderType> KnownIncludes;
};

/// Lookup the dylib or TextAPI file location for a system library or framework.
/// The search paths provided are searched in order.
/// @rpath based libraries are not supported.
///
/// \param InstallName The install name for the library.
/// \param FrameworkSearchPaths Search paths to look up frameworks with.
/// \param LibrarySearchPaths Search paths to look up dylibs with.
/// \param SearchPaths Fallback search paths if library was not found in earlier
/// paths.
/// \return The full path of the library.
std::string findLibrary(StringRef InstallName, FileManager &FM,
ArrayRef<std::string> FrameworkSearchPaths,
ArrayRef<std::string> LibrarySearchPaths,
ArrayRef<std::string> SearchPaths);
} // namespace installapi
} // namespace clang

Expand Down
41 changes: 37 additions & 4 deletions clang/include/clang/InstallAPI/DylibVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ enum class VerificationMode {
Pedantic,
};

using LibAttrs = llvm::StringMap<ArchitectureSet>;
using ReexportedInterfaces = llvm::SmallVector<llvm::MachO::InterfaceFile, 8>;

/// Service responsible to tracking state of verification across the
/// lifetime of InstallAPI.
/// As declarations are collected during AST traversal, they are
/// compared as symbols against what is available in the binary dylib.
class DylibVerifier : llvm::MachO::RecordVisitor {
private:
struct SymbolContext;
struct DWARFContext;

public:
enum class Result { NoVerify, Ignore, Valid, Invalid };
Expand All @@ -54,17 +58,19 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
DiagnosticsEngine *Diag = nullptr;

// Handle diagnostics reporting for target level violations.
void emitDiag(llvm::function_ref<void()> Report);
void emitDiag(llvm::function_ref<void()> Report, RecordLoc *Loc = nullptr);

VerifierContext() = default;
VerifierContext(DiagnosticsEngine *Diag) : Diag(Diag) {}
};

DylibVerifier() = default;

DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag,
VerificationMode Mode, bool Demangle)
: Dylib(std::move(Dylib)), Mode(Mode), Demangle(Demangle),
DylibVerifier(llvm::MachO::Records &&Dylib, ReexportedInterfaces &&Reexports,
DiagnosticsEngine *Diag, VerificationMode Mode, bool Demangle,
StringRef DSYMPath)
: Dylib(std::move(Dylib)), Reexports(std::move(Reexports)), Mode(Mode),
Demangle(Demangle), DSYMPath(DSYMPath),
Exports(std::make_unique<SymbolSet>()), Ctx(VerifierContext{Diag}) {}

Result verify(GlobalRecord *R, const FrontendAttrs *FA);
Expand All @@ -75,6 +81,14 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
// Scan through dylib slices and report any remaining missing exports.
Result verifyRemainingSymbols();

/// Compare and report the attributes represented as
/// load commands in the dylib to the attributes provided via options.
bool verifyBinaryAttrs(const ArrayRef<Target> ProvidedTargets,
const BinaryAttrs &ProvidedBA,
const LibAttrs &ProvidedReexports,
const LibAttrs &ProvidedClients,
const LibAttrs &ProvidedRPaths, const FileType &FT);

/// Initialize target for verification.
void setTarget(const Target &T);

Expand Down Expand Up @@ -103,6 +117,10 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
bool shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
const Record *DR);

/// Check if declaration is exported from a reexported library. These
/// symbols should be omitted from the text-api file.
bool shouldIgnoreReexport(const Record *R, SymbolContext &SymCtx) const;

/// Compare the visibility declarations to the linkage of symbol found in
/// dylib.
Result compareVisibility(const Record *R, SymbolContext &SymCtx,
Expand Down Expand Up @@ -143,20 +161,35 @@ class DylibVerifier : llvm::MachO::RecordVisitor {
std::string getAnnotatedName(const Record *R, SymbolContext &SymCtx,
bool ValidSourceLoc = true);

/// Extract source location for symbol implementations.
/// As this is a relatively expensive operation, it is only used
/// when there is a violation to report and there is not a known declaration
/// in the interface.
void accumulateSrcLocForDylibSymbols();

// Symbols in dylib.
llvm::MachO::Records Dylib;

// Reexported interfaces apart of the library.
ReexportedInterfaces Reexports;

// Controls what class of violations to report.
VerificationMode Mode = VerificationMode::Invalid;

// Attempt to demangle when reporting violations.
bool Demangle = false;

// File path to DSYM file.
StringRef DSYMPath;

// Valid symbols in final text file.
std::unique_ptr<SymbolSet> Exports = std::make_unique<SymbolSet>();

// Track current state of verification while traversing AST.
VerifierContext Ctx;

// Track DWARF provided source location for dylibs.
DWARFContext *DWARFCtx = nullptr;
};

} // namespace installapi
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/InstallAPI/MachO.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "llvm/TextAPI/TextAPIWriter.h"
#include "llvm/TextAPI/Utils.h"

using Architecture = llvm::MachO::Architecture;
using ArchitectureSet = llvm::MachO::ArchitectureSet;
using SymbolFlags = llvm::MachO::SymbolFlags;
using RecordLinkage = llvm::MachO::RecordLinkage;
using Record = llvm::MachO::Record;
Expand All @@ -34,6 +36,7 @@ using ObjCCategoryRecord = llvm::MachO::ObjCCategoryRecord;
using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord;
using ObjCIFSymbolKind = llvm::MachO::ObjCIFSymbolKind;
using Records = llvm::MachO::Records;
using RecordLoc = llvm::MachO::RecordLoc;
using RecordsSlice = llvm::MachO::RecordsSlice;
using BinaryAttrs = llvm::MachO::RecordsSlice::BinaryAttrs;
using SymbolSet = llvm::MachO::SymbolSet;
Expand Down
26 changes: 22 additions & 4 deletions clang/include/clang/Lex/HeaderSearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,19 @@ struct HeaderFileInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned External : 1;

/// Whether this header is part of a module.
/// Whether this header is part of and built with a module. i.e. it is listed
/// in a module map, and is not `excluded` or `textual`. (same meaning as
/// `ModuleMap::isModular()`).
LLVM_PREFERRED_TYPE(bool)
unsigned isModuleHeader : 1;

/// Whether this header is part of the module that we are building.
/// Whether this header is a `textual header` in a module.
LLVM_PREFERRED_TYPE(bool)
unsigned isTextualModuleHeader : 1;

/// Whether this header is part of the module that we are building, even if it
/// doesn't build with the module. i.e. this will include `excluded` and
/// `textual` headers as well as normal headers.
LLVM_PREFERRED_TYPE(bool)
unsigned isCompilingModuleHeader : 1;

Expand Down Expand Up @@ -128,13 +136,20 @@ struct HeaderFileInfo {

HeaderFileInfo()
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
External(false), isModuleHeader(false), isCompilingModuleHeader(false),
Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {}
External(false), isModuleHeader(false), isTextualModuleHeader(false),
isCompilingModuleHeader(false), Resolved(false),
IndexHeaderMapHeader(false), IsValid(false) {}

/// Retrieve the controlling macro for this header file, if
/// any.
const IdentifierInfo *
getControllingMacro(ExternalPreprocessorSource *External);

/// Update the module membership bits based on the header role.
///
/// isModuleHeader will potentially be set, but not cleared.
/// isTextualModuleHeader will be set or cleared based on the role update.
void mergeModuleMembership(ModuleMap::ModuleHeaderRole Role);
};

/// An external source of header file information, which may supply
Expand Down Expand Up @@ -522,6 +537,9 @@ class HeaderSearch {
///
/// \return false if \#including the file will have no effect or true
/// if we should include it.
///
/// \param M The module to which `File` belongs (this should usually be the
/// SuggestedModule returned by LookupFile/LookupSubframeworkHeader)
bool ShouldEnterIncludeFile(Preprocessor &PP, FileEntryRef File,
bool isImport, bool ModulesEnabled, Module *M,
bool &IsFirstIncludeOfFile);
Expand Down
15 changes: 8 additions & 7 deletions clang/include/clang/Lex/ModuleMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ class ModuleMap {
Attributes Attrs;

/// If \c InferModules is non-zero, the module map file that allowed
/// inferred modules. Otherwise, nullopt.
OptionalFileEntryRef ModuleMapFile;
/// inferred modules. Otherwise, invalid.
FileID ModuleMapFID;

/// The names of modules that cannot be inferred within this
/// directory.
Expand All @@ -279,8 +279,7 @@ class ModuleMap {

/// A mapping from an inferred module to the module map that allowed the
/// inference.
// FIXME: Consider making the values non-optional.
llvm::DenseMap<const Module *, OptionalFileEntryRef> InferredModuleAllowedBy;
llvm::DenseMap<const Module *, FileID> InferredModuleAllowedBy;

llvm::DenseMap<const Module *, AdditionalModMapsSet> AdditionalModMaps;

Expand Down Expand Up @@ -618,8 +617,9 @@ class ModuleMap {
///
/// \param Module The module whose module map file will be returned, if known.
///
/// \returns The file entry for the module map file containing the given
/// module, or nullptr if the module definition was inferred.
/// \returns The FileID for the module map file containing the given module,
/// invalid if the module definition was inferred.
FileID getContainingModuleMapFileID(const Module *Module) const;
OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const;

/// Get the module map file that (along with the module name) uniquely
Expand All @@ -631,9 +631,10 @@ class ModuleMap {
/// of inferred modules, returns the module map that allowed the inference
/// (e.g. contained 'module *'). Otherwise, returns
/// getContainingModuleMapFile().
FileID getModuleMapFileIDForUniquing(const Module *M) const;
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const;

void setInferredModuleAllowedBy(Module *M, OptionalFileEntryRef ModMap);
void setInferredModuleAllowedBy(Module *M, FileID ModMapFID);

/// Canonicalize \p Path in a manner suitable for a module map file. In
/// particular, this canonicalizes the parent directory separately from the
Expand Down
18 changes: 18 additions & 0 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,19 @@ class Preprocessor {
State ConditionalStackState = Off;
} PreambleConditionalStack;

/// Function for getting the dependency preprocessor directives of a file.
///
/// These are directives derived from a special form of lexing where the
/// source input is scanned for the preprocessor directives that might have an
/// effect on the dependencies for a compilation unit.
///
/// Enables a client to cache the directives for a file and provide them
/// across multiple compiler invocations.
/// FIXME: Allow returning an error.
using DependencyDirectivesFn = llvm::unique_function<std::optional<
ArrayRef<dependency_directives_scan::Directive>>(FileEntryRef)>;
DependencyDirectivesFn DependencyDirectivesForFile;

/// The current top of the stack that we're lexing from if
/// not expanding a macro and we are lexing directly from source code.
///
Expand Down Expand Up @@ -1270,6 +1283,11 @@ class Preprocessor {
/// false if it is producing tokens to be consumed by Parse and Sema.
bool isPreprocessedOutput() const { return PreprocessedOutput; }

/// Set the function used to get dependency directives for a file.
void setDependencyDirectivesFn(DependencyDirectivesFn Fn) {
DependencyDirectivesForFile = std::move(Fn);
}

/// Return true if we are lexing directly from the specified lexer.
bool isCurrentLexer(const PreprocessorLexer *L) const {
return CurPPLexer == L;
Expand Down
Loading