24 changes: 13 additions & 11 deletions clang/include/clang/Lex/HeaderSearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,15 @@ class HeaderSearch {
/// Return whether the specified file is a normal header,
/// a system header, or a C++ friendly system header.
SrcMgr::CharacteristicKind getFileDirFlavor(FileEntryRef File) {
return (SrcMgr::CharacteristicKind)getFileInfo(File).DirInfo;
if (const HeaderFileInfo *HFI = getExistingFileInfo(File))
return (SrcMgr::CharacteristicKind)HFI->DirInfo;
return (SrcMgr::CharacteristicKind)HeaderFileInfo().DirInfo;
}

/// Mark the specified file as a "once only" file due to
/// \#pragma once.
void MarkFileIncludeOnce(FileEntryRef File) {
HeaderFileInfo &FI = getFileInfo(File);
FI.isPragmaOnce = true;
getFileInfo(File).isPragmaOnce = true;
}

/// Mark the specified file as a system header, e.g. due to
Expand Down Expand Up @@ -834,16 +835,17 @@ class HeaderSearch {

unsigned header_file_size() const { return FileInfo.size(); }

/// Return the HeaderFileInfo structure for the specified FileEntry,
/// in preparation for updating it in some way.
/// Return the HeaderFileInfo structure for the specified FileEntry, in
/// preparation for updating it in some way.
HeaderFileInfo &getFileInfo(FileEntryRef FE);

/// Return the HeaderFileInfo structure for the specified FileEntry,
/// if it has ever been filled in.
/// \param WantExternal Whether the caller wants purely-external header file
/// info (where \p External is true).
const HeaderFileInfo *getExistingFileInfo(FileEntryRef FE,
bool WantExternal = true) const;
/// Return the HeaderFileInfo structure for the specified FileEntry, if it has
/// ever been filled in (either locally or externally).
const HeaderFileInfo *getExistingFileInfo(FileEntryRef FE) const;

/// Return the headerFileInfo structure for the specified FileEntry, if it has
/// ever been filled in locally.
const HeaderFileInfo *getExistingLocalFileInfo(FileEntryRef FE) const;

SearchDirIterator search_dir_begin() { return {*this, 0}; }
SearchDirIterator search_dir_end() { return {*this, SearchDirs.size()}; }
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1601,6 +1601,8 @@ class Parser : public CodeCompletionHandler {
const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers &VS,
SourceLocation PureSpecLoc);
StringLiteral *ParseCXXDeletedFunctionMessage();
void SkipDeletedFunctionBody();
void ParseCXXNonStaticMemberInitializer(Decl *VarD);
void ParseLexedAttributes(ParsingClass &Class);
void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
Expand Down Expand Up @@ -3657,6 +3659,8 @@ class Parser : public CodeCompletionHandler {
bool ParseOpenACCGangArgList();
/// Parses a 'gang-arg', used for the 'gang' clause.
bool ParseOpenACCGangArg();
/// Parses a 'condition' expr, ensuring it results in a
ExprResult ParseOpenACCConditionExpr();

private:
//===--------------------------------------------------------------------===//
Expand Down
454 changes: 69 additions & 385 deletions clang/include/clang/Sema/Sema.h

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/include/clang/Sema/SemaBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class SemaBase {
/// if (SemaDiagnosticBuilder(...) << foo << bar)
/// return ExprError();
///
/// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably
/// But see DiagIfDeviceCode() and DiagIfHostCode() -- you probably
/// want to use these instead of creating a SemaDiagnosticBuilder yourself.
operator bool() const { return isImmediate(); }

Expand Down
304 changes: 304 additions & 0 deletions clang/include/clang/Sema/SemaCUDA.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
//===----- SemaCUDA.h ----- Semantic Analysis for CUDA constructs ---------===//
//
// 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 declares semantic analysis for CUDA constructs.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMACUDA_H
#define LLVM_CLANG_SEMA_SEMACUDA_H

#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Redeclarable.h"
#include "clang/Basic/Cuda.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaBase.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include <string>

namespace clang {

enum class CUDAFunctionTarget;

class SemaCUDA : public SemaBase {
public:
SemaCUDA(Sema &S);

/// Increments our count of the number of times we've seen a pragma forcing
/// functions to be __host__ __device__. So long as this count is greater
/// than zero, all functions encountered will be __host__ __device__.
void PushForceHostDevice();

/// Decrements our count of the number of times we've seen a pragma forcing
/// functions to be __host__ __device__. Returns false if the count is 0
/// before incrementing, so you can emit an error.
bool PopForceHostDevice();

ExprResult ActOnExecConfigExpr(Scope *S, SourceLocation LLLLoc,
MultiExprArg ExecConfig,
SourceLocation GGGLoc);

/// A pair of a canonical FunctionDecl and a SourceLocation. When used as the
/// key in a hashtable, both the FD and location are hashed.
struct FunctionDeclAndLoc {
CanonicalDeclPtr<const FunctionDecl> FD;
SourceLocation Loc;
};

/// FunctionDecls and SourceLocations for which CheckCall has emitted a
/// (maybe deferred) "bad call" diagnostic. We use this to avoid emitting the
/// same deferred diag twice.
llvm::DenseSet<FunctionDeclAndLoc> LocsWithCUDACallDiags;

/// An inverse call graph, mapping known-emitted functions to one of their
/// known-emitted callers (plus the location of the call).
///
/// Functions that we can tell a priori must be emitted aren't added to this
/// map.
llvm::DenseMap</* Callee = */ CanonicalDeclPtr<const FunctionDecl>,
/* Caller = */ FunctionDeclAndLoc>
DeviceKnownEmittedFns;

/// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current
/// context is "used as device code".
///
/// - If CurContext is a __host__ function, does not emit any diagnostics
/// unless \p EmitOnBothSides is true.
/// - If CurContext is a __device__ or __global__ function, emits the
/// diagnostics immediately.
/// - If CurContext is a __host__ __device__ function and we are compiling for
/// the device, creates a diagnostic which is emitted if and when we realize
/// that the function will be codegen'ed.
///
/// Example usage:
///
/// // Variable-length arrays are not allowed in CUDA device code.
/// if (DiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentTarget())
/// return ExprError();
/// // Otherwise, continue parsing as normal.
SemaDiagnosticBuilder DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID);

/// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current
/// context is "used as host code".
///
/// Same as DiagIfDeviceCode, with "host" and "device" switched.
SemaDiagnosticBuilder DiagIfHostCode(SourceLocation Loc, unsigned DiagID);

/// Determines whether the given function is a CUDA device/host/kernel/etc.
/// function.
///
/// Use this rather than examining the function's attributes yourself -- you
/// will get it wrong. Returns CUDAFunctionTarget::Host if D is null.
CUDAFunctionTarget IdentifyTarget(const FunctionDecl *D,
bool IgnoreImplicitHDAttr = false);
CUDAFunctionTarget IdentifyTarget(const ParsedAttributesView &Attrs);

enum CUDAVariableTarget {
CVT_Device, /// Emitted on device side with a shadow variable on host side
CVT_Host, /// Emitted on host side only
CVT_Both, /// Emitted on both sides with different addresses
CVT_Unified, /// Emitted as a unified address, e.g. managed variables
};
/// Determines whether the given variable is emitted on host or device side.
CUDAVariableTarget IdentifyTarget(const VarDecl *D);

/// Defines kinds of CUDA global host/device context where a function may be
/// called.
enum CUDATargetContextKind {
CTCK_Unknown, /// Unknown context
CTCK_InitGlobalVar, /// Function called during global variable
/// initialization
};

/// Define the current global CUDA host/device context where a function may be
/// called. Only used when a function is called outside of any functions.
struct CUDATargetContext {
CUDAFunctionTarget Target = CUDAFunctionTarget::HostDevice;
CUDATargetContextKind Kind = CTCK_Unknown;
Decl *D = nullptr;
} CurCUDATargetCtx;

struct CUDATargetContextRAII {
SemaCUDA &S;
SemaCUDA::CUDATargetContext SavedCtx;
CUDATargetContextRAII(SemaCUDA &S_, SemaCUDA::CUDATargetContextKind K,
Decl *D);
~CUDATargetContextRAII() { S.CurCUDATargetCtx = SavedCtx; }
};

/// Gets the CUDA target for the current context.
CUDAFunctionTarget CurrentTarget() {
return IdentifyTarget(dyn_cast<FunctionDecl>(SemaRef.CurContext));
}

static bool isImplicitHostDeviceFunction(const FunctionDecl *D);

// CUDA function call preference. Must be ordered numerically from
// worst to best.
enum CUDAFunctionPreference {
CFP_Never, // Invalid caller/callee combination.
CFP_WrongSide, // Calls from host-device to host or device
// function that do not match current compilation
// mode.
CFP_HostDevice, // Any calls to host/device functions.
CFP_SameSide, // Calls from host-device to host or device
// function matching current compilation mode.
CFP_Native, // host-to-host or device-to-device calls.
};

/// Identifies relative preference of a given Caller/Callee
/// combination, based on their host/device attributes.
/// \param Caller function which needs address of \p Callee.
/// nullptr in case of global context.
/// \param Callee target function
///
/// \returns preference value for particular Caller/Callee combination.
CUDAFunctionPreference IdentifyPreference(const FunctionDecl *Caller,
const FunctionDecl *Callee);

/// Determines whether Caller may invoke Callee, based on their CUDA
/// host/device attributes. Returns false if the call is not allowed.
///
/// Note: Will return true for CFP_WrongSide calls. These may appear in
/// semantically correct CUDA programs, but only if they're never codegen'ed.
bool IsAllowedCall(const FunctionDecl *Caller, const FunctionDecl *Callee) {
return IdentifyPreference(Caller, Callee) != CFP_Never;
}

/// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD,
/// depending on FD and the current compilation settings.
void maybeAddHostDeviceAttrs(FunctionDecl *FD, const LookupResult &Previous);

/// May add implicit CUDAConstantAttr attribute to VD, depending on VD
/// and current compilation settings.
void MaybeAddConstantAttr(VarDecl *VD);

/// Check whether we're allowed to call Callee from the current context.
///
/// - If the call is never allowed in a semantically-correct program
/// (CFP_Never), emits an error and returns false.
///
/// - If the call is allowed in semantically-correct programs, but only if
/// it's never codegen'ed (CFP_WrongSide), creates a deferred diagnostic to
/// be emitted if and when the caller is codegen'ed, and returns true.
///
/// Will only create deferred diagnostics for a given SourceLocation once,
/// so you can safely call this multiple times without generating duplicate
/// deferred errors.
///
/// - Otherwise, returns true without emitting any diagnostics.
bool CheckCall(SourceLocation Loc, FunctionDecl *Callee);

void CheckLambdaCapture(CXXMethodDecl *D, const sema::Capture &Capture);

/// Set __device__ or __host__ __device__ attributes on the given lambda
/// operator() method.
///
/// CUDA lambdas by default is host device function unless it has explicit
/// host or device attribute.
void SetLambdaAttrs(CXXMethodDecl *Method);

/// Record \p FD if it is a CUDA/HIP implicit host device function used on
/// device side in device compilation.
void RecordImplicitHostDeviceFuncUsedByDevice(const FunctionDecl *FD);

/// Finds a function in \p Matches with highest calling priority
/// from \p Caller context and erases all functions with lower
/// calling priority.
void EraseUnwantedMatches(
const FunctionDecl *Caller,
llvm::SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>>
&Matches);

/// Given a implicit special member, infer its CUDA target from the
/// calls it needs to make to underlying base/field special members.
/// \param ClassDecl the class for which the member is being created.
/// \param CSM the kind of special member.
/// \param MemberDecl the special member itself.
/// \param ConstRHS true if this is a copy operation with a const object on
/// its RHS.
/// \param Diagnose true if this call should emit diagnostics.
/// \return true if there was an error inferring.
/// The result of this call is implicit CUDA target attribute(s) attached to
/// the member declaration.
bool inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
CXXSpecialMemberKind CSM,
CXXMethodDecl *MemberDecl,
bool ConstRHS, bool Diagnose);

/// \return true if \p CD can be considered empty according to CUDA
/// (E.2.3.1 in CUDA 7.5 Programming guide).
bool isEmptyConstructor(SourceLocation Loc, CXXConstructorDecl *CD);
bool isEmptyDestructor(SourceLocation Loc, CXXDestructorDecl *CD);

// \brief Checks that initializers of \p Var satisfy CUDA restrictions. In
// case of error emits appropriate diagnostic and invalidates \p Var.
//
// \details CUDA allows only empty constructors as initializers for global
// variables (see E.2.3.1, CUDA 7.5). The same restriction also applies to all
// __shared__ variables whether they are local or not (they all are implicitly
// static in CUDA). One exception is that CUDA allows constant initializers
// for __constant__ and __device__ variables.
void checkAllowedInitializer(VarDecl *VD);

/// Check whether NewFD is a valid overload for CUDA. Emits
/// diagnostics and invalidates NewFD if not.
void checkTargetOverload(FunctionDecl *NewFD, const LookupResult &Previous);
/// Copies target attributes from the template TD to the function FD.
void inheritTargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD);

/// Returns the name of the launch configuration function. This is the name
/// of the function that will be called to configure kernel call, with the
/// parameters specified via <<<>>>.
std::string getConfigureFuncName() const;

private:
unsigned ForceHostDeviceDepth = 0;

friend class ASTReader;
friend class ASTWriter;
};

} // namespace clang

namespace llvm {
// Hash a FunctionDeclAndLoc by looking at both its FunctionDecl and its
// SourceLocation.
template <> struct DenseMapInfo<clang::SemaCUDA::FunctionDeclAndLoc> {
using FunctionDeclAndLoc = clang::SemaCUDA::FunctionDeclAndLoc;
using FDBaseInfo =
DenseMapInfo<clang::CanonicalDeclPtr<const clang::FunctionDecl>>;

static FunctionDeclAndLoc getEmptyKey() {
return {FDBaseInfo::getEmptyKey(), clang::SourceLocation()};
}

static FunctionDeclAndLoc getTombstoneKey() {
return {FDBaseInfo::getTombstoneKey(), clang::SourceLocation()};
}

static unsigned getHashValue(const FunctionDeclAndLoc &FDL) {
return hash_combine(FDBaseInfo::getHashValue(FDL.FD),
FDL.Loc.getHashValue());
}

static bool isEqual(const FunctionDeclAndLoc &LHS,
const FunctionDeclAndLoc &RHS) {
return LHS.FD == RHS.FD && LHS.Loc == RHS.Loc;
}
};
} // namespace llvm

#endif // LLVM_CLANG_SEMA_SEMACUDA_H
27 changes: 23 additions & 4 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,42 @@
#ifndef LLVM_CLANG_SEMA_SEMAHLSL_H
#define LLVM_CLANG_SEMA_SEMAHLSL_H

#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaBase.h"
#include <initializer_list>

namespace clang {

class SemaHLSL : public SemaBase {
public:
SemaHLSL(Sema &S);

Decl *ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
SourceLocation KwLoc, IdentifierInfo *Ident,
SourceLocation IdentLoc, SourceLocation LBrace);
void ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace);
Decl *ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc,
IdentifierInfo *Ident, SourceLocation IdentLoc,
SourceLocation LBrace);
void ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace);
HLSLNumThreadsAttr *mergeNumThreadsAttr(Decl *D,
const AttributeCommonInfo &AL, int X,
int Y, int Z);
HLSLShaderAttr *mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLShaderAttr::ShaderType ShaderType);
HLSLParamModifierAttr *
mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLParamModifierAttr::Spelling Spelling);
void ActOnTopLevelFunction(FunctionDecl *FD);
void CheckEntryPoint(FunctionDecl *FD);
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
const HLSLAnnotationAttr *AnnotationAttr);
void DiagnoseAttrStageMismatch(
const Attr *A, HLSLShaderAttr::ShaderType Stage,
std::initializer_list<HLSLShaderAttr::ShaderType> AllowedStages);
};

} // namespace clang
Expand Down
28 changes: 27 additions & 1 deletion clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ class SemaOpenACC : public SemaBase {
OpenACCDefaultClauseKind DefaultClauseKind;
};

std::variant<DefaultDetails> Details;
struct ConditionDetails {
Expr *ConditionExpr;
};

std::variant<DefaultDetails, ConditionDetails> Details;

public:
OpenACCParsedClause(OpenACCDirectiveKind DirKind,
Expand All @@ -63,6 +67,16 @@ class SemaOpenACC : public SemaBase {
return std::get<DefaultDetails>(Details).DefaultClauseKind;
}

const Expr *getConditionExpr() const {
return const_cast<OpenACCParsedClause *>(this)->getConditionExpr();
}

Expr *getConditionExpr() {
assert(ClauseKind == OpenACCClauseKind::If &&
"Parsed clause kind does not have a condition expr");
return std::get<ConditionDetails>(Details).ConditionExpr;
}

void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; }
void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); }

Expand All @@ -71,6 +85,18 @@ class SemaOpenACC : public SemaBase {
"Parsed clause is not a default clause");
Details = DefaultDetails{DefKind};
}

void setConditionDetails(Expr *ConditionExpr) {
assert(ClauseKind == OpenACCClauseKind::If &&
"Parsed clause kind does not have a condition expr");
// In C++ we can count on this being a 'bool', but in C this gets left as
// some sort of scalar that codegen will have to take care of converting.
assert((!ConditionExpr || ConditionExpr->isInstantiationDependent() ||
ConditionExpr->getType()->isScalarType()) &&
"Condition expression type not scalar/dependent");

Details = ConditionDetails{ConditionExpr};
}
};

SemaOpenACC(Sema &S);
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,10 @@ enum ASTRecordTypes {
/// Record code for an unterminated \#pragma clang assume_nonnull begin
/// recorded in a preamble.
PP_ASSUME_NONNULL_LOC = 67,

/// Record code for lexical and visible block for delayed namespace in
/// reduced BMI.
DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD = 68,
};

/// Record types used within a source manager block.
Expand Down
16 changes: 15 additions & 1 deletion clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,20 @@ class ASTReader
/// in the chain.
DeclUpdateOffsetsMap DeclUpdateOffsets;

using DelayedNamespaceOffsetMapTy = llvm::DenseMap<
serialization::DeclID,
std::pair</*LexicalOffset*/ uint64_t, /*VisibleOffset*/ uint64_t>>;

/// Mapping from global declaration IDs to the lexical and visible block
/// offset for delayed namespace in reduced BMI.
///
/// We can't use the existing DeclUpdate mechanism since the DeclUpdate
/// may only be applied in an outer most read. However, we need to know
/// whether or not a DeclContext has external storage during the recursive
/// reading. So we need to apply the offset immediately after we read the
/// namespace as if it is not delayed.
DelayedNamespaceOffsetMapTy DelayedNamespaceOffsetMap;

struct PendingUpdateRecord {
Decl *D;
serialization::GlobalDeclID ID;
Expand Down Expand Up @@ -859,7 +873,7 @@ class ASTReader

/// Our current depth in #pragma cuda force_host_device begin/end
/// macros.
unsigned ForceCUDAHostDeviceDepth = 0;
unsigned ForceHostDeviceDepth = 0;

/// The IDs of the declarations Sema stores directly.
///
Expand Down
26 changes: 25 additions & 1 deletion clang/include/clang/Serialization/ASTWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,16 @@ class ASTWriter : public ASTDeserializationListener,
/// The declarations and types to emit.
std::queue<DeclOrType> DeclTypesToEmit;

/// The delayed namespace to emit. Only meaningful for reduced BMI.
///
/// In reduced BMI, we want to elide the unreachable declarations in
/// the global module fragment. However, in ASTWriterDecl, when we see
/// a namespace, all the declarations in the namespace would be emitted.
/// So the optimization become meaningless. To solve the issue, we
/// delay recording all the declarations until we emit all the declarations.
/// Then we can safely record the reached declarations only.
llvm::SmallVector<NamespaceDecl *, 16> DelayedNamespace;

/// The first ID number we can use for our own declarations.
serialization::DeclID FirstDeclID = serialization::NUM_PREDEF_DECL_IDS;

Expand Down Expand Up @@ -529,7 +539,8 @@ class ASTWriter : public ASTDeserializationListener,
void WriteType(QualType T);

bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);
bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext *DC);
bool isLookupResultEntirelyExternalOrUnreachable(StoredDeclsList &Result,
DeclContext *DC);

void GenerateNameLookupTable(const DeclContext *DC,
llvm::SmallVectorImpl<char> &LookupTable);
Expand Down Expand Up @@ -704,6 +715,15 @@ class ASTWriter : public ASTDeserializationListener,
/// declaration.
serialization::DeclID getDeclID(const Decl *D);

/// Whether or not the declaration got emitted. If not, it wouldn't be
/// emitted.
///
/// This may only be called after we've done the job to write the
/// declarations (marked by DoneWritingDeclsAndTypes).
///
/// A declaration may only be omitted in reduced BMI.
bool wasDeclEmitted(const Decl *D) const;

unsigned getAnonymousDeclarationNumber(const NamedDecl *D);

/// Add a string to the given record.
Expand Down Expand Up @@ -798,6 +818,10 @@ class ASTWriter : public ASTDeserializationListener,
return WritingModule && WritingModule->isNamedModule();
}

bool isGeneratingReducedBMI() const { return GeneratingReducedBMI; }

bool getDoneWritingDeclsAndTypes() const { return DoneWritingDeclsAndTypes; }

private:
// ASTDeserializationListener implementation
void ReaderInitialized(ASTReader *Reader) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ class CachedFileSystemEntry {
CachedFileContents *Contents;
};

using CachedRealPath = llvm::ErrorOr<std::string>;

/// This class is a shared cache, that caches the 'stat' and 'open' calls to the
/// underlying real file system, and the scanned preprocessor directives of
/// files.
Expand All @@ -154,9 +156,11 @@ class DependencyScanningFilesystemSharedCache {
/// The mutex that needs to be locked before mutation of any member.
mutable std::mutex CacheLock;

/// Map from filenames to cached entries.
llvm::StringMap<const CachedFileSystemEntry *, llvm::BumpPtrAllocator>
EntriesByFilename;
/// Map from filenames to cached entries and real paths.
llvm::StringMap<
std::pair<const CachedFileSystemEntry *, const CachedRealPath *>,
llvm::BumpPtrAllocator>
CacheByFilename;

/// Map from unique IDs to cached entries.
llvm::DenseMap<llvm::sys::fs::UniqueID, const CachedFileSystemEntry *>
Expand All @@ -168,6 +172,9 @@ class DependencyScanningFilesystemSharedCache {
/// The backing storage for cached contents.
llvm::SpecificBumpPtrAllocator<CachedFileContents> ContentsStorage;

/// The backing storage for cached real paths.
llvm::SpecificBumpPtrAllocator<CachedRealPath> RealPathStorage;

/// Returns entry associated with the filename or nullptr if none is found.
const CachedFileSystemEntry *findEntryByFilename(StringRef Filename) const;

Expand All @@ -194,6 +201,17 @@ class DependencyScanningFilesystemSharedCache {
const CachedFileSystemEntry &
getOrInsertEntryForFilename(StringRef Filename,
const CachedFileSystemEntry &Entry);

/// Returns the real path associated with the filename or nullptr if none is
/// found.
const CachedRealPath *findRealPathByFilename(StringRef Filename) const;

/// Returns the real path associated with the filename if there is some.
/// Otherwise, constructs new one with the given one, associates it with the
/// filename and returns the result.
const CachedRealPath &
getOrEmplaceRealPathForFilename(StringRef Filename,
llvm::ErrorOr<StringRef> RealPath);
};

DependencyScanningFilesystemSharedCache();
Expand All @@ -210,14 +228,17 @@ class DependencyScanningFilesystemSharedCache {
/// This class is a local cache, that caches the 'stat' and 'open' calls to the
/// underlying real file system.
class DependencyScanningFilesystemLocalCache {
llvm::StringMap<const CachedFileSystemEntry *, llvm::BumpPtrAllocator> Cache;
llvm::StringMap<
std::pair<const CachedFileSystemEntry *, const CachedRealPath *>,
llvm::BumpPtrAllocator>
Cache;

public:
/// Returns entry associated with the filename or nullptr if none is found.
const CachedFileSystemEntry *findEntryByFilename(StringRef Filename) const {
assert(llvm::sys::path::is_absolute_gnu(Filename));
auto It = Cache.find(Filename);
return It == Cache.end() ? nullptr : It->getValue();
return It == Cache.end() ? nullptr : It->getValue().first;
}

/// Associates the given entry with the filename and returns the given entry
Expand All @@ -226,9 +247,40 @@ class DependencyScanningFilesystemLocalCache {
insertEntryForFilename(StringRef Filename,
const CachedFileSystemEntry &Entry) {
assert(llvm::sys::path::is_absolute_gnu(Filename));
const auto *InsertedEntry = Cache.insert({Filename, &Entry}).first->second;
assert(InsertedEntry == &Entry && "entry already present");
return *InsertedEntry;
auto [It, Inserted] = Cache.insert({Filename, {&Entry, nullptr}});
auto &[CachedEntry, CachedRealPath] = It->getValue();
if (!Inserted) {
// The file is already present in the local cache. If we got here, it only
// contains the real path. Let's make sure the entry is populated too.
assert((!CachedEntry && CachedRealPath) && "entry already present");
CachedEntry = &Entry;
}
return *CachedEntry;
}

/// Returns real path associated with the filename or nullptr if none is
/// found.
const CachedRealPath *findRealPathByFilename(StringRef Filename) const {
assert(llvm::sys::path::is_absolute_gnu(Filename));
auto It = Cache.find(Filename);
return It == Cache.end() ? nullptr : It->getValue().second;
}

/// Associates the given real path with the filename and returns the given
/// entry pointer (for convenience).
const CachedRealPath &
insertRealPathForFilename(StringRef Filename,
const CachedRealPath &RealPath) {
assert(llvm::sys::path::is_absolute_gnu(Filename));
auto [It, Inserted] = Cache.insert({Filename, {nullptr, &RealPath}});
auto &[CachedEntry, CachedRealPath] = It->getValue();
if (!Inserted) {
// The file is already present in the local cache. If we got here, it only
// contains the entry. Let's make sure the real path is populated too.
assert((!CachedRealPath && CachedEntry) && "real path already present");
CachedRealPath = &RealPath;
}
return *CachedRealPath;
}
};

Expand Down Expand Up @@ -296,6 +348,9 @@ class DependencyScanningWorkerFilesystem
llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
openFileForRead(const Twine &Path) override;

std::error_code getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) override;

std::error_code setCurrentWorkingDirectory(const Twine &Path) override;

/// Returns entry for the given filename.
Expand All @@ -310,6 +365,10 @@ class DependencyScanningWorkerFilesystem
/// false if not (i.e. this entry is not a file or its scan fails).
bool ensureDirectiveTokensArePopulated(EntryRef Entry);

/// Check whether \p Path exists. By default checks cached result of \c
/// status(), and falls back on FS if unable to do so.
bool exists(const Twine &Path) override;

private:
/// For a filename that's not yet associated with any entry in the caches,
/// uses the underlying filesystem to either look up the entry based in the
Expand Down Expand Up @@ -402,6 +461,10 @@ class DependencyScanningWorkerFilesystem
llvm::ErrorOr<std::string> WorkingDirForCacheLookup;

void updateWorkingDirForCacheLookup();

llvm::ErrorOr<StringRef>
tryGetFilenameForLookup(StringRef OriginalFilename,
llvm::SmallVectorImpl<char> &PathBuf) const;
};

} // end namespace dependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@ class ModuleDepCollector final : public DependencyCollector {
ModuleDeps &Deps);
};

/// Resets codegen options that don't affect modules/PCH.
void resetBenignCodeGenOptions(frontend::ActionKind ProgramAction,
const LangOptions &LangOpts,
CodeGenOptions &CGOpts);

} // end namespace dependencies
} // end namespace tooling
} // end namespace clang
Expand Down
137 changes: 55 additions & 82 deletions clang/lib/APINotes/APINotesReader.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(

TemplateTemplateParmDecl *CanonTTP = TemplateTemplateParmDecl::Create(
*this, getTranslationUnitDecl(), SourceLocation(), TTP->getDepth(),
TTP->getPosition(), TTP->isParameterPack(), nullptr,
TTP->getPosition(), TTP->isParameterPack(), nullptr, /*Typename=*/false,
TemplateParameterList::Create(*this, SourceLocation(), SourceLocation(),
CanonParams, SourceLocation(),
/*RequiresClause=*/nullptr));
Expand Down
16 changes: 15 additions & 1 deletion clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3947,6 +3947,14 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// decl and its redeclarations may be required.
}

StringLiteral *Msg = D->getDeletedMessage();
if (Msg) {
auto Imported = import(Msg);
if (!Imported)
return Imported.takeError();
Msg = *Imported;
}

ToFunction->setQualifierInfo(ToQualifierLoc);
ToFunction->setAccess(D->getAccess());
ToFunction->setLexicalDeclContext(LexicalDC);
Expand All @@ -3961,6 +3969,11 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToFunction->setRangeEnd(ToEndLoc);
ToFunction->setDefaultLoc(ToDefaultLoc);

if (Msg)
ToFunction->setDefaultedOrDeletedInfo(
FunctionDecl::DefaultedOrDeletedFunctionInfo::Create(
Importer.getToContext(), {}, Msg));

// Set the parameters.
for (auto *Param : Parameters) {
Param->setOwningFunction(ToFunction);
Expand Down Expand Up @@ -5952,7 +5965,8 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
ToD, D, Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(), *LocationOrErr,
D->getDepth(), D->getPosition(), D->isParameterPack(),
(*NameOrErr).getAsIdentifierInfo(), *TemplateParamsOrErr))
(*NameOrErr).getAsIdentifierInfo(), D->wasDeclaredWithTypename(),
*TemplateParamsOrErr))
return ToD;

if (D->hasDefaultArgument()) {
Expand Down
69 changes: 52 additions & 17 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3058,7 +3058,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.IsTrivialForCall = false;
FunctionDeclBits.IsDefaulted = false;
FunctionDeclBits.IsExplicitlyDefaulted = false;
FunctionDeclBits.HasDefaultedFunctionInfo = false;
FunctionDeclBits.HasDefaultedOrDeletedInfo = false;
FunctionDeclBits.IsIneligibleOrNotSelected = false;
FunctionDeclBits.HasImplicitReturnZero = false;
FunctionDeclBits.IsLateTemplateParsed = false;
Expand Down Expand Up @@ -3092,30 +3092,65 @@ bool FunctionDecl::isVariadic() const {
return false;
}

FunctionDecl::DefaultedFunctionInfo *
FunctionDecl::DefaultedFunctionInfo::Create(ASTContext &Context,
ArrayRef<DeclAccessPair> Lookups) {
DefaultedFunctionInfo *Info = new (Context.Allocate(
totalSizeToAlloc<DeclAccessPair>(Lookups.size()),
std::max(alignof(DefaultedFunctionInfo), alignof(DeclAccessPair))))
DefaultedFunctionInfo;
FunctionDecl::DefaultedOrDeletedFunctionInfo *
FunctionDecl::DefaultedOrDeletedFunctionInfo::Create(
ASTContext &Context, ArrayRef<DeclAccessPair> Lookups,
StringLiteral *DeletedMessage) {
static constexpr size_t Alignment =
std::max({alignof(DefaultedOrDeletedFunctionInfo),
alignof(DeclAccessPair), alignof(StringLiteral *)});
size_t Size = totalSizeToAlloc<DeclAccessPair, StringLiteral *>(
Lookups.size(), DeletedMessage != nullptr);

DefaultedOrDeletedFunctionInfo *Info =
new (Context.Allocate(Size, Alignment)) DefaultedOrDeletedFunctionInfo;
Info->NumLookups = Lookups.size();
Info->HasDeletedMessage = DeletedMessage != nullptr;

std::uninitialized_copy(Lookups.begin(), Lookups.end(),
Info->getTrailingObjects<DeclAccessPair>());
if (DeletedMessage)
*Info->getTrailingObjects<StringLiteral *>() = DeletedMessage;
return Info;
}

void FunctionDecl::setDefaultedFunctionInfo(DefaultedFunctionInfo *Info) {
assert(!FunctionDeclBits.HasDefaultedFunctionInfo && "already have this");
void FunctionDecl::setDefaultedOrDeletedInfo(
DefaultedOrDeletedFunctionInfo *Info) {
assert(!FunctionDeclBits.HasDefaultedOrDeletedInfo && "already have this");
assert(!Body && "can't replace function body with defaulted function info");

FunctionDeclBits.HasDefaultedFunctionInfo = true;
DefaultedInfo = Info;
FunctionDeclBits.HasDefaultedOrDeletedInfo = true;
DefaultedOrDeletedInfo = Info;
}

void FunctionDecl::setDeletedAsWritten(bool D, StringLiteral *Message) {
FunctionDeclBits.IsDeleted = D;

if (Message) {
assert(isDeletedAsWritten() && "Function must be deleted");
if (FunctionDeclBits.HasDefaultedOrDeletedInfo)
DefaultedOrDeletedInfo->setDeletedMessage(Message);
else
setDefaultedOrDeletedInfo(DefaultedOrDeletedFunctionInfo::Create(
getASTContext(), /*Lookups=*/{}, Message));
}
}

void FunctionDecl::DefaultedOrDeletedFunctionInfo::setDeletedMessage(
StringLiteral *Message) {
// We should never get here with the DefaultedOrDeletedInfo populated, but
// no space allocated for the deleted message, since that would require
// recreating this, but setDefaultedOrDeletedInfo() disallows overwriting
// an already existing DefaultedOrDeletedFunctionInfo.
assert(HasDeletedMessage &&
"No space to store a delete message in this DefaultedOrDeletedInfo");
*getTrailingObjects<StringLiteral *>() = Message;
}

FunctionDecl::DefaultedFunctionInfo *
FunctionDecl::getDefaultedFunctionInfo() const {
return FunctionDeclBits.HasDefaultedFunctionInfo ? DefaultedInfo : nullptr;
FunctionDecl::DefaultedOrDeletedFunctionInfo *
FunctionDecl::getDefalutedOrDeletedInfo() const {
return FunctionDeclBits.HasDefaultedOrDeletedInfo ? DefaultedOrDeletedInfo
: nullptr;
}

bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
Expand Down Expand Up @@ -3202,7 +3237,7 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
if (!hasBody(Definition))
return nullptr;

assert(!Definition->FunctionDeclBits.HasDefaultedFunctionInfo &&
assert(!Definition->FunctionDeclBits.HasDefaultedOrDeletedInfo &&
"definition should not have a body");
if (Definition->Body)
return Definition->Body.get(getASTContext().getExternalSource());
Expand All @@ -3211,7 +3246,7 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
}

void FunctionDecl::setBody(Stmt *B) {
FunctionDeclBits.HasDefaultedFunctionInfo = false;
FunctionDeclBits.HasDefaultedOrDeletedInfo = false;
Body = LazyDeclStmtPtr(B);
if (B)
EndRangeLoc = B->getEndLoc();
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,9 +822,14 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {

if (D->isPureVirtual())
Out << " = 0";
else if (D->isDeletedAsWritten())
else if (D->isDeletedAsWritten()) {
Out << " = delete";
else if (D->isExplicitlyDefaulted())
if (const StringLiteral *M = D->getDeletedMessage()) {
Out << "(";
M->outputString(Out);
Out << ")";
}
} else if (D->isExplicitlyDefaulted())
Out << " = default";
else if (D->doesThisDeclarationHaveABody()) {
if (!Policy.TerseOutput) {
Expand Down Expand Up @@ -1218,7 +1223,10 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {

if (const TemplateTemplateParmDecl *TTP =
dyn_cast<TemplateTemplateParmDecl>(D)) {
Out << "class";
if (TTP->wasDeclaredWithTypename())
Out << "typename";
else
Out << "class";

if (TTP->isParameterPack())
Out << " ...";
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,10 +805,10 @@ void TemplateTemplateParmDecl::anchor() {}

TemplateTemplateParmDecl::TemplateTemplateParmDecl(
DeclContext *DC, SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id, TemplateParameterList *Params,
IdentifierInfo *Id, bool Typename, TemplateParameterList *Params,
ArrayRef<TemplateParameterList *> Expansions)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
TemplateParmPosition(D, P), ParameterPack(true),
TemplateParmPosition(D, P), Typename(Typename), ParameterPack(true),
ExpandedParameterPack(true), NumExpandedParams(Expansions.size()) {
if (!Expansions.empty())
std::uninitialized_copy(Expansions.begin(), Expansions.end(),
Expand All @@ -819,26 +819,26 @@ TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
bool ParameterPack, IdentifierInfo *Id,
TemplateParameterList *Params) {
bool Typename, TemplateParameterList *Params) {
return new (C, DC) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id,
Params);
Typename, Params);
}

TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id,
IdentifierInfo *Id, bool Typename,
TemplateParameterList *Params,
ArrayRef<TemplateParameterList *> Expansions) {
return new (C, DC,
additionalSizeToAlloc<TemplateParameterList *>(Expansions.size()))
TemplateTemplateParmDecl(DC, L, D, P, Id, Params, Expansions);
TemplateTemplateParmDecl(DC, L, D, P, Id, Typename, Params, Expansions);
}

TemplateTemplateParmDecl *
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0,
false, nullptr, nullptr);
false, nullptr, false, nullptr);
}

TemplateTemplateParmDecl *
Expand All @@ -847,7 +847,7 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
auto *TTP =
new (C, ID, additionalSizeToAlloc<TemplateParameterList *>(NumExpansions))
TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, nullptr,
nullptr, std::nullopt);
false, nullptr, std::nullopt);
TTP->NumExpandedParams = NumExpansions;
return TTP;
}
Expand Down Expand Up @@ -1469,7 +1469,7 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
// template <typename T, ...Ints> class IntSeq
auto *TemplateTemplateParm = TemplateTemplateParmDecl::Create(
C, DC, SourceLocation(), /*Depth=*/0, /*Position=*/0,
/*ParameterPack=*/false, /*Id=*/nullptr, TPL);
/*ParameterPack=*/false, /*Id=*/nullptr, /*Typename=*/false, TPL);
TemplateTemplateParm->setImplicit(true);

// typename T
Expand Down
34 changes: 21 additions & 13 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2778,26 +2778,34 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
std::optional<PrimType> VarT = classify(VD->getType());

if (Context::shouldBeGloballyIndexed(VD)) {
// We've already seen and initialized this global.
if (P.getGlobal(VD))
return true;

std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);

if (!GlobalIndex)
return false;

if (Init) {
auto initGlobal = [&](unsigned GlobalIndex) -> bool {
assert(Init);
DeclScope<Emitter> LocalScope(this, VD);

if (VarT) {
if (!this->visit(Init))
return false;
return this->emitInitGlobal(*VarT, *GlobalIndex, VD);
return this->emitInitGlobal(*VarT, GlobalIndex, VD);
}
return this->visitGlobalInitializer(Init, *GlobalIndex);
return this->visitGlobalInitializer(Init, GlobalIndex);
};

// We've already seen and initialized this global.
if (std::optional<unsigned> GlobalIndex = P.getGlobal(VD)) {
if (P.getPtrGlobal(*GlobalIndex).isInitialized())
return true;

// The previous attempt at initialization might've been unsuccessful,
// so let's try this one.
return Init && initGlobal(*GlobalIndex);
}
return true;

std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);

if (!GlobalIndex)
return false;

return !Init || initGlobal(*GlobalIndex);
} else {
VariableScope<Emitter> LocalScope(this);
if (VarT) {
Expand Down
26 changes: 20 additions & 6 deletions clang/lib/AST/Interp/FunctionPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,45 @@ namespace interp {
class FunctionPointer final {
private:
const Function *Func;
bool Valid;

public:
// FIXME: We might want to track the fact that the Function pointer
// has been created from an integer and is most likely garbage anyway.
FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr)
: Func(reinterpret_cast<const Function *>(IntVal)) {}
FunctionPointer(const Function *Func) : Func(Func), Valid(true) {
assert(Func);
}

FunctionPointer(const Function *Func) : Func(Func) { assert(Func); }
FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr)
: Func(reinterpret_cast<const Function *>(IntVal)), Valid(false) {}

const Function *getFunction() const { return Func; }
bool isZero() const { return !Func; }
bool isWeak() const {
if (!Func || !Valid)
return false;

return Func->getDecl()->isWeak();
}

APValue toAPValue() const {
if (!Func)
return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {},
/*OnePastTheEnd=*/false, /*IsNull=*/true);

if (!Valid)
return APValue(static_cast<Expr *>(nullptr),
CharUnits::fromQuantity(getIntegerRepresentation()), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);

return APValue(Func->getDecl(), CharUnits::Zero(), {},
/*OnePastTheEnd=*/false, /*IsNull=*/false);
}

void print(llvm::raw_ostream &OS) const {
OS << "FnPtr(";
if (Func)
if (Func && Valid)
OS << Func->getName();
else if (Func)
OS << reinterpret_cast<uintptr_t>(Func);
else
OS << "nullptr";
OS << ")";
Expand Down
99 changes: 62 additions & 37 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,65 @@ static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
return true;
}

static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC,
const ValueDecl *VD) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
}

static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
const ValueDecl *VD);
static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
const ValueDecl *D) {
const SourceInfo &E = S.Current->getSource(OpPC);

if (isa<ParmVarDecl>(D)) {
if (S.getLangOpts().CPlusPlus11) {
S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
} else {
S.FFDiag(E);
}
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!VD->getType().isConstQualified()) {
diagnoseNonConstVariable(S, OpPC, VD);
return false;
}

// const, but no initializer.
if (!VD->getAnyInitializer()) {
diagnoseMissingInitializer(S, OpPC, VD);
return false;
}
}
return false;
}

static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
const ValueDecl *VD) {
if (!S.getLangOpts().CPlusPlus)
return;

const SourceInfo &Loc = S.Current->getSource(OpPC);
if (const auto *VarD = dyn_cast<VarDecl>(VD);
VarD && VarD->getType().isConstQualified() &&
!VarD->getAnyInitializer()) {
diagnoseMissingInitializer(S, OpPC, VD);
return;
}

if (VD->getType()->isIntegralOrEnumerationType())
if (VD->getType()->isIntegralOrEnumerationType()) {
S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
else
S.FFDiag(Loc,
S.getLangOpts().CPlusPlus11
? diag::note_constexpr_ltor_non_constexpr
: diag::note_constexpr_ltor_non_integral,
1)
<< VD << VD->getType();
S.Note(VD->getLocation(), diag::note_declared_at);
return;
}

S.FFDiag(Loc,
S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
: diag::note_constexpr_ltor_non_integral,
1)
<< VD << VD->getType();
S.Note(VD->getLocation(), diag::note_declared_at);
}

Expand Down Expand Up @@ -202,6 +245,9 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!Ptr.isExtern())
return true;

if (Ptr.isInitialized())
return true;

if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {
const auto *VD = Ptr.getDeclDesc()->asValueDecl();
diagnoseNonConstVariable(S, OpPC, VD);
Expand Down Expand Up @@ -369,9 +415,15 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
VD && VD->hasGlobalStorage()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at);
if (VD->getAnyInitializer()) {
S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at);
} else {
diagnoseMissingInitializer(S, OpPC, VD);
}
return false;
}

if (!S.checkingPotentialConstantExpression()) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
<< AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
Expand Down Expand Up @@ -598,33 +650,6 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
return true;
}

static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
const ValueDecl *D) {
const SourceInfo &E = S.Current->getSource(OpPC);

if (isa<ParmVarDecl>(D)) {
if (S.getLangOpts().CPlusPlus11) {
S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
} else {
S.FFDiag(E);
}
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!VD->getType().isConstQualified()) {
diagnoseNonConstVariable(S, OpPC, VD);
return false;
}

// const, but no initializer.
if (!VD->getAnyInitializer()) {
S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
return false;
}
}
return false;
}

/// We aleady know the given DeclRefExpr is invalid for some reason,
/// now figure out why and print appropriate diagnostics.
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,

// We cannot compare against weak declarations at compile time.
for (const auto &FP : {LHS, RHS}) {
if (!FP.isZero() && FP.getFunction()->getDecl()->isWeak()) {
if (FP.isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
<< FP.toDiagnosticString(S.getCtx());
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/AST/Interp/InterpState.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ class InterpState final : public State, public SourceMapper {

/// Delegates source mapping to the mapper.
SourceInfo getSource(const Function *F, CodePtr PC) const override {
return M ? M->getSource(F, PC) : F->getSource(PC);
if (M)
return M->getSource(F, PC);

assert(F && "Function cannot be null");
return F->getSource(PC);
}

Context &getContext() const { return Ctx; }
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
bool IsStatic, IsExtern;
if (const auto *Var = dyn_cast<VarDecl>(VD)) {
IsStatic = Context::shouldBeGloballyIndexed(VD);
IsExtern = !Var->getAnyInitializer();
IsExtern = Var->hasExternalStorage();
} else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl>(VD)) {
IsStatic = true;
IsExtern = false;
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/AST/JSONNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,9 @@ void JSONNodeDumper::VisitFunctionDecl(const FunctionDecl *FD) {
if (FD->isDefaulted())
JOS.attribute("explicitlyDefaulted",
FD->isDeleted() ? "deleted" : "default");

if (StringLiteral *Msg = FD->getDeletedMessage())
JOS.attribute("deletedMessage", Msg->getString());
}

void JSONNodeDumper::VisitEnumDecl(const EnumDecl *ED) {
Expand Down Expand Up @@ -1576,6 +1579,14 @@ void JSONNodeDumper::VisitMaterializeTemporaryExpr(
attributeOnlyIfTrue("boundToLValueRef", MTE->isBoundToLvalueReference());
}

void JSONNodeDumper::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node) {
attributeOnlyIfTrue("hasRewrittenInit", Node->hasRewrittenInit());
}

void JSONNodeDumper::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node) {
attributeOnlyIfTrue("hasRewrittenInit", Node->hasRewrittenInit());
}

void JSONNodeDumper::VisitCXXDependentScopeMemberExpr(
const CXXDependentScopeMemberExpr *DSME) {
JOS.attribute("isArrow", DSME->isArrow());
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ODRHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,12 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
AddBoolean(Function->isDeletedAsWritten());
AddBoolean(Function->isExplicitlyDefaulted());

StringLiteral *DeletedMessage = Function->getDeletedMessage();
AddBoolean(DeletedMessage);

if (DeletedMessage)
ID.AddString(DeletedMessage->getBytes());

AddDecl(Function);

AddQualType(Function->getReturnType());
Expand Down
42 changes: 40 additions & 2 deletions clang/lib/AST/OpenACCClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "clang/AST/OpenACCClause.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"

using namespace clang;

Expand All @@ -27,10 +28,47 @@ OpenACCDefaultClause *OpenACCDefaultClause::Create(const ASTContext &C,
return new (Mem) OpenACCDefaultClause(K, BeginLoc, LParenLoc, EndLoc);
}

OpenACCIfClause *OpenACCIfClause::Create(const ASTContext &C,
SourceLocation BeginLoc,
SourceLocation LParenLoc,
Expr *ConditionExpr,
SourceLocation EndLoc) {
void *Mem = C.Allocate(sizeof(OpenACCIfClause), alignof(OpenACCIfClause));
return new (Mem) OpenACCIfClause(BeginLoc, LParenLoc, ConditionExpr, EndLoc);
}

OpenACCIfClause::OpenACCIfClause(SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *ConditionExpr,
SourceLocation EndLoc)
: OpenACCClauseWithCondition(OpenACCClauseKind::If, BeginLoc, LParenLoc,
ConditionExpr, EndLoc) {
assert(ConditionExpr && "if clause requires condition expr");
assert((ConditionExpr->isInstantiationDependent() ||
ConditionExpr->getType()->isScalarType()) &&
"Condition expression type not scalar/dependent");
}

OpenACCClause::child_range OpenACCClause::children() {
switch (getClauseKind()) {
default:
assert(false && "Clause children function not implemented");
break;
#define VISIT_CLAUSE(CLAUSE_NAME) \
case OpenACCClauseKind::CLAUSE_NAME: \
return cast<OpenACC##CLAUSE_NAME##Clause>(this)->children();

#include "clang/Basic/OpenACCClauses.def"
}
return child_range(child_iterator(), child_iterator());
}

//===----------------------------------------------------------------------===//
// OpenACC clauses printing methods
//===----------------------------------------------------------------------===//
void OpenACCClausePrinter::VisitOpenACCDefaultClause(
const OpenACCDefaultClause &C) {
void OpenACCClausePrinter::VisitDefaultClause(const OpenACCDefaultClause &C) {
OS << "default(" << C.getDefaultClauseKind() << ")";
}

void OpenACCClausePrinter::VisitIfClause(const OpenACCIfClause &C) {
OS << "if(" << C.getConditionExpr() << ")";
}
19 changes: 15 additions & 4 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2445,9 +2445,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
namespace {
class OpenACCClauseProfiler
: public OpenACCClauseVisitor<OpenACCClauseProfiler> {
StmtProfiler &Profiler;

public:
OpenACCClauseProfiler() = default;
OpenACCClauseProfiler(StmtProfiler &P) : Profiler(P) {}

void VisitOpenACCClauseList(ArrayRef<const OpenACCClause *> Clauses) {
for (const OpenACCClause *Clause : Clauses) {
Expand All @@ -2456,20 +2457,30 @@ class OpenACCClauseProfiler
Visit(Clause);
}
}
void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause);

#define VISIT_CLAUSE(CLAUSE_NAME) \
void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause);

#include "clang/Basic/OpenACCClauses.def"
};

/// Nothing to do here, there are no sub-statements.
void OpenACCClauseProfiler::VisitOpenACCDefaultClause(
void OpenACCClauseProfiler::VisitDefaultClause(
const OpenACCDefaultClause &Clause) {}

void OpenACCClauseProfiler::VisitIfClause(const OpenACCIfClause &Clause) {
assert(Clause.hasConditionExpr() &&
"if clause requires a valid condition expr");
Profiler.VisitStmt(Clause.getConditionExpr());
}
} // namespace

void StmtProfiler::VisitOpenACCComputeConstruct(
const OpenACCComputeConstruct *S) {
// VisitStmt handles children, so the AssociatedStmt is handled.
VisitStmt(S);

OpenACCClauseProfiler P;
OpenACCClauseProfiler P{*this};
P.VisitOpenACCClauseList(S->clauses());
}

Expand Down
22 changes: 10 additions & 12 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,11 @@ void TextNodeDumper::Visit(const OpenACCClause *C) {
case OpenACCClauseKind::Default:
OS << '(' << cast<OpenACCDefaultClause>(C)->getDefaultClauseKind() << ')';
break;
case OpenACCClauseKind::If:
// The condition expression will be printed as a part of the 'children',
// but print 'clause' here so it is clear what is happening from the dump.
OS << " clause";
break;
default:
// Nothing to do here.
break;
Expand Down Expand Up @@ -1450,23 +1455,13 @@ void TextNodeDumper::VisitExpressionTraitExpr(const ExpressionTraitExpr *Node) {
}

void TextNodeDumper::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node) {
if (Node->hasRewrittenInit()) {
if (Node->hasRewrittenInit())
OS << " has rewritten init";
AddChild([=] {
ColorScope Color(OS, ShowColors, StmtColor);
Visit(Node->getExpr());
});
}
}

void TextNodeDumper::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node) {
if (Node->hasRewrittenInit()) {
if (Node->hasRewrittenInit())
OS << " has rewritten init";
AddChild([=] {
ColorScope Color(OS, ShowColors, StmtColor);
Visit(Node->getExpr());
});
}
}

void TextNodeDumper::VisitMaterializeTemporaryExpr(
Expand Down Expand Up @@ -1966,6 +1961,9 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) {
if (D->isTrivial())
OS << " trivial";

if (const StringLiteral *M = D->getDeletedMessage())
AddChild("delete message", [=] { Visit(M); });

if (D->isIneligibleOrNotSelected())
OS << (isa<CXXDestructorDecl>(D) ? " not_selected" : " ineligible");

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,11 @@ class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {
isa<CXXStdInitializerListExpr>(E)) {
return;
}
if (auto *Op = dyn_cast<BinaryOperator>(E);
Op && Op->getOpcode() == BO_Cmp) {
// Builtin `<=>` returns a `std::strong_ordering` object.
return;
}

if (auto *InitList = dyn_cast<InitListExpr>(E)) {
if (!InitList->isSemanticForm())
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ bool Module::directlyUses(const Module *Requested) {
if (Requested->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}) ||
Requested->fullModuleNameIs({"_Builtin_stddef_wint_t"}))
return true;
// Darwin is allowed is to use our builtin 'ptrauth.h' and its accompanying
// module.
if (!Requested->Parent && Requested->Name == "ptrauth")
return true;

if (NoUndeclaredIncludes)
UndeclaredUses.insert(Requested);
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__CCMP__");
if (HasCF)
Builder.defineMacro("__CF__");
// Condition here is aligned with the feature set of mapxf in Options.td
if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD)
Builder.defineMacro("__APX_F__");

// Each case falls through to the previous one here.
switch (SSELevel) {
Expand Down
Empty file added clang/lib/CIR/CMakeLists.txt
Empty file.
4 changes: 4 additions & 0 deletions clang/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ if(CLANG_INCLUDE_TESTS)
endif()
add_subdirectory(Interpreter)
add_subdirectory(Support)

if(CLANG_ENABLE_CIR)
add_subdirectory(CIR)
endif()
6 changes: 5 additions & 1 deletion clang/lib/CodeGen/CGAtomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1806,7 +1806,11 @@ void AtomicInfo::EmitAtomicUpdateOp(
/*NumReservedValues=*/2);
PHI->addIncoming(OldVal, CurBB);
Address NewAtomicAddr = CreateTempAlloca();
Address NewAtomicIntAddr = castToAtomicIntPointer(NewAtomicAddr);
Address NewAtomicIntAddr =
shouldCastToInt(NewAtomicAddr.getElementType(), /*CmpXchg=*/true)
? castToAtomicIntPointer(NewAtomicAddr)
: NewAtomicAddr;

if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
requiresMemSetZero(getAtomicAddress().getElementType())) {
CGF.Builder.CreateStore(PHI, NewAtomicIntAddr);
Expand Down
16 changes: 12 additions & 4 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18194,7 +18194,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
/*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
Intrinsic::dx_any, ArrayRef<Value *>{Op0}, nullptr, "dx.any");
CGM.getHLSLRuntime().getAnyIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
"hlsl.any");
}
case Builtin::BI__builtin_hlsl_elementwise_clamp: {
Value *OpX = EmitScalarExpr(E->getArg(0));
Expand Down Expand Up @@ -18303,9 +18304,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *Op0 = EmitScalarExpr(E->getArg(0));
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("rcp operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType=*/Op0->getType(), Intrinsic::dx_rcp,
ArrayRef<Value *>{Op0}, nullptr, "dx.rcp");
llvm::Type *Ty = Op0->getType();
llvm::Type *EltTy = Ty->getScalarType();
Constant *One =
Ty->isVectorTy()
? ConstantVector::getSplat(
ElementCount::getFixed(
dyn_cast<FixedVectorType>(Ty)->getNumElements()),
ConstantFP::get(EltTy, 1.0))
: ConstantFP::get(EltTy, 1.0);
return Builder.CreateFDiv(One, Op0, "hlsl.rcp");
}
case Builtin::BI__builtin_hlsl_elementwise_rsqrt: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4124,7 +4124,8 @@ static bool isProvablyNull(llvm::Value *addr) {
}

static bool isProvablyNonNull(Address Addr, CodeGenFunction &CGF) {
return llvm::isKnownNonZero(Addr.getBasePointer(), CGF.CGM.getDataLayout());
return llvm::isKnownNonZero(Addr.getBasePointer(), /*Depth=*/0,
CGF.CGM.getDataLayout());
}

/// Emit the actual writing-back of a writeback.
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2216,8 +2216,11 @@ void CodeGenFunction::pushDestroyAndDeferDeactivation(
void CodeGenFunction::pushDestroyAndDeferDeactivation(
CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray) {
pushCleanupAndDeferDeactivation<DestroyObject>(
cleanupKind, addr, type, destroyer, useEHCleanupForArray);
llvm::Instruction *DominatingIP =
Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
pushDestroy(cleanupKind, addr, type, destroyer, useEHCleanupForArray);
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
}

void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class CGHLSLRuntime {
//===----------------------------------------------------------------------===//

GENERATE_HLSL_INTRINSIC_FUNCTION(All, all)
GENERATE_HLSL_INTRINSIC_FUNCTION(Any, any)
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)

//===----------------------------------------------------------------------===//
Expand Down
84 changes: 44 additions & 40 deletions clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ namespace {
/// contains enough information to determine where the runs break. Microsoft
/// and Itanium follow different rules and use different codepaths.
/// * It is desired that, when possible, bitfields use the appropriate iN type
/// when lowered to llvm types. For example unsigned x : 24 gets lowered to
/// when lowered to llvm types. For example unsigned x : 24 gets lowered to
/// i24. This isn't always possible because i24 has storage size of 32 bit
/// and if it is possible to use that extra byte of padding we must use
/// [i8 x 3] instead of i24. The function clipTailPadding does this.
/// and if it is possible to use that extra byte of padding we must use [i8 x
/// 3] instead of i24. This is computed when accumulating bitfields in
/// accumulateBitfields.
/// C++ examples that require clipping:
/// struct { int a : 24; char b; }; // a must be clipped, b goes at offset 3
/// struct A { int a : 24; ~A(); }; // a must be clipped because:
Expand All @@ -62,11 +63,7 @@ namespace {
/// that the tail padding is not used in the complete class.) However,
/// because LLVM reads from the complete type it can generate incorrect code
/// if we do not clip the tail padding off of the bitfield in the complete
/// layout. This introduces a somewhat awkward extra unnecessary clip stage.
/// The location of the clip is stored internally as a sentinel of type
/// SCISSOR. If LLVM were updated to read base types (which it probably
/// should because locations of things such as VBases are bogus in the llvm
/// type anyway) then we could eliminate the SCISSOR.
/// layout.
/// * Itanium allows nearly empty primary virtual bases. These bases don't get
/// get their own storage because they're laid out as part of another base
/// or at the beginning of the structure. Determining if a VBase actually
Expand Down Expand Up @@ -200,9 +197,7 @@ struct CGRecordLowering {
const CXXRecordDecl *Query) const;
void calculateZeroInit();
CharUnits calculateTailClippingOffset(bool isNonVirtualBaseType) const;
/// Lowers bitfield storage types to I8 arrays for bitfields with tail
/// padding that is or can potentially be used.
void clipTailPadding();
void checkBitfieldClipping() const;
/// Determines if we need a packed llvm struct.
void determinePacked(bool NVBaseType);
/// Inserts padding everywhere it's needed.
Expand Down Expand Up @@ -305,7 +300,7 @@ void CGRecordLowering::lower(bool NVBaseType) {
}
llvm::stable_sort(Members);
Members.push_back(StorageInfo(Size, getIntNType(8)));
clipTailPadding();
checkBitfieldClipping();
determinePacked(NVBaseType);
insertPadding();
Members.pop_back();
Expand Down Expand Up @@ -531,6 +526,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// available padding characters.
RecordDecl::field_iterator BestEnd = Begin;
CharUnits BestEndOffset;
bool BestClipped; // Whether the representation must be in a byte array.

for (;;) {
// AtAlignedBoundary is true iff Field is the (potential) start of a new
Expand Down Expand Up @@ -593,10 +589,9 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// this is the best seen so far.
BestEnd = Field;
BestEndOffset = BeginOffset + AccessSize;
if (Types.getCodeGenOpts().FineGrainedBitfieldAccesses)
// Fine-grained access, so no merging of spans.
InstallBest = true;
else if (!BitSizeSinceBegin)
// Assume clipped until proven not below.
BestClipped = true;
if (!BitSizeSinceBegin)
// A zero-sized initial span -- this will install nothing and reset
// for another.
InstallBest = true;
Expand Down Expand Up @@ -624,6 +619,12 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// The access unit is not at a naturally aligned offset within the
// structure.
InstallBest = true;

if (InstallBest && BestEnd == Field)
// We're installing the first span, whose clipping was presumed
// above. Compute it correctly.
if (getSize(Type) == AccessSize)
BestClipped = false;
}

if (!InstallBest) {
Expand Down Expand Up @@ -656,11 +657,15 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// access unit.
BestEndOffset = BeginOffset + TypeSize;
BestEnd = Field;
BestClipped = false;
}

if (Barrier)
// The next field is a barrier that we cannot merge across.
InstallBest = true;
else if (Types.getCodeGenOpts().FineGrainedBitfieldAccesses)
// Fine-grained access, so no merging of spans.
InstallBest = true;
else
// Otherwise, we're not installing. Update the bit size
// of the current span to go all the way to LimitOffset, which is
Expand All @@ -679,7 +684,17 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// Add the storage member for the access unit to the record. The
// bitfields get the offset of their storage but come afterward and
// remain there after a stable sort.
llvm::Type *Type = getIntNType(Context.toBits(AccessSize));
llvm::Type *Type;
if (BestClipped) {
assert(getSize(getIntNType(Context.toBits(AccessSize))) >
AccessSize &&
"Clipped access need not be clipped");
Type = getByteArrayType(AccessSize);
} else {
Type = getIntNType(Context.toBits(AccessSize));
assert(getSize(Type) == AccessSize &&
"Unclipped access must be clipped");
}
Members.push_back(StorageInfo(BeginOffset, Type));
for (; Begin != BestEnd; ++Begin)
if (!Begin->isZeroLengthBitField(Context))
Expand Down Expand Up @@ -934,32 +949,21 @@ void CGRecordLowering::calculateZeroInit() {
}
}

void CGRecordLowering::clipTailPadding() {
std::vector<MemberInfo>::iterator Prior = Members.begin();
CharUnits Tail = getSize(Prior->Data);
for (std::vector<MemberInfo>::iterator Member = Prior + 1,
MemberEnd = Members.end();
Member != MemberEnd; ++Member) {
// Verify accumulateBitfields computed the correct storage representations.
void CGRecordLowering::checkBitfieldClipping() const {
#ifndef NDEBUG
auto Tail = CharUnits::Zero();
for (const auto &M : Members) {
// Only members with data and the scissor can cut into tail padding.
if (!Member->Data && Member->Kind != MemberInfo::Scissor)
if (!M.Data && M.Kind != MemberInfo::Scissor)
continue;
if (Member->Offset < Tail) {
assert(Prior->Kind == MemberInfo::Field &&
"Only storage fields have tail padding!");
if (!Prior->FD || Prior->FD->isBitField())
Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo(
cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8)));
else {
assert(Prior->FD->hasAttr<NoUniqueAddressAttr>() &&
"should not have reused this field's tail padding");
Prior->Data = getByteArrayType(
Context.getTypeInfoDataSizeInChars(Prior->FD->getType()).Width);
}
}
if (Member->Data)
Prior = Member;
Tail = Prior->Offset + getSize(Prior->Data);

assert(M.Offset >= Tail && "Bitfield access unit is not clipped");
Tail = M.Offset;
if (M.Data)
Tail += getSize(M.Data);
}
#endif
}

void CGRecordLowering::determinePacked(bool NVBaseType) {
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/CodeGen/CodeGenAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
Expand Down Expand Up @@ -1003,6 +1006,12 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const {
return BEConsumer->getCodeGenerator();
}

bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) {
if (CI.getFrontendOpts().GenReducedBMI)
CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
return true;
}

static std::unique_ptr<raw_pwrite_stream>
GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) {
switch (Action) {
Expand Down Expand Up @@ -1061,6 +1070,16 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
CI.getPreprocessor().addPPCallbacks(std::move(Callbacks));
}

if (CI.getFrontendOpts().GenReducedBMI &&
!CI.getFrontendOpts().ModuleOutputPath.empty()) {
std::vector<std::unique_ptr<ASTConsumer>> Consumers(2);
Consumers[0] = std::make_unique<ReducedBMIGenerator>(
CI.getPreprocessor(), CI.getModuleCache(),
CI.getFrontendOpts().ModuleOutputPath);
Consumers[1] = std::move(Result);
return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}

return std::move(Result);
}

Expand Down
18 changes: 15 additions & 3 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2635,7 +2635,7 @@ void CodeGenModule::setNonAliasAttributes(GlobalDecl GD,
addUsedGlobal(F);
if (auto *SA = D->getAttr<PragmaClangTextSectionAttr>())
if (!D->getAttr<SectionAttr>())
F->addFnAttr("implicit-section-name", SA->getName());
F->setSection(SA->getName());

llvm::AttrBuilder Attrs(F->getContext());
if (GetCPUAndFeaturesAttributes(GD, Attrs)) {
Expand Down Expand Up @@ -3952,8 +3952,20 @@ bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
// behavior may break ABI compatibility of the current unit.
if (const Module *M = F->getOwningModule();
M && M->getTopLevelModule()->isNamedModule() &&
getContext().getCurrentNamedModule() != M->getTopLevelModule())
return false;
getContext().getCurrentNamedModule() != M->getTopLevelModule()) {
// There are practices to mark template member function as always-inline
// and mark the template as extern explicit instantiation but not give
// the definition for member function. So we have to emit the function
// from explicitly instantiation with always-inline.
//
// See https://github.com/llvm/llvm-project/issues/86893 for details.
//
// TODO: Maybe it is better to give it a warning if we call a non-inline
// function from other module units which is marked as always-inline.
if (!F->isTemplateInstantiation() || !F->hasAttr<AlwaysInlineAttr>()) {
return false;
}
}

if (F->hasAttr<NoInlineAttr>())
return false;
Expand Down
12 changes: 11 additions & 1 deletion clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4756,6 +4756,14 @@ Action *Driver::ConstructPhaseAction(
if (Args.hasArg(options::OPT_extract_api))
return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO);

// With 'fexperimental-modules-reduced-bmi', we don't want to run the
// precompile phase unless the user specified '--precompile'. In the case
// the '--precompile' flag is enabled, we will try to emit the reduced BMI
// as a by product in GenerateModuleInterfaceAction.
if (Args.hasArg(options::OPT_modules_reduced_bmi) &&
!Args.getLastArg(options::OPT__precompile))
return Input;

types::ID OutputTy = getPrecompiledType(Input->getType());
assert(OutputTy != types::TY_INVALID &&
"Cannot precompile this input type!");
Expand Down Expand Up @@ -5916,8 +5924,10 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
// If we're emitting a module output with the specified option
// `-fmodule-output`.
if (!AtTopLevel && isa<PrecompileJobAction>(JA) &&
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput)
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) {
assert(!C.getArgs().hasArg(options::OPT_modules_reduced_bmi));
return GetModuleOutputPath(C, JA, BaseInput);
}

// Output to a temporary file?
if ((!AtTopLevel && !isSaveTempsEnabled() &&
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,13 @@ ToolChain::getTargetSubDirPath(StringRef BaseDir) const {
std::optional<std::string> ToolChain::getRuntimePath() const {
SmallString<128> P(D.ResourceDir);
llvm::sys::path::append(P, "lib");
return getTargetSubDirPath(P);
if (auto Ret = getTargetSubDirPath(P))
return Ret;
// Darwin does not use per-target runtime directory.
if (Triple.isOSDarwin())
return {};
llvm::sys::path::append(P, Triple.str());
return std::string(P);
}

std::optional<std::string> ToolChain::getStdlibPath() const {
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4045,6 +4045,24 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D,
// module fragment.
CmdArgs.push_back("-fskip-odr-check-in-gmf");

if (Args.hasArg(options::OPT_modules_reduced_bmi) &&
(Input.getType() == driver::types::TY_CXXModule ||
Input.getType() == driver::types::TY_PP_CXXModule)) {
CmdArgs.push_back("-fexperimental-modules-reduced-bmi");

if (Args.hasArg(options::OPT_fmodule_output_EQ))
Args.AddLastArg(CmdArgs, options::OPT_fmodule_output_EQ);
else
CmdArgs.push_back(Args.MakeArgString(
"-fmodule-output=" +
getCXX20NamedModuleOutputPath(Args, Input.getBaseInput())));
}

// Noop if we see '-fexperimental-modules-reduced-bmi' with other translation
// units than module units. This is more user friendly to allow end uers to
// enable this feature without asking for help from build systems.
Args.ClaimAllArgs(options::OPT_modules_reduced_bmi);

// We need to include the case the input file is a module file here.
// Since the default compilation model for C++ module interface unit will
// create temporary module file and compile the temporary module file
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
case llvm::Triple::csky:
case llvm::Triple::loongarch32:
case llvm::Triple::loongarch64:
case llvm::Triple::m68k:
return !clang::driver::tools::areOptimizationsEnabled(Args);
default:
break;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
}
}

// Pass the path to compiler resource files.
CmdArgs.push_back("-resource-dir");
CmdArgs.push_back(D.ResourceDir.c_str());

// Offloading related options
addOffloadOptions(C, Inputs, JA, Args, CmdArgs);

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,9 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// Android ARM uses max-page-size=4096 to reduce VMA usage.
ExtraOpts.push_back("-z");
ExtraOpts.push_back("max-page-size=4096");
} else if (Triple.isAArch64()) {
} else if (Triple.isAArch64() || Triple.getArch() == llvm::Triple::x86_64) {
// Android AArch64 uses max-page-size=16384 to support 4k/16k page sizes.
// Android emulates a 16k page size for app testing on x86_64 machines.
ExtraOpts.push_back("-z");
ExtraOpts.push_back("max-page-size=16384");
}
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,13 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
// arguments to function calls. We do this by ensuring that either all
// arguments (including any lambdas) go on the same line as the function
// call, or we break before the first argument.
auto PrevNonComment = Current.getPreviousNonComment();
const auto *Prev = Current.Previous;
if (!Prev)
return false;
// For example, `/*Newline=*/false`.
if (Prev->is(TT_BlockComment) && Current.SpacesRequiredBefore == 0)
return false;
const auto *PrevNonComment = Current.getPreviousNonComment();
if (!PrevNonComment || PrevNonComment->isNot(tok::l_paren))
return false;
if (Current.isOneOf(tok::comment, tok::l_paren, TT_LambdaLSquare))
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3891,7 +3891,11 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
FileName.ends_with_insensitive(".protodevel")) {
return FormatStyle::LK_Proto;
}
if (FileName.ends_with_insensitive(".textpb") ||
// txtpb is the canonical extension, and textproto is the legacy canonical
// extension
// https://protobuf.dev/reference/protobuf/textformat-spec/#text-format-files
if (FileName.ends_with_insensitive(".txtpb") ||
FileName.ends_with_insensitive(".textpb") ||
FileName.ends_with_insensitive(".pb.txt") ||
FileName.ends_with_insensitive(".textproto") ||
FileName.ends_with_insensitive(".asciipb")) {
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,13 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
if (Consumers.empty())
return nullptr;

if (CI.getFrontendOpts().GenReducedBMI &&
!CI.getFrontendOpts().ModuleOutputPath.empty()) {
Consumers.push_back(std::make_unique<ReducedBMIGenerator>(
CI.getPreprocessor(), CI.getModuleCache(),
CI.getFrontendOpts().ModuleOutputPath));
}

return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,9 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_named_character_escapes", "202207L");
Builder.defineMacro("__cpp_placeholder_variables", "202306L");

// C++26 features supported in earlier language modes.
Builder.defineMacro("__cpp_deleted_function", "202403L");

if (LangOpts.Char8)
Builder.defineMacro("__cpp_char8_t", "202207L");
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Headers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -437,14 +437,14 @@ foreach( f ${generated_files} )
endforeach( f )

function(add_header_target target_name file_list)
add_custom_target(${target_name} DEPENDS ${file_list})
add_library(${target_name} INTERFACE ${file_list})
set_target_properties(${target_name} PROPERTIES
FOLDER "Misc"
RUNTIME_OUTPUT_DIRECTORY "${output_dir}")
endfunction()

# The catch-all clang-resource-headers target
add_custom_target("clang-resource-headers" ALL DEPENDS ${out_files})
add_library(clang-resource-headers INTERFACE ${out_files})
set_target_properties("clang-resource-headers" PROPERTIES
FOLDER "Misc"
RUNTIME_OUTPUT_DIRECTORY "${output_dir}")
Expand Down Expand Up @@ -501,6 +501,10 @@ add_header_target("windows-resource-headers" ${windows_only_files})
add_header_target("utility-resource-headers" ${utility_files})

get_clang_resource_dir(header_install_dir SUBDIR include)
target_include_directories(clang-resource-headers INTERFACE
$<BUILD_INTERFACE:${output_dir}>
$<INSTALL_INTERFACE:${header_install_dir}>)
set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS clang-resource-headers)

#############################################################
# Install rules for the catch-all clang-resource-headers target
Expand Down
98 changes: 87 additions & 11 deletions clang/lib/InstallAPI/DylibVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,13 @@ void DylibVerifier::addSymbol(const Record *R, SymbolContext &SymCtx,

bool DylibVerifier::shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
const Record *DR) {
return SymCtx.FA->Avail.isObsoleted();
if (!SymCtx.FA->Avail.isObsoleted())
return false;

if (Zippered)
DeferredZipperedSymbols[SymCtx.SymbolName].emplace_back(ZipperedDeclSource{
SymCtx.FA, &Ctx.Diag->getSourceManager(), Ctx.Target});
return true;
}

bool DylibVerifier::shouldIgnoreReexport(const Record *R,
Expand All @@ -195,6 +201,28 @@ bool DylibVerifier::shouldIgnoreReexport(const Record *R,
return false;
}

bool DylibVerifier::shouldIgnoreInternalZipperedSymbol(
const Record *R, const SymbolContext &SymCtx) const {
if (!Zippered)
return false;

return Exports->findSymbol(SymCtx.Kind, SymCtx.SymbolName,
SymCtx.ObjCIFKind) != nullptr;
}

bool DylibVerifier::shouldIgnoreZipperedAvailability(const Record *R,
SymbolContext &SymCtx) {
if (!(Zippered && SymCtx.FA->Avail.isUnavailable()))
return false;

// Collect source location incase there is an exported symbol to diagnose
// during `verifyRemainingSymbols`.
DeferredZipperedSymbols[SymCtx.SymbolName].emplace_back(
ZipperedDeclSource{SymCtx.FA, SourceManagers.back().get(), Ctx.Target});

return true;
}

bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R,
SymbolContext &SymCtx,
const ObjCInterfaceRecord *DR) {
Expand Down Expand Up @@ -294,6 +322,9 @@ DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R,
if (shouldIgnorePrivateExternAttr(SymCtx.FA->D))
return Result::Ignore;

if (shouldIgnoreInternalZipperedSymbol(R, SymCtx))
return Result::Ignore;

unsigned ID;
Result Outcome;
if (Mode == VerificationMode::ErrorsAndWarnings) {
Expand Down Expand Up @@ -321,6 +352,9 @@ DylibVerifier::Result DylibVerifier::compareAvailability(const Record *R,
if (!SymCtx.FA->Avail.isUnavailable())
return Result::Valid;

if (shouldIgnoreZipperedAvailability(R, SymCtx))
return Result::Ignore;

const bool IsDeclAvailable = SymCtx.FA->Avail.isUnavailable();

switch (Mode) {
Expand Down Expand Up @@ -588,13 +622,58 @@ void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) {
}
}

const bool IsLinkerSymbol = SymbolName.starts_with("$ld$");

if (R.isVerified()) {
// Check for unavailable symbols.
// This should only occur in the zippered case where we ignored
// availability until all headers have been parsed.
auto It = DeferredZipperedSymbols.find(SymCtx.SymbolName);
if (It == DeferredZipperedSymbols.end()) {
updateState(Result::Valid);
return;
}

ZipperedDeclSources Locs;
for (const ZipperedDeclSource &ZSource : It->second) {
if (ZSource.FA->Avail.isObsoleted()) {
updateState(Result::Ignore);
return;
}
if (ZSource.T.Arch != Ctx.Target.Arch)
continue;
Locs.emplace_back(ZSource);
}
assert(Locs.size() == 2 && "Expected two decls for zippered symbol");

// Print violating declarations per platform.
for (const ZipperedDeclSource &ZSource : Locs) {
unsigned DiagID = 0;
if (Mode == VerificationMode::Pedantic || IsLinkerSymbol) {
updateState(Result::Invalid);
DiagID = diag::err_header_availability_mismatch;
} else if (Mode == VerificationMode::ErrorsAndWarnings) {
updateState(Result::Ignore);
DiagID = diag::warn_header_availability_mismatch;
} else {
updateState(Result::Ignore);
return;
}
// Bypass emitDiag banner and print the target everytime.
Ctx.Diag->setSourceManager(ZSource.SrcMgr);
Ctx.Diag->Report(diag::warn_target) << getTargetTripleName(ZSource.T);
Ctx.Diag->Report(ZSource.FA->Loc, DiagID)
<< getAnnotatedName(&R, SymCtx) << ZSource.FA->Avail.isUnavailable()
<< ZSource.FA->Avail.isUnavailable();
}
return;
}

if (shouldIgnoreCpp(SymbolName, R.isWeakDefined())) {
updateState(Result::Valid);
return;
}

const bool IsLinkerSymbol = SymbolName.starts_with("$ld$");

// All checks at this point classify as some kind of violation.
// The different verification modes dictate whether they are reported to the
// user.
Expand Down Expand Up @@ -647,8 +726,6 @@ void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) {
}

void DylibVerifier::visitGlobal(const GlobalRecord &R) {
if (R.isVerified())
return;
SymbolContext SymCtx;
SimpleSymbol Sym = parseSymbol(R.getName());
SymCtx.SymbolName = Sym.Name;
Expand All @@ -658,8 +735,6 @@ void DylibVerifier::visitGlobal(const GlobalRecord &R) {

void DylibVerifier::visitObjCIVar(const ObjCIVarRecord &R,
const StringRef Super) {
if (R.isVerified())
return;
SymbolContext SymCtx;
SymCtx.SymbolName = ObjCIVarRecord::createScopedName(Super, R.getName());
SymCtx.Kind = EncodeKind::ObjectiveCInstanceVariable;
Expand All @@ -679,8 +754,6 @@ void DylibVerifier::accumulateSrcLocForDylibSymbols() {
}

void DylibVerifier::visitObjCInterface(const ObjCInterfaceRecord &R) {
if (R.isVerified())
return;
SymbolContext SymCtx;
SymCtx.SymbolName = R.getName();
SymCtx.ObjCIFKind = assignObjCIFSymbolKind(&R);
Expand Down Expand Up @@ -713,9 +786,12 @@ DylibVerifier::Result DylibVerifier::verifyRemainingSymbols() {

DWARFContext DWARFInfo;
DWARFCtx = &DWARFInfo;
Ctx.DiscoveredFirstError = false;
Ctx.PrintArch = true;
Ctx.Target = Target(Architecture::AK_unknown, PlatformType::PLATFORM_UNKNOWN);
for (std::shared_ptr<RecordsSlice> Slice : Dylib) {
if (Ctx.Target.Arch == Slice->getTarget().Arch)
continue;
Ctx.DiscoveredFirstError = false;
Ctx.PrintArch = true;
Ctx.Target = Slice->getTarget();
Ctx.DylibSlice = Slice.get();
Slice->visit(*this);
Expand Down
77 changes: 42 additions & 35 deletions clang/lib/Lex/HeaderSearch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -946,9 +946,13 @@ OptionalFileEntryRef HeaderSearch::LookupFile(
// If we have no includer, that means we're processing a #include
// from a module build. We should treat this as a system header if we're
// building a [system] module.
bool IncluderIsSystemHeader =
Includer ? getFileInfo(*Includer).DirInfo != SrcMgr::C_User :
BuildSystemModule;
bool IncluderIsSystemHeader = [&]() {
if (!Includer)
return BuildSystemModule;
const HeaderFileInfo *HFI = getExistingFileInfo(*Includer);
assert(HFI && "includer without file info");
return HFI->DirInfo != SrcMgr::C_User;
}();
if (OptionalFileEntryRef FE = getFileAndSuggestModule(
TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
RequestingModule, SuggestedModule)) {
Expand All @@ -963,10 +967,11 @@ OptionalFileEntryRef HeaderSearch::LookupFile(
// Note that we only use one of FromHFI/ToHFI at once, due to potential
// reallocation of the underlying vector potentially making the first
// reference binding dangling.
HeaderFileInfo &FromHFI = getFileInfo(*Includer);
unsigned DirInfo = FromHFI.DirInfo;
bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
StringRef Framework = FromHFI.Framework;
const HeaderFileInfo *FromHFI = getExistingFileInfo(*Includer);
assert(FromHFI && "includer without file info");
unsigned DirInfo = FromHFI->DirInfo;
bool IndexHeaderMapHeader = FromHFI->IndexHeaderMapHeader;
StringRef Framework = FromHFI->Framework;

HeaderFileInfo &ToHFI = getFileInfo(*FE);
ToHFI.DirInfo = DirInfo;
Expand Down Expand Up @@ -1153,10 +1158,12 @@ OptionalFileEntryRef HeaderSearch::LookupFile(
// "Foo" is the name of the framework in which the including header was found.
if (!Includers.empty() && Includers.front().first && !isAngled &&
!Filename.contains('/')) {
HeaderFileInfo &IncludingHFI = getFileInfo(*Includers.front().first);
if (IncludingHFI.IndexHeaderMapHeader) {
const HeaderFileInfo *IncludingHFI =
getExistingFileInfo(*Includers.front().first);
assert(IncludingHFI && "includer without file info");
if (IncludingHFI->IndexHeaderMapHeader) {
SmallString<128> ScratchFilename;
ScratchFilename += IncludingHFI.Framework;
ScratchFilename += IncludingHFI->Framework;
ScratchFilename += '/';
ScratchFilename += Filename;

Expand Down Expand Up @@ -1286,11 +1293,11 @@ OptionalFileEntryRef HeaderSearch::LookupSubframeworkHeader(
}

// This file is a system header or C++ unfriendly if the old file is.
//
// Note that the temporary 'DirInfo' is required here, as either call to
// getFileInfo could resize the vector and we don't want to rely on order
// of evaluation.
unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
const HeaderFileInfo *ContextHFI = getExistingFileInfo(ContextFileEnt);
assert(ContextHFI && "context file without file info");
// Note that the temporary 'DirInfo' is required here, as the call to
// getFileInfo could resize the vector and might invalidate 'ContextHFI'.
unsigned DirInfo = ContextHFI->DirInfo;
getFileInfo(*File).DirInfo = DirInfo;

FrameworkName.pop_back(); // remove the trailing '/'
Expand Down Expand Up @@ -1348,8 +1355,6 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
HFI.Framework = OtherHFI.Framework;
}

/// getFileInfo - Return the HeaderFileInfo structure for the specified
/// FileEntry.
HeaderFileInfo &HeaderSearch::getFileInfo(FileEntryRef FE) {
if (FE.getUID() >= FileInfo.size())
FileInfo.resize(FE.getUID() + 1);
Expand All @@ -1366,27 +1371,20 @@ HeaderFileInfo &HeaderSearch::getFileInfo(FileEntryRef FE) {
}

HFI->IsValid = true;
// We have local information about this header file, so it's no longer
// strictly external.
// We assume the caller has local information about this header file, so it's
// no longer strictly external.
HFI->External = false;
return *HFI;
}

const HeaderFileInfo *
HeaderSearch::getExistingFileInfo(FileEntryRef FE, bool WantExternal) const {
// If we have an external source, ensure we have the latest information.
// FIXME: Use a generation count to check whether this is really up to date.
const HeaderFileInfo *HeaderSearch::getExistingFileInfo(FileEntryRef FE) const {
HeaderFileInfo *HFI;
if (ExternalSource) {
if (FE.getUID() >= FileInfo.size()) {
if (!WantExternal)
return nullptr;
if (FE.getUID() >= FileInfo.size())
FileInfo.resize(FE.getUID() + 1);
}

HFI = &FileInfo[FE.getUID()];
if (!WantExternal && (!HFI->IsValid || HFI->External))
return nullptr;
// FIXME: Use a generation count to check whether this is really up to date.
if (!HFI->Resolved) {
auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
if (ExternalHFI.IsValid) {
Expand All @@ -1395,16 +1393,25 @@ HeaderSearch::getExistingFileInfo(FileEntryRef FE, bool WantExternal) const {
mergeHeaderFileInfo(*HFI, ExternalHFI);
}
}
} else if (FE.getUID() >= FileInfo.size()) {
return nullptr;
} else {
} else if (FE.getUID() < FileInfo.size()) {
HFI = &FileInfo[FE.getUID()];
} else {
HFI = nullptr;
}

if (!HFI->IsValid || (HFI->External && !WantExternal))
return nullptr;
return (HFI && HFI->IsValid) ? HFI : nullptr;
}

const HeaderFileInfo *
HeaderSearch::getExistingLocalFileInfo(FileEntryRef FE) const {
HeaderFileInfo *HFI;
if (FE.getUID() < FileInfo.size()) {
HFI = &FileInfo[FE.getUID()];
} else {
HFI = nullptr;
}

return HFI;
return (HFI && HFI->IsValid && !HFI->External) ? HFI : nullptr;
}

bool HeaderSearch::isFileMultipleIncludeGuarded(FileEntryRef File) const {
Expand Down
46 changes: 45 additions & 1 deletion clang/lib/Parse/ParseCXXInlineMethods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,49 @@

using namespace clang;

/// Parse the optional ("message") part of a deleted-function-body.
StringLiteral *Parser::ParseCXXDeletedFunctionMessage() {
if (!Tok.is(tok::l_paren))
return nullptr;
StringLiteral *Message = nullptr;
BalancedDelimiterTracker BT{*this, tok::l_paren};
BT.consumeOpen();

if (isTokenStringLiteral()) {
ExprResult Res = ParseUnevaluatedStringLiteralExpression();
if (Res.isUsable()) {
Message = Res.getAs<StringLiteral>();
Diag(Message->getBeginLoc(), getLangOpts().CPlusPlus26
? diag::warn_cxx23_delete_with_message
: diag::ext_delete_with_message)
<< Message->getSourceRange();
}
} else {
Diag(Tok.getLocation(), diag::err_expected_string_literal)
<< /*Source='in'*/ 0 << "'delete'";
SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
}

BT.consumeClose();
return Message;
}

/// If we've encountered '= delete' in a context where it is ill-formed, such
/// as in the declaration of a non-function, also skip the ("message") part if
/// it is present to avoid issuing further diagnostics.
void Parser::SkipDeletedFunctionBody() {
if (!Tok.is(tok::l_paren))
return;

BalancedDelimiterTracker BT{*this, tok::l_paren};
BT.consumeOpen();

// Just skip to the end of the current declaration.
SkipUntil(tok::r_paren, tok::comma, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::r_paren))
BT.consumeClose();
}

/// ParseCXXInlineMethodDef - We parsed and verified that the specified
/// Declarator is a well formed C++ inline method definition. Now lex its body
/// and store its tokens for parsing after the C++ class is complete.
Expand Down Expand Up @@ -70,7 +113,8 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
? diag::warn_cxx98_compat_defaulted_deleted_function
: diag::ext_defaulted_deleted_function)
<< 1 /* deleted */;
Actions.SetDeclDeleted(FnD, KWLoc);
StringLiteral *Message = ParseCXXDeletedFunctionMessage();
Actions.SetDeclDeleted(FnD, KWLoc, Message);
Delete = true;
if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
DeclAsFunction->setRangeEnd(KWEndLoc);
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
Expand Down Expand Up @@ -2379,10 +2380,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
if (getLangOpts().CPlusPlus23) {
auto &LastRecord = Actions.ExprEvalContexts.back();
LastRecord.InLifetimeExtendingContext = true;

// Materialize non-`cv void` prvalue temporaries in discarded
// expressions. These materialized temporaries may be lifetime-extented.
LastRecord.InMaterializeTemporaryObjectContext = true;
}

if (getLangOpts().OpenMP)
Expand Down Expand Up @@ -2664,7 +2661,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
}
}

Sema::CUDATargetContextRAII X(Actions, Sema::CTCK_InitGlobalVar, ThisDecl);
SemaCUDA::CUDATargetContextRAII X(Actions.CUDA(),
SemaCUDA::CTCK_InitGlobalVar, ThisDecl);
switch (TheInitKind) {
// Parse declarator '=' initializer.
case InitKind::Equal: {
Expand All @@ -2676,6 +2674,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
<< 1 /* delete */;
else
Diag(ConsumeToken(), diag::err_deleted_non_function);
SkipDeletedFunctionBody();
} else if (Tok.is(tok::kw_default)) {
if (D.isFunctionDeclarator())
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3397,6 +3397,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
<< 1 /* delete */;
else
Diag(ConsumeToken(), diag::err_deleted_non_function);
SkipDeletedFunctionBody();
return ExprError();
}
} else if (Tok.is(tok::kw_default)) {
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -2129,10 +2130,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
}

if (!LHS.isInvalid()) {
ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(),
OpenLoc,
ExecConfigExprs,
CloseLoc);
ExprResult ECResult = Actions.CUDA().ActOnExecConfigExpr(
getCurScope(), OpenLoc, ExecConfigExprs, CloseLoc);
if (ECResult.isInvalid())
LHS = ExprError();
else
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Parse/ParseHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) {
return nullptr;
}

Decl *D = Actions.HLSL().ActOnStartHLSLBuffer(
getCurScope(), IsCBuffer, BufferLoc, Identifier, IdentifierLoc,
T.getOpenLocation());
Decl *D = Actions.HLSL().ActOnStartBuffer(getCurScope(), IsCBuffer, BufferLoc,
Identifier, IdentifierLoc,
T.getOpenLocation());

while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
// FIXME: support attribute on constants inside cbuffer/tbuffer.
Expand All @@ -88,15 +88,15 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) {
T.skipToEnd();
DeclEnd = T.getCloseLocation();
BufferScope.Exit();
Actions.HLSL().ActOnFinishHLSLBuffer(D, DeclEnd);
Actions.HLSL().ActOnFinishBuffer(D, DeclEnd);
return nullptr;
}
}

T.consumeClose();
DeclEnd = T.getCloseLocation();
BufferScope.Exit();
Actions.HLSL().ActOnFinishHLSLBuffer(D, DeclEnd);
Actions.HLSL().ActOnFinishBuffer(D, DeclEnd);

Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);
return D;
Expand Down
Loading