23 changes: 23 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5860,3 +5860,26 @@ specify the starting offset to begin embedding from. The resources is treated
as being empty if the specified offset is larger than the number of bytes in
the resource. The offset will be applied *before* any ``limit`` parameters are
applied.
Union and aggregate initialization in C
=======================================
In C23 (N2900), when an object is initialized from initializer ``= {}``, all
elements of arrays, all members of structs, and the first members of unions are
empty-initialized recursively. In addition, all padding bits are initialized to
zero.
Clang guarantees the following behaviors:
* ``1:`` Clang supports initializer ``= {}`` mentioned above in all C
standards.
* ``2:`` When unions are initialized from initializer ``= {}``, bytes outside
of the first members of unions are also initialized to zero.
* ``3:`` When unions, structures and arrays are initialized from initializer
``= { initializer-list }``, all members not explicitly initialized in
the initializer list are empty-initialized recursively. In addition, all
padding bits are initialized to zero.
Currently, the above extension only applies to C source code, not C++.
2 changes: 1 addition & 1 deletion clang/docs/OpenMPSupport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ implementation.
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | error directive | :good:`done` | D139166 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | scope construct | :none:`worked on` | D157933 |
| misc | scope construct | :good:`done` | D157933, https://github.com/llvm/llvm-project/pull/109197 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | routines for controlling and querying team regions | :part:`partial` | D95003 (libomp only) |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
Expand Down
20 changes: 18 additions & 2 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ code bases.
still supporting SPARC V8 CPUs need to specify ``-mcpu=v8`` with a
`config file
<https://clang.llvm.org/docs/UsersManual.html#configuration-files>`_.

- The ``clang-rename`` tool has been removed.

C/C++ Language Potentially Breaking Changes
Expand Down Expand Up @@ -115,7 +115,7 @@ C++ Language Changes
- Allow single element access of GCC vector/ext_vector_type object to be
constant expression. Supports the `V.xyzw` syntax and other tidbits
as seen in OpenCL. Selecting multiple elements is left as a future work.
- Implement `CWG1815 <https://wg21.link/CWG1815>`_. Support lifetime extension
- Implement `CWG1815 <https://wg21.link/CWG1815>`_. Support lifetime extension
of temporary created by aggregate initialization using a default member
initializer.

Expand Down Expand Up @@ -268,6 +268,14 @@ Attribute Changes in Clang
- Introduced a new attribute ``[[clang::coro_await_elidable_argument]]`` on function parameters
to propagate safe elide context to arguments if such function is also under a safe elide context.

- The documentation of the ``[[clang::musttail]]`` attribute was updated to
note that the lifetimes of all local variables end before the call. This does
not change the behaviour of the compiler, as this was true for previous
versions.

- Fix a bug where clang doesn't automatically apply the ``[[gsl::Owner]]`` or
``[[gsl::Pointer]]`` to STL explicit template specialization decls. (#GH109442)

Improvements to Clang's diagnostics
-----------------------------------

Expand Down Expand Up @@ -324,6 +332,10 @@ Improvements to Clang's diagnostics

- Don't emit bogus dangling diagnostics when ``[[gsl::Owner]]`` and `[[clang::lifetimebound]]` are used together (#GH108272).

- The ``-Wreturn-stack-address`` warning now also warns about addresses of
local variables passed to function calls using the ``[[clang::musttail]]``
attribute.

Improvements to Clang's time-trace
----------------------------------

Expand Down Expand Up @@ -440,6 +452,9 @@ Miscellaneous Clang Crashes Fixed

- Fixed ``-ast-dump`` crashes on codes involving ``concept`` with ``-ast-dump-decl-types``. (#GH94928)

- Fixed internal assertion firing when a declaration in the implicit global
module is found through ADL. (GH#109879)

OpenACC Specific Changes
------------------------

Expand Down Expand Up @@ -625,6 +640,7 @@ Python Binding Changes
OpenMP Support
--------------
- Added support for 'omp assume' directive.
- Added support for 'omp scope' directive.

Improvements
^^^^^^^^^^^^
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,12 @@ return value must be trivially destructible. The calling convention of the
caller and callee must match, and they must not be variadic functions or have
old style K&R C function declarations.

The lifetimes of all local variables and function parameters end immediately
before the call to the function. This means that it is undefined behaviour to
pass a pointer or reference to a local variable to the called function, which
is not the case without the attribute. Clang will emit a warning in common
cases where this happens.

``clang::musttail`` provides assurances that the tail call can be optimized on
all targets, not just one.
}];
Expand Down
8 changes: 0 additions & 8 deletions clang/include/clang/Basic/BuiltinsNVPTX.def
Original file line number Diff line number Diff line change
Expand Up @@ -599,14 +599,6 @@ TARGET_BUILTIN(__nvvm_e4m3x2_to_f16x2_rn_relu, "V2hs", "", AND(SM_89,PTX81))
TARGET_BUILTIN(__nvvm_e5m2x2_to_f16x2_rn, "V2hs", "", AND(SM_89,PTX81))
TARGET_BUILTIN(__nvvm_e5m2x2_to_f16x2_rn_relu, "V2hs", "", AND(SM_89,PTX81))

// Bitcast

BUILTIN(__nvvm_bitcast_f2i, "if", "")
BUILTIN(__nvvm_bitcast_i2f, "fi", "")

BUILTIN(__nvvm_bitcast_ll2d, "dLLi", "")
BUILTIN(__nvvm_bitcast_d2ll, "LLid", "")

// FNS
TARGET_BUILTIN(__nvvm_fns, "UiUiUii", "n", PTX60)

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ CODEGENOPT(EmulatedTLS , 1, 0) ///< Set by default or -f[no-]emulated-tls.
ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off)
/// Inline asm dialect, -masm=(att|intel)
ENUM_CODEGENOPT(InlineAsmDialect, InlineAsmDialectKind, 1, IAD_ATT)
CODEGENOPT(OutputAsmVariant, 2, 3) ///< Set the asm variant for output (3: unspecified).
CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
///< are required.
CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled.
Expand Down
6 changes: 5 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10101,11 +10101,15 @@ def err_lifetimebound_ctor_dtor : Error<
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr_ref : Warning<
"%select{address of|reference to}0 stack memory associated with "
"%select{local variable|parameter|compound literal}2 %1 returned">,
"%select{local variable|parameter|compound literal}2 %1 "
"%select{returned|passed to musttail function}3">,
InGroup<ReturnStackAddress>;
def warn_ret_local_temp_addr_ref : Warning<
"returning %select{address of|reference to}0 local temporary object">,
InGroup<ReturnStackAddress>;
def warn_musttail_local_temp_addr_ref : Warning<
"passing %select{address of|reference to}0 local temporary object to musttail function">,
InGroup<ReturnStackAddress>;
def err_ret_local_temp_ref : Error<
"returning reference to local temporary object">;
def warn_ret_addr_label : Warning<
Expand Down
11 changes: 7 additions & 4 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -6352,8 +6352,10 @@ def mcx16 : Flag<["-"], "mcx16">, Group<m_x86_Features_Group>;
def mno_cx16 : Flag<["-"], "mno-cx16">, Group<m_x86_Features_Group>;
def menqcmd : Flag<["-"], "menqcmd">, Group<m_x86_Features_Group>;
def mno_enqcmd : Flag<["-"], "mno-enqcmd">, Group<m_x86_Features_Group>;
def mevex512 : Flag<["-"], "mevex512">, Group<m_x86_Features_Group>;
def mno_evex512 : Flag<["-"], "mno-evex512">, Group<m_x86_Features_Group>;
def mevex512 : Flag<["-"], "mevex512">, Group<m_x86_Features_Group>,
Visibility<[ClangOption, CLOption, FlangOption]>;
def mno_evex512 : Flag<["-"], "mno-evex512">, Group<m_x86_Features_Group>,
Visibility<[ClangOption, CLOption, FlangOption]>;
def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>;
def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>;
def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>;
Expand Down Expand Up @@ -7215,6 +7217,9 @@ def fuse_ctor_homing: Flag<["-"], "fuse-ctor-homing">,
def as_secure_log_file : Separate<["-"], "as-secure-log-file">,
HelpText<"Emit .secure_log_unique directives to this filename.">,
MarshallingInfoString<CodeGenOpts<"AsSecureLogFile">>;
def output_asm_variant : Joined<["--"], "output-asm-variant=">,
HelpText<"Select the asm variant (integer) to use for output (3: unspecified)">,
MarshallingInfoInt<CodeGenOpts<"OutputAsmVariant">, "3">;

} // let Visibility = [CC1Option, CC1AsOption]

Expand Down Expand Up @@ -8305,8 +8310,6 @@ def filetype : Separate<["-"], "filetype">,
HelpText<"Specify the output file type ('asm', 'null', or 'obj')">;

// Transliterate Options
def output_asm_variant : Separate<["-"], "output-asm-variant">,
HelpText<"Select the asm variant index to use for output">;
def show_encoding : Flag<["-"], "show-encoding">,
HelpText<"Show instruction encoding information in transliterate mode">;
def show_inst : Flag<["-"], "show-inst">,
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Frontend/ASTUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -692,8 +692,8 @@ class ASTUnit {
///
/// \returns - The initialized ASTUnit or null if the AST failed to load.
static std::unique_ptr<ASTUnit>
LoadFromASTFile(const std::string &Filename,
const PCHContainerReader &PCHContainerRdr, WhatToLoad ToLoad,
LoadFromASTFile(StringRef Filename, const PCHContainerReader &PCHContainerRdr,
WhatToLoad ToLoad,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts,
std::shared_ptr<HeaderSearchOptions> HSOpts,
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Frontend/MultiplexConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class MultiplexConsumer : public SemaConsumer {
public:
// Takes ownership of the pointers in C.
MultiplexConsumer(std::vector<std::unique_ptr<ASTConsumer>> C);
MultiplexConsumer(std::unique_ptr<ASTConsumer> C);
~MultiplexConsumer() override;

// ASTConsumer
Expand Down Expand Up @@ -80,7 +81,7 @@ class MultiplexConsumer : public SemaConsumer {
void InitializeSema(Sema &S) override;
void ForgetSema() override;

private:
protected:
std::vector<std::unique_ptr<ASTConsumer>> Consumers; // Owns these.
std::unique_ptr<MultiplexASTMutationListener> MutationListener;
std::unique_ptr<MultiplexASTDeserializationListener> DeserializationListener;
Expand Down
58 changes: 30 additions & 28 deletions clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@
#ifndef LLVM_CLANG_INTERPRETER_INTERPRETER_H
#define LLVM_CLANG_INTERPRETER_INTERPRETER_H

#include "clang/AST/Decl.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/Interpreter/PartialTranslationUnit.h"
#include "clang/Interpreter/Value.h"
#include "clang/Sema/Ownership.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
Expand All @@ -38,6 +36,9 @@ class ThreadSafeContext;
namespace clang {

class CompilerInstance;
class CodeGenerator;
class CXXRecordDecl;
class Decl;
class IncrementalExecutor;
class IncrementalParser;

Expand Down Expand Up @@ -77,42 +78,45 @@ class IncrementalCompilerBuilder {
llvm::StringRef CudaSDKPath;
};

/// Generate glue code between the Interpreter's built-in runtime and user code.
class RuntimeInterfaceBuilder {
public:
virtual ~RuntimeInterfaceBuilder() = default;

using TransformExprFunction = ExprResult(RuntimeInterfaceBuilder *Builder,
Expr *, ArrayRef<Expr *>);
virtual TransformExprFunction *getPrintValueTransformer() = 0;
};
class IncrementalAction;
class InProcessPrintingASTConsumer;

/// Provides top-level interfaces for incremental compilation and execution.
class Interpreter {
friend class Value;
friend InProcessPrintingASTConsumer;

std::unique_ptr<llvm::orc::ThreadSafeContext> TSCtx;
/// Long-lived, incremental parsing action.
std::unique_ptr<IncrementalAction> Act;
std::unique_ptr<IncrementalParser> IncrParser;
std::unique_ptr<IncrementalExecutor> IncrExecutor;
std::unique_ptr<RuntimeInterfaceBuilder> RuntimeIB;

// An optional parser for CUDA offloading
std::unique_ptr<IncrementalParser> DeviceParser;

/// List containing information about each incrementally parsed piece of code.
std::list<PartialTranslationUnit> PTUs;

unsigned InitPTUSize = 0;

// This member holds the last result of the value printing. It's a class
// member because we might want to access it after more inputs. If no value
// printing happens, it's in an invalid state.
Value LastValue;

// Add a call to an Expr to report its result. We query the function from
// RuntimeInterfaceBuilder once and store it as a function pointer to avoid
// frequent virtual function calls.
RuntimeInterfaceBuilder::TransformExprFunction *AddPrintValueCall = nullptr;
/// When CodeGen is created the first llvm::Module gets cached in many places
/// and we must keep it alive.
std::unique_ptr<llvm::Module> CachedInCodeGenModule;

/// Compiler instance performing the incremental compilation.
std::unique_ptr<CompilerInstance> CI;

protected:
// Derived classes can use an extended interface of the Interpreter.
Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err,
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr);
Interpreter(std::unique_ptr<CompilerInstance> Instance, llvm::Error &Err,
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr,
std::unique_ptr<clang::ASTConsumer> Consumer = nullptr);

// Create the internal IncrementalExecutor, or re-create it after calling
// ResetExecutor().
Expand All @@ -122,15 +126,8 @@ class Interpreter {
// JIT engine. In particular, it doesn't run cleanup or destructors.
void ResetExecutor();

// Lazily construct the RuntimeInterfaceBuilder. The provided instance will be
// used for the entire lifetime of the interpreter. The default implementation
// targets the in-process __clang_Interpreter runtime. Override this to use a
// custom runtime.
virtual std::unique_ptr<RuntimeInterfaceBuilder> FindRuntimeInterface();

public:
virtual ~Interpreter();

static llvm::Expected<std::unique_ptr<Interpreter>>
create(std::unique_ptr<CompilerInstance> CI);
static llvm::Expected<std::unique_ptr<Interpreter>>
Expand All @@ -145,7 +142,6 @@ class Interpreter {
llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code);
llvm::Error Execute(PartialTranslationUnit &T);
llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr);
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);

/// Undo N previous incremental inputs.
llvm::Error Undo(unsigned N = 1);
Expand All @@ -167,8 +163,6 @@ class Interpreter {
llvm::Expected<llvm::orc::ExecutorAddr>
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;

enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };

const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const {
return ValuePrintingInfo;
}
Expand All @@ -178,7 +172,15 @@ class Interpreter {
private:
size_t getEffectivePTUSize() const;
void markUserCodeStart();
llvm::Expected<Expr *> ExtractValueFromExpr(Expr *E);
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);

CodeGenerator *getCodeGen() const;
std::unique_ptr<llvm::Module> GenModule();
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU);

// A cache for the compiled destructors used to for de-allocation of managed
// clang::Values.
llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;

llvm::SmallVector<Expr *, 4> ValuePrintingInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,14 +326,14 @@ class ProgramState : public llvm::FoldingSetNode {
/// \param ITraits information about special handling for particular regions
/// or symbols.
[[nodiscard]] ProgramStateRef
invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E,
invalidateRegions(ArrayRef<const MemRegion *> Regions, const Stmt *S,
unsigned BlockCount, const LocationContext *LCtx,
bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
const CallEvent *Call = nullptr,
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;

[[nodiscard]] ProgramStateRef
invalidateRegions(ArrayRef<SVal> Values, const Expr *E, unsigned BlockCount,
invalidateRegions(ArrayRef<SVal> Values, const Stmt *S, unsigned BlockCount,
const LocationContext *LCtx, bool CausesPointerEscape,
InvalidatedSymbols *IS = nullptr,
const CallEvent *Call = nullptr,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,9 @@ class SValBuilder {
const Expr *expr,
const LocationContext *LCtx,
unsigned count);
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
const Expr *expr,
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Stmt *S,
const LocationContext *LCtx,
QualType type,
unsigned count);
QualType type, unsigned count);
DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt,
const LocationContext *LCtx,
QualType type,
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ class StoreManager {
///
/// \param[in] store The initial store.
/// \param[in] Values The values to invalidate.
/// \param[in] E The current statement being evaluated. Used to conjure
/// \param[in] S The current statement being evaluated. Used to conjure
/// symbols to mark the values of invalidated regions.
/// \param[in] Count The current block count. Used to conjure
/// symbols to mark the values of invalidated regions.
Expand All @@ -233,7 +233,7 @@ class StoreManager {
/// even if they do not currently have bindings. Pass \c NULL if this
/// information will not be used.
virtual StoreRef invalidateRegions(
Store store, ArrayRef<SVal> Values, const Expr *Ex, unsigned Count,
Store store, ArrayRef<SVal> Values, const Stmt *S, unsigned Count,
const LocationContext *LCtx, const CallEvent *Call,
InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits,
InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) = 0;
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12587,8 +12587,7 @@ void ASTContext::forEachMultiversionedFunctionVersion(
FD->getDeclContext()->getRedeclContext()->lookup(FD->getDeclName())) {
FunctionDecl *CurFD = CurDecl->getAsFunction()->getMostRecentDecl();
if (CurFD && hasSameType(CurFD->getType(), FD->getType()) &&
!SeenDecls.contains(CurFD)) {
SeenDecls.insert(CurFD);
SeenDecls.insert(CurFD).second) {
Pred(CurFD);
}
}
Expand Down
115 changes: 76 additions & 39 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_NoOp:
case CK_UserDefinedConversion:
case CK_AddressSpaceConversion:
case CK_CPointerToObjCPointerCast:
return this->delegate(SubExpr);

case CK_BitCast: {
Expand Down Expand Up @@ -1281,9 +1282,8 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
? BinaryOperator::getOpForCompoundAssignment(E->getOpcode())
: E->getOpcode();

// The LHS and RHS of a comparison operator must have the same type. So we
// just use LHS vector element type here.
PrimType ElemT = this->classifyVectorElementType(LHS->getType());
PrimType RHSElemT = this->classifyVectorElementType(RHS->getType());
PrimType ResultElemT = this->classifyVectorElementType(E->getType());

// Evaluate LHS and save value to LHSOffset.
Expand Down Expand Up @@ -1311,7 +1311,7 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
PrimType PromotT = classifyPrim(PromotTy);
PrimType OpT = NeedIntPromot ? PromotT : ElemT;

auto getElem = [=](unsigned Offset, unsigned Index) {
auto getElem = [=](unsigned Offset, PrimType ElemT, unsigned Index) {
if (!this->emitGetLocal(PT_Ptr, Offset, E))
return false;
if (!this->emitArrayElemPop(ElemT, Index, E))
Expand Down Expand Up @@ -1341,9 +1341,9 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
}

for (unsigned I = 0; I != VecTy->getNumElements(); ++I) {
if (!getElem(LHSOffset, I))
if (!getElem(LHSOffset, ElemT, I))
return false;
if (!getElem(RHSOffset, I))
if (!getElem(RHSOffset, RHSElemT, I))
return false;
switch (Op) {
case BO_Add:
Expand Down Expand Up @@ -1371,11 +1371,11 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
return false;
break;
case BO_Shl:
if (!this->emitShl(OpT, ElemT, E))
if (!this->emitShl(OpT, RHSElemT, E))
return false;
break;
case BO_Shr:
if (!this->emitShr(OpT, ElemT, E))
if (!this->emitShr(OpT, RHSElemT, E))
return false;
break;
case BO_EQ:
Expand Down Expand Up @@ -3097,12 +3097,11 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
QualType ElementType = E->getAllocatedType();
std::optional<PrimType> ElemT = classify(ElementType);
unsigned PlacementArgs = E->getNumPlacementArgs();
const FunctionDecl *OperatorNew = E->getOperatorNew();
const Expr *PlacementDest = nullptr;
bool IsNoThrow = false;

// FIXME: Better diagnostic. diag::note_constexpr_new_placement
if (PlacementArgs != 0) {
// The only new-placement list we support is of the form (std::nothrow).
//
// FIXME: There is no restriction on this, but it's not clear that any
// other form makes any sense. We get here for cases such as:
//
Expand All @@ -3111,27 +3110,44 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
// (which should presumably be valid only if N is a multiple of
// alignof(int), and in any case can't be deallocated unless N is
// alignof(X) and X has new-extended alignment).
if (PlacementArgs != 1 || !E->getPlacementArg(0)->getType()->isNothrowT())
return this->emitInvalid(E);
if (PlacementArgs == 1) {
const Expr *Arg1 = E->getPlacementArg(0);
if (Arg1->getType()->isNothrowT()) {
if (!this->discard(Arg1))
return false;
IsNoThrow = true;
} else {
// Invalid unless we have C++26 or are in a std:: function.
if (!this->emitInvalidNewDeleteExpr(E, E))
return false;

if (!this->discard(E->getPlacementArg(0)))
return false;
IsNoThrow = true;
}
// If we have a placement-new destination, we'll later use that instead
// of allocating.
if (OperatorNew->isReservedGlobalPlacementOperator())
PlacementDest = Arg1;
}
} else {
// Always invalid.
return this->emitInvalid(E);
}
} else if (!OperatorNew->isReplaceableGlobalAllocationFunction())
return this->emitInvalidNewDeleteExpr(E, E);

const Descriptor *Desc;
if (ElemT) {
if (E->isArray())
Desc = nullptr; // We're not going to use it in this case.
else
Desc = P.createDescriptor(E, *ElemT, Descriptor::InlineDescMD,
/*IsConst=*/false, /*IsTemporary=*/false,
/*IsMutable=*/false);
} else {
Desc = P.createDescriptor(
E, ElementType.getTypePtr(),
E->isArray() ? std::nullopt : Descriptor::InlineDescMD,
/*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false, Init);
if (!PlacementDest) {
if (ElemT) {
if (E->isArray())
Desc = nullptr; // We're not going to use it in this case.
else
Desc = P.createDescriptor(E, *ElemT, Descriptor::InlineDescMD,
/*IsConst=*/false, /*IsTemporary=*/false,
/*IsMutable=*/false);
} else {
Desc = P.createDescriptor(
E, ElementType.getTypePtr(),
E->isArray() ? std::nullopt : Descriptor::InlineDescMD,
/*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false, Init);
}
}

if (E->isArray()) {
Expand All @@ -3148,26 +3164,42 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {

PrimType SizeT = classifyPrim(Stripped->getType());

if (!this->visit(Stripped))
return false;

if (ElemT) {
// N primitive elements.
if (!this->emitAllocN(SizeT, *ElemT, E, IsNoThrow, E))
if (PlacementDest) {
if (!this->visit(PlacementDest))
return false;
if (!this->visit(Stripped))
return false;
if (!this->emitCheckNewTypeMismatchArray(SizeT, E, E))
return false;
} else {
// N Composite elements.
if (!this->emitAllocCN(SizeT, Desc, IsNoThrow, E))
if (!this->visit(Stripped))
return false;

if (ElemT) {
// N primitive elements.
if (!this->emitAllocN(SizeT, *ElemT, E, IsNoThrow, E))
return false;
} else {
// N Composite elements.
if (!this->emitAllocCN(SizeT, Desc, IsNoThrow, E))
return false;
}
}

if (Init && !this->visitInitializer(Init))
return false;

} else {
// Allocate just one element.
if (!this->emitAlloc(Desc, E))
return false;
if (PlacementDest) {
if (!this->visit(PlacementDest))
return false;
if (!this->emitCheckNewTypeMismatch(E, E))
return false;
} else {
// Allocate just one element.
if (!this->emitAlloc(Desc, E))
return false;
}

if (Init) {
if (ElemT) {
Expand All @@ -3194,6 +3226,11 @@ template <class Emitter>
bool Compiler<Emitter>::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
const Expr *Arg = E->getArgument();

const FunctionDecl *OperatorDelete = E->getOperatorDelete();

if (!OperatorDelete->isReplaceableGlobalAllocationFunction())
return this->emitInvalidNewDeleteExpr(E, E);

// Arg must be an lvalue.
if (!this->visit(Arg))
return false;
Expand Down
87 changes: 87 additions & 0 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,93 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
return Call(S, OpPC, F, VarArgSize);
}

bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
std::optional<uint64_t> ArraySize) {
const Pointer &Ptr = S.Stk.peek<Pointer>();

if (!CheckStore(S, OpPC, Ptr))
return false;

if (!InvalidNewDeleteExpr(S, OpPC, E))
return false;

// Assume proper types in std functions.
if (S.Current->isStdFunction())
return true;

const auto *NewExpr = cast<CXXNewExpr>(E);
QualType StorageType = Ptr.getType();

if (isa_and_nonnull<CXXNewExpr>(Ptr.getFieldDesc()->asExpr())) {
// FIXME: Are there other cases where this is a problem?
StorageType = StorageType->getPointeeType();
}

const ASTContext &ASTCtx = S.getASTContext();
QualType AllocType;
if (ArraySize) {
AllocType = ASTCtx.getConstantArrayType(
NewExpr->getAllocatedType(),
APInt(64, static_cast<uint64_t>(*ArraySize), false), nullptr,
ArraySizeModifier::Normal, 0);
} else {
AllocType = NewExpr->getAllocatedType();
}

unsigned StorageSize = 1;
unsigned AllocSize = 1;
if (const auto *CAT = dyn_cast<ConstantArrayType>(AllocType))
AllocSize = CAT->getZExtSize();
if (const auto *CAT = dyn_cast<ConstantArrayType>(StorageType))
StorageSize = CAT->getZExtSize();

if (AllocSize > StorageSize ||
!ASTCtx.hasSimilarType(ASTCtx.getBaseElementType(AllocType),
ASTCtx.getBaseElementType(StorageType))) {
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_constexpr_placement_new_wrong_type)
<< StorageType << AllocType;
return false;
}
return true;
}

bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {
assert(E);
const auto &Loc = S.Current->getSource(OpPC);

if (S.getLangOpts().CPlusPlus26)
return true;

if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();

if (!S.getLangOpts().CPlusPlus26 && NewExpr->getNumPlacementArgs() > 0) {
// This is allowed pre-C++26, but only an std function.
if (S.Current->isStdFunction())
return true;
S.FFDiag(Loc, diag::note_constexpr_new_placement)
<< /*C++26 feature*/ 1 << E->getSourceRange();
} else if (NewExpr->getNumPlacementArgs() == 1 &&
!OperatorNew->isReservedGlobalPlacementOperator()) {
S.FFDiag(Loc, diag::note_constexpr_new_placement)
<< /*Unsupported*/ 0 << E->getSourceRange();
} else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
}
} else {
const auto *DeleteExpr = cast<CXXDeleteExpr>(E);
const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
if (!OperatorDelete->isReplaceableGlobalAllocationFunction()) {
S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
<< isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
}
}

return false;
}

bool Interpret(InterpState &S, APValue &Result) {
// The current stack frame when we started Interpret().
// This is being used by the ops to determine wheter
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -2947,6 +2947,17 @@ static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
return true;
}

/// Check if the initializer and storage types of a placement-new expression
/// match.
bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
std::optional<uint64_t> ArraySize = std::nullopt);

template <PrimType Name, class T = typename PrimConv<Name>::T>
bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
const auto &Size = S.Stk.pop<T>();
return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
}
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1306,7 +1306,16 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
return false;
}

// FIXME: CheckArraySize for NumElems?
// NB: The same check we're using in CheckArraySize()
if (NumElems.getActiveBits() >
ConstantArrayType::getMaxSizeBits(S.getASTContext()) ||
NumElems.ugt(Descriptor::MaxArrayElemBytes / ElemSize.getQuantity())) {
// FIXME: NoThrow check?
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_new_too_large)
<< NumElems.getZExtValue();
return false;
}

std::optional<PrimType> ElemT = S.getContext().classify(ElemType);
DynamicAllocator &Allocator = S.getAllocator();
Expand Down Expand Up @@ -1336,8 +1345,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
assert(!ElemT);
// Structs etc.
const Descriptor *Desc = S.P.createDescriptor(
Call, ElemType.getTypePtr(),
NumElems.ule(1) ? std::nullopt : Descriptor::InlineDescMD,
Call, ElemType.getTypePtr(), Descriptor::InlineDescMD,
/*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false,
/*Init=*/nullptr);

Expand Down
26 changes: 24 additions & 2 deletions clang/lib/AST/ByteCode/InterpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,26 @@ static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx,
V.toAPValue(ASTCtx).printPretty(OS, ASTCtx, Ty);
}

static bool shouldSkipInBacktrace(const Function *F) {
if (F->isBuiltin())
return true;
if (F->isLambdaStaticInvoker())
return true;

const FunctionDecl *FD = F->getDecl();
if (FD->getDeclName().getCXXOverloadedOperator() == OO_New ||
FD->getDeclName().getCXXOverloadedOperator() == OO_Array_New)
return true;
return false;
}

void InterpFrame::describe(llvm::raw_ostream &OS) const {
// We create frames for builtin functions as well, but we can't reliably
// diagnose them. The 'in call to' diagnostics for them add no value to the
// user _and_ it doesn't generally work since the argument types don't always
// match the function prototype. Just ignore them.
// Similarly, for lambda static invokers, we would just print __invoke().
if (const auto *F = getFunction();
F && (F->isBuiltin() || F->isLambdaStaticInvoker()))
if (const auto *F = getFunction(); F && shouldSkipInBacktrace(F))
return;

const Expr *CallExpr = Caller->getExpr(getRetPC());
Expand Down Expand Up @@ -245,3 +257,13 @@ SourceRange InterpFrame::getRange(CodePtr PC) const {

return S.getRange(Func, PC);
}

bool InterpFrame::isStdFunction() const {
if (!Func)
return false;
for (const DeclContext *DC = Func->getDecl(); DC; DC = DC->getParent())
if (DC->isStdNamespace())
return true;

return false;
}
2 changes: 2 additions & 0 deletions clang/lib/AST/ByteCode/InterpFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ class InterpFrame final : public Frame {

unsigned getDepth() const { return Depth; }

bool isStdFunction() const;

void dump() const { dump(llvm::errs(), 0); }
void dump(llvm::raw_ostream &OS, unsigned Indent = 0) const;

Expand Down
14 changes: 14 additions & 0 deletions clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -787,4 +787,18 @@ def Free : Opcode {
let Args = [ArgBool];
}

def CheckNewTypeMismatch : Opcode {
let Args = [ArgExpr];
}

def InvalidNewDeleteExpr : Opcode {
let Args = [ArgExpr];
}

def CheckNewTypeMismatchArray : Opcode {
let Types = [IntegerTypeClass];
let Args = [ArgExpr];
let HasGroup = 1;
}

def IsConstantContext: Opcode;
3 changes: 2 additions & 1 deletion clang/lib/Basic/Targets/BPF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
}

Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");
Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");
Builder.defineMacro("__BPF_FEATURE_ATOMIC_MEM_ORDERING");

if (CPU.empty())
CPU = "v3";
Expand All @@ -48,7 +50,6 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,

std::string CpuVerNumStr = CPU.substr(1);
Builder.defineMacro("__BPF_CPU_VERSION__", CpuVerNumStr);
Builder.defineMacro("__BPF_FEATURE_MAY_GOTO");

int CpuVerNum = std::stoi(CpuVerNumStr);
if (CpuVerNum >= 2)
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,3 +486,15 @@ bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const {
bool RISCVTargetInfo::isValidFeatureName(StringRef Name) const {
return llvm::RISCVISAInfo::isSupportedExtensionFeature(Name);
}

bool RISCVTargetInfo::validateGlobalRegisterVariable(
StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const {
if (RegName == "ra" || RegName == "sp" || RegName == "gp" ||
RegName == "tp" || RegName.starts_with("x") || RegName.starts_with("a") ||
RegName.starts_with("s") || RegName.starts_with("t")) {
unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
HasSizeMismatch = RegSize != XLen;
return true;
}
return false;
}
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ class RISCVTargetInfo : public TargetInfo {
bool supportsCpuInit() const override { return getTriple().isOSLinux(); }
bool validateCpuSupports(StringRef Feature) const override;
bool isValidFeatureName(StringRef Name) const override;

bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,
bool &HasSizeMismatch) const override;
};
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
public:
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Basic/Targets/SPIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
PointerWidth = PointerAlign = 32;
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
// SPIR-V has core support for atomic ops, and Int32 is always available;
// we take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 32);
resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
}
Expand All @@ -356,6 +359,9 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
// SPIR-V has core support for atomic ops, and Int64 is always available;
// we take the maximum because it's possible the Host supports wider types.
MaxAtomicInlineWidth = std::max<unsigned char>(MaxAtomicInlineWidth, 64);
resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,8 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
Options.MCOptions.X86RelaxRelocations = CodeGenOpts.X86RelaxRelocations;
Options.MCOptions.CompressDebugSections =
CodeGenOpts.getCompressDebugSections();
if (CodeGenOpts.OutputAsmVariant != 3) // 3 (default): not specified
Options.MCOptions.OutputAsmVariant = CodeGenOpts.OutputAsmVariant;
Options.MCOptions.ABIName = TargetOpts.ABI;
for (const auto &Entry : HSOpts.UserEntries)
if (!Entry.IsFramework &&
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/CodeGen/CGAtomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,8 +766,19 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
// LLVM atomic instructions always have synch scope. If clang atomic
// expression has no scope operand, use default LLVM synch scope.
if (!ScopeModel) {
llvm::SyncScope::ID SS;
if (CGF.getLangOpts().OpenCL)
// OpenCL approach is: "The functions that do not have memory_scope
// argument have the same semantics as the corresponding functions with
// the memory_scope argument set to memory_scope_device." See ref.:
// https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_C.html#atomic-functions
SS = CGF.getTargetHooks().getLLVMSyncScopeID(CGF.getLangOpts(),
SyncScope::OpenCLDevice,
Order, CGF.getLLVMContext());
else
SS = llvm::SyncScope::System;
EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
Order, CGF.CGM.getLLVMContext().getOrInsertSyncScopeID(""));
Order, SS);
return;
}

Expand Down
13 changes: 7 additions & 6 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,9 +587,10 @@ static Value *emitCallMaybeConstrainedFPBuiltin(CodeGenFunction &CGF,
// matching the argument type. It is assumed that only the first argument is
// overloaded.
template <unsigned N>
Value *emitBuiltinWithOneOverloadedType(CodeGenFunction &CGF, const CallExpr *E,
unsigned IntrinsicID,
llvm::StringRef Name = "") {
static Value *emitBuiltinWithOneOverloadedType(CodeGenFunction &CGF,
const CallExpr *E,
unsigned IntrinsicID,
llvm::StringRef Name = "") {
static_assert(N, "expect non-empty argument");
SmallVector<Value *, N> Args;
for (unsigned I = 0; I < N; ++I)
Expand Down Expand Up @@ -13649,7 +13650,7 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID,
else
InitValStr = std::to_string(InitVal.getZExtValue());
std::string EnumStr = Enumerator->getNameAsString() + ":" + InitValStr;
Value *EnumStrVal = Builder.CreateGlobalStringPtr(EnumStr);
Value *EnumStrVal = Builder.CreateGlobalString(EnumStr);

ConstantInt *Flag = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
Value *FlagValue = ConstantInt::get(Int64Ty, Flag->getSExtValue());
Expand Down Expand Up @@ -18175,7 +18176,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
CallOps.push_back(Ops[i]);
llvm::Function *F = CGM.getIntrinsic(ID);
Value *Call = Builder.CreateCall(F, CallOps);
return Builder.CreateAlignedStore(Call, Ops[0], MaybeAlign(64));
return Builder.CreateAlignedStore(Call, Ops[0], MaybeAlign());
}

case PPC::BI__builtin_ppc_compare_and_swap:
Expand Down Expand Up @@ -18569,7 +18570,7 @@ llvm::Value *CodeGenFunction::EmitScalarOrConstFoldImmArg(unsigned ICEArguments,
}

// Return dot product intrinsic that corresponds to the QT scalar type
Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT) {
static Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT) {
if (QT->isFloatingType())
return RT.getFDotIntrinsic();
if (QT->isSignedIntegerType())
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1249,8 +1249,12 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
CGM.getTarget().getDWARFAddressSpace(
CGM.getTypes().getTargetAddressSpace(PointeeTy));

const BTFTagAttributedType *BTFAttrTy;
if (auto *Atomic = PointeeTy->getAs<AtomicType>())
BTFAttrTy = dyn_cast<BTFTagAttributedType>(Atomic->getValueType());
else
BTFAttrTy = dyn_cast<BTFTagAttributedType>(PointeeTy);
SmallVector<llvm::Metadata *, 4> Annots;
auto *BTFAttrTy = dyn_cast<BTFTagAttributedType>(PointeeTy);
while (BTFAttrTy) {
StringRef Tag = BTFAttrTy->getAttr()->getBTFTypeTag();
if (!Tag.empty()) {
Expand Down
40 changes: 38 additions & 2 deletions clang/lib/CodeGen/CGExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,17 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
// Prepare a 'this' for CXXDefaultInitExprs.
CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddress());

const bool ZeroInitPadding =
CGF.CGM.shouldZeroInitPadding() && !Dest.isZeroed();
const Address BaseLoc = Dest.getAddress().withElementType(CGF.Int8Ty);
auto DoZeroInitPadding = [&](CharUnits Offset, CharUnits Size) {
if (Size.isPositive()) {
Address Loc = CGF.Builder.CreateConstGEP(BaseLoc, Offset.getQuantity());
llvm::Constant *SizeVal = CGF.Builder.getInt64(Size.getQuantity());
CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, false);
}
};

if (record->isUnion()) {
// Only initialize one field of a union. The field itself is
// specified by the initializer list.
Expand All @@ -1722,17 +1733,37 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
if (NumInitElements) {
// Store the initializer into the field
EmitInitializationToLValue(InitExprs[0], FieldLoc);
if (ZeroInitPadding) {
CharUnits TotalSize =
Dest.getPreferredSize(CGF.getContext(), DestLV.getType());
CharUnits FieldSize =
CGF.getContext().getTypeSizeInChars(FieldLoc.getType());
DoZeroInitPadding(FieldSize, TotalSize - FieldSize);
}
} else {
// Default-initialize to null.
EmitNullInitializationToLValue(FieldLoc);
if (ZeroInitPadding)
EmitNullInitializationToLValue(DestLV);
else
EmitNullInitializationToLValue(FieldLoc);
}

return;
}

// Here we iterate over the fields; this makes it simpler to both
// default-initialize fields and skip over unnamed fields.
const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(record);
CharUnits SizeSoFar = CharUnits::Zero();
for (const auto *field : record->fields()) {
if (ZeroInitPadding) {
unsigned FieldNo = field->getFieldIndex();
CharUnits Offset =
CGF.getContext().toCharUnitsFromBits(Layout.getFieldOffset(FieldNo));
DoZeroInitPadding(SizeSoFar, Offset - SizeSoFar);
CharUnits FieldSize =
CGF.getContext().getTypeSizeInChars(field->getType());
SizeSoFar = Offset + FieldSize;
}
// We're done once we hit the flexible array member.
if (field->getType()->isIncompleteArrayType())
break;
Expand Down Expand Up @@ -1774,6 +1805,11 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
}
}
}
if (ZeroInitPadding) {
CharUnits TotalSize =
Dest.getPreferredSize(CGF.getContext(), DestLV.getType());
DoZeroInitPadding(SizeSoFar, TotalSize - SizeSoFar);
}
}

void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
Expand Down
93 changes: 82 additions & 11 deletions clang/lib/CodeGen/CGExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ using namespace CodeGen;
namespace {
class ConstExprEmitter;

llvm::Constant *getPadding(const CodeGenModule &CGM, CharUnits PadSize) {
llvm::Type *Ty = CGM.CharTy;
if (PadSize > CharUnits::One())
Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity());
if (CGM.shouldZeroInitPadding()) {
return llvm::Constant::getNullValue(Ty);
}
return llvm::UndefValue::get(Ty);
}

struct ConstantAggregateBuilderUtils {
CodeGenModule &CGM;

Expand All @@ -61,10 +71,7 @@ struct ConstantAggregateBuilderUtils {
}

llvm::Constant *getPadding(CharUnits PadSize) const {
llvm::Type *Ty = CGM.CharTy;
if (PadSize > CharUnits::One())
Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity());
return llvm::UndefValue::get(Ty);
return ::getPadding(CGM, PadSize);
}

llvm::Constant *getZeroes(CharUnits ZeroSize) const {
Expand Down Expand Up @@ -591,6 +598,11 @@ class ConstStructBuilder {
bool Build(const InitListExpr *ILE, bool AllowOverwrite);
bool Build(const APValue &Val, const RecordDecl *RD, bool IsPrimaryBase,
const CXXRecordDecl *VTableClass, CharUnits BaseOffset);
bool DoZeroInitPadding(const ASTRecordLayout &Layout, unsigned FieldNo,
const FieldDecl &Field, bool AllowOverwrite,
CharUnits &FieldSize, CharUnits &SizeSoFar);
bool DoZeroInitPadding(const ASTRecordLayout &Layout, bool AllowOverwrite,
CharUnits &SizeSoFar);
llvm::Constant *Finalize(QualType Ty);
};

Expand Down Expand Up @@ -715,6 +727,10 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {
if (CXXRD->getNumBases())
return false;

const bool ZeroInitPadding = CGM.shouldZeroInitPadding();
CharUnits FieldSize = CharUnits::Zero();
CharUnits SizeSoFar = CharUnits::Zero();

for (FieldDecl *Field : RD->fields()) {
++FieldNo;

Expand All @@ -732,8 +748,13 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {
const Expr *Init = nullptr;
if (ElementNo < ILE->getNumInits())
Init = ILE->getInit(ElementNo++);
if (isa_and_nonnull<NoInitExpr>(Init))
if (isa_and_nonnull<NoInitExpr>(Init)) {
if (ZeroInitPadding &&
!DoZeroInitPadding(Layout, FieldNo, *Field, AllowOverwrite, FieldSize,
SizeSoFar))
return false;
continue;
}

// Zero-sized fields are not emitted, but their initializers may still
// prevent emission of this struct as a constant.
Expand All @@ -743,6 +764,11 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {
continue;
}

if (ZeroInitPadding &&
!DoZeroInitPadding(Layout, FieldNo, *Field, AllowOverwrite, FieldSize,
SizeSoFar))
return false;

// When emitting a DesignatedInitUpdateExpr, a nested InitListExpr
// represents additional overwriting of our current constant value, and not
// a new constant to emit independently.
Expand All @@ -768,6 +794,10 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {
if (!EltInit)
return false;

if (ZeroInitPadding && FieldSize.isZero())
SizeSoFar += CharUnits::fromQuantity(
CGM.getDataLayout().getTypeAllocSize(EltInit->getType()));

if (!Field->isBitField()) {
// Handle non-bitfield members.
if (!AppendField(Field, Layout.getFieldOffset(FieldNo), EltInit,
Expand All @@ -785,6 +815,9 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {
}
}

if (ZeroInitPadding && !DoZeroInitPadding(Layout, AllowOverwrite, SizeSoFar))
return false;

return true;
}

Expand Down Expand Up @@ -849,6 +882,9 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,

unsigned FieldNo = 0;
uint64_t OffsetBits = CGM.getContext().toBits(Offset);
const bool ZeroInitPadding = CGM.shouldZeroInitPadding();
CharUnits FieldSize = CharUnits::Zero();
CharUnits SizeSoFar = CharUnits::Zero();

bool AllowOverwrite = false;
for (RecordDecl::field_iterator Field = RD->field_begin(),
Expand All @@ -870,6 +906,15 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
if (!EltInit)
return false;

if (ZeroInitPadding) {
if (!DoZeroInitPadding(Layout, FieldNo, **Field, AllowOverwrite,
FieldSize, SizeSoFar))
return false;
if (FieldSize.isZero())
SizeSoFar += CharUnits::fromQuantity(
CGM.getDataLayout().getTypeAllocSize(EltInit->getType()));
}

if (!Field->isBitField()) {
// Handle non-bitfield members.
if (!AppendField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits,
Expand All @@ -886,7 +931,35 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
return false;
}
}
if (ZeroInitPadding && !DoZeroInitPadding(Layout, AllowOverwrite, SizeSoFar))
return false;

return true;
}

bool ConstStructBuilder::DoZeroInitPadding(
const ASTRecordLayout &Layout, unsigned FieldNo, const FieldDecl &Field,
bool AllowOverwrite, CharUnits &FieldSize, CharUnits &SizeSoFar) {
CharUnits Offset =
CGM.getContext().toCharUnitsFromBits(Layout.getFieldOffset(FieldNo));
if (SizeSoFar < Offset)
if (!AppendBytes(SizeSoFar, getPadding(CGM, Offset - SizeSoFar),
AllowOverwrite))
return false;
FieldSize = CGM.getContext().getTypeSizeInChars(Field.getType());
SizeSoFar = Offset + FieldSize;
return true;
}

bool ConstStructBuilder::DoZeroInitPadding(const ASTRecordLayout &Layout,
bool AllowOverwrite,
CharUnits &SizeSoFar) {
CharUnits TotalSize = Layout.getSize();
if (SizeSoFar < TotalSize)
if (!AppendBytes(SizeSoFar, getPadding(CGM, TotalSize - SizeSoFar),
AllowOverwrite))
return false;
SizeSoFar = TotalSize;
return true;
}

Expand Down Expand Up @@ -1127,12 +1200,10 @@ class ConstExprEmitter

assert(CurSize <= TotalSize && "Union size mismatch!");
if (unsigned NumPadBytes = TotalSize - CurSize) {
llvm::Type *Ty = CGM.CharTy;
if (NumPadBytes > 1)
Ty = llvm::ArrayType::get(Ty, NumPadBytes);

Elts.push_back(llvm::UndefValue::get(Ty));
Types.push_back(Ty);
llvm::Constant *Padding =
getPadding(CGM, CharUnits::fromQuantity(NumPadBytes));
Elts.push_back(Padding);
Types.push_back(Padding->getType());
}

llvm::StructType *STy = llvm::StructType::get(VMContext, Types, false);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1807,7 +1807,7 @@ ScalarExprEmitter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) {
ASTContext &Context = CGF.getContext();
unsigned AddrSpace =
Context.getTargetAddressSpace(CGF.CGM.GetGlobalConstantAddressSpace());
llvm::Constant *GlobalConstStr = Builder.CreateGlobalStringPtr(
llvm::Constant *GlobalConstStr = Builder.CreateGlobalString(
E->ComputeName(Context), "__usn_str", AddrSpace);

llvm::Type *ExprTy = ConvertType(E->getType());
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,7 @@ llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() {
return llvm::PointerType::getUnqual(Kmpc_MicroTy);
}

llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseKind
static llvm::OffloadEntriesInfoManager::OMPTargetDeviceClauseKind
convertDeviceClause(const VarDecl *VD) {
std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(VD);
Expand All @@ -1513,7 +1513,7 @@ convertDeviceClause(const VarDecl *VD) {
}
}

llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind
static llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind
convertCaptureClause(const VarDecl *VD) {
std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapType =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
Expand Down Expand Up @@ -8836,7 +8836,7 @@ static ValueDecl *getDeclFromThisExpr(const Expr *E) {

/// Emit a string constant containing the names of the values mapped to the
/// offloading runtime library.
llvm::Constant *
static llvm::Constant *
emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder,
MappableExprsHandler::MappingExprInfo &MapExprs) {

Expand Down Expand Up @@ -9450,8 +9450,8 @@ static llvm::Value *emitDeviceID(
return DeviceID;
}

llvm::Value *emitDynCGGroupMem(const OMPExecutableDirective &D,
CodeGenFunction &CGF) {
static llvm::Value *emitDynCGGroupMem(const OMPExecutableDirective &D,
CodeGenFunction &CGF) {
llvm::Value *DynCGroupMem = CGF.Builder.getInt32(0);

if (auto *DynMemClause = D.getSingleClause<OMPXDynCGroupMemClause>()) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// C99 6.8.4.1: The first substatement is executed if the expression compares
// unequal to 0. The condition must be a scalar type.
LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
ApplyDebugLocation DL(*this, S.getCond());

if (S.getInit())
EmitStmt(S.getInit());
Expand Down
15 changes: 8 additions & 7 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2734,8 +2734,8 @@ GetAlignedMapping(const OMPLoopDirective &S, CodeGenFunction &CGF) {

// Pass OMPLoopDirective (instead of OMPSimdDirective) to make this function
// available for "loop bind(thread)", which maps to "simd".
void emitOMPSimdDirective(const OMPLoopDirective &S, CodeGenFunction &CGF,
CodeGenModule &CGM) {
static void emitOMPSimdDirective(const OMPLoopDirective &S,
CodeGenFunction &CGF, CodeGenModule &CGM) {
bool UseOMPIRBuilder =
CGM.getLangOpts().OpenMPIRBuilder && isSimdSupportedByOpenMPIRBuilder(S);
if (UseOMPIRBuilder) {
Expand Down Expand Up @@ -3987,8 +3987,8 @@ convertClauseKindToSchedKind(OpenMPScheduleClauseKind ScheduleClauseKind) {

// Pass OMPLoopDirective (instead of OMPForDirective) to make this function
// available for "loop bind(parallel)", which maps to "for".
void emitOMPForDirective(const OMPLoopDirective &S, CodeGenFunction &CGF,
CodeGenModule &CGM, bool HasCancel) {
static void emitOMPForDirective(const OMPLoopDirective &S, CodeGenFunction &CGF,
CodeGenModule &CGM, bool HasCancel) {
bool HasLastprivates = false;
bool UseOMPIRBuilder = CGM.getLangOpts().OpenMPIRBuilder &&
isForSupportedByOpenMPIRBuilder(S, HasCancel);
Expand Down Expand Up @@ -5447,7 +5447,7 @@ void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) {
CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc(), Data);
}

bool isSupportedByOpenMPIRBuilder(const OMPTaskgroupDirective &T) {
static bool isSupportedByOpenMPIRBuilder(const OMPTaskgroupDirective &T) {
return T.clauses().empty();
}

Expand Down Expand Up @@ -5968,8 +5968,9 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S,

// Pass OMPLoopDirective (instead of OMPDistributeDirective) to make this
// function available for "loop bind(teams)", which maps to "distribute".
void emitOMPDistributeDirective(const OMPLoopDirective &S, CodeGenFunction &CGF,
CodeGenModule &CGM) {
static void emitOMPDistributeDirective(const OMPLoopDirective &S,
CodeGenFunction &CGF,
CodeGenModule &CGM) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -784,8 +784,9 @@ getLLVMVisibility(clang::LangOptions::VisibilityFromDLLStorageClassKinds K) {
llvm_unreachable("unknown option value!");
}

void setLLVMVisibility(llvm::GlobalValue &GV,
std::optional<llvm::GlobalValue::VisibilityTypes> V) {
static void
setLLVMVisibility(llvm::GlobalValue &GV,
std::optional<llvm::GlobalValue::VisibilityTypes> V) {
if (!V)
return;

Expand Down Expand Up @@ -4224,8 +4225,8 @@ TargetMVPriority(const TargetInfo &TI,
// in the cases of CPUDispatch, this causes issues. This also makes sure we
// work with internal linkage functions, so that the same function name can be
// used with internal linkage in multiple TUs.
llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
GlobalDecl GD) {
static llvm::GlobalValue::LinkageTypes
getMultiversionLinkage(CodeGenModule &CGM, GlobalDecl GD) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
if (FD->getFormalLinkage() == Linkage::Internal)
return llvm::GlobalValue::InternalLinkage;
Expand Down
51 changes: 51 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1676,6 +1676,57 @@ class CodeGenModule : public CodeGenTypeCache {
MustTailCallUndefinedGlobals.insert(Global);
}

bool shouldZeroInitPadding() const {
// In C23 (N3096) $6.7.10:
// """
// If any object is initialized with an empty iniitializer, then it is
// subject to default initialization:
// - if it is an aggregate, every member is initialized (recursively)
// according to these rules, and any padding is initialized to zero bits;
// - if it is a union, the first named member is initialized (recursively)
// according to these rules, and any padding is initialized to zero bits.
//
// If the aggregate or union contains elements or members that are
// aggregates or unions, these rules apply recursively to the subaggregates
// or contained unions.
//
// If there are fewer initializers in a brace-enclosed list than there are
// elements or members of an aggregate, or fewer characters in a string
// literal used to initialize an array of known size than there are elements
// in the array, the remainder of the aggregate is subject to default
// initialization.
// """
//
// From my understanding, the standard is ambiguous in the following two
// areas:
// 1. For a union type with empty initializer, if the first named member is
// not the largest member, then the bytes comes after the first named member
// but before padding are left unspecified. An example is:
// union U { int a; long long b;};
// union U u = {}; // The first 4 bytes are 0, but 4-8 bytes are left
// unspecified.
//
// 2. It only mentions padding for empty initializer, but doesn't mention
// padding for a non empty initialization list. And if the aggregation or
// union contains elements or members that are aggregates or unions, and
// some are non empty initializers, while others are empty initiailizers,
// the padding initialization is unclear. An example is:
// struct S1 { int a; long long b; };
// struct S2 { char c; struct S1 s1; };
// // The values for paddings between s2.c and s2.s1.a, between s2.s1.a
// and s2.s1.b are unclear.
// struct S2 s2 = { 'c' };
//
// Here we choose to zero initiailize left bytes of a union type. Because
// projects like the Linux kernel are relying on this behavior. If we don't
// explicitly zero initialize them, the undef values can be optimized to
// return gabage data. We also choose to zero initialize paddings for
// aggregates and unions, no matter they are initialized by empty
// initializers or non empty initializers. This can provide a consistent
// behavior. So projects like the Linux kernel can rely on it.
return !getLangOpts().CPlusPlus;
}

private:
bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const;

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/SanitizerMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ static bool isAsanHwasanOrMemTag(const SanitizerSet &SS) {
SanitizerKind::HWAddress | SanitizerKind::MemTag);
}

SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
if (Mask & (SanitizerKind::Address | SanitizerKind::KernelAddress))
Mask |= SanitizerKind::Address | SanitizerKind::KernelAddress;
// Note: KHWASan doesn't support globals.
Expand Down
36 changes: 36 additions & 0 deletions clang/lib/CodeGen/Targets/SPIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,36 @@ class SPIRVTargetCodeGenInfo : public CommonSPIRTargetCodeGenInfo {
SPIRVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
: CommonSPIRTargetCodeGenInfo(std::make_unique<SPIRVABIInfo>(CGT)) {}
void setCUDAKernelCallingConvention(const FunctionType *&FT) const override;
llvm::SyncScope::ID getLLVMSyncScopeID(const LangOptions &LangOpts,
SyncScope Scope,
llvm::AtomicOrdering Ordering,
llvm::LLVMContext &Ctx) const override;
};

inline StringRef mapClangSyncScopeToLLVM(SyncScope Scope) {
switch (Scope) {
case SyncScope::HIPSingleThread:
case SyncScope::SingleScope:
return "singlethread";
case SyncScope::HIPWavefront:
case SyncScope::OpenCLSubGroup:
case SyncScope::WavefrontScope:
return "subgroup";
case SyncScope::HIPWorkgroup:
case SyncScope::OpenCLWorkGroup:
case SyncScope::WorkgroupScope:
return "workgroup";
case SyncScope::HIPAgent:
case SyncScope::OpenCLDevice:
case SyncScope::DeviceScope:
return "device";
case SyncScope::SystemScope:
case SyncScope::HIPSystem:
case SyncScope::OpenCLAllSVMDevices:
return "";
}
return "";
}
} // End anonymous namespace.

void CommonSPIRABIInfo::setCCs() {
Expand Down Expand Up @@ -188,6 +217,13 @@ void SPIRVTargetCodeGenInfo::setCUDAKernelCallingConvention(
}
}

llvm::SyncScope::ID
SPIRVTargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &, SyncScope Scope,
llvm::AtomicOrdering,
llvm::LLVMContext &Ctx) const {
return Ctx.getOrInsertSyncScopeID(mapClangSyncScopeToLLVM(Scope));
}

/// Construct a SPIR-V target extension type for the given OpenCL image type.
static llvm::Type *getSPIRVImageType(llvm::LLVMContext &Ctx, StringRef BaseType,
StringRef OpenCLName,
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/CrossTU/CrossTranslationUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,9 +566,9 @@ CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) {
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
return ASTUnit::LoadFromASTFile(
std::string(ASTDumpPath.str()),
CI.getPCHContainerOperations()->getRawReader(), ASTUnit::LoadEverything,
Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOptsPtr());
ASTDumpPath, CI.getPCHContainerOperations()->getRawReader(),
ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts(),
CI.getHeaderSearchOptsPtr());
}

/// Load the AST from a source-file, which is supposed to be located inside the
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Frontend/ASTUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
}

std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
const std::string &Filename, const PCHContainerReader &PCHContainerRdr,
StringRef Filename, const PCHContainerReader &PCHContainerRdr,
WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts,
std::shared_ptr<HeaderSearchOptions> HSOpts,
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Frontend/FrontendAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
StringRef InputFile = Input.getFile();

std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
std::string(InputFile), CI.getPCHContainerReader(),
ASTUnit::LoadPreprocessorOnly, ASTDiags, CI.getFileSystemOpts(),
InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly,
ASTDiags, CI.getFileSystemOpts(),
/*HeaderSearchOptions=*/nullptr);
if (!AST)
return false;
Expand Down Expand Up @@ -693,9 +693,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
StringRef InputFile = Input.getFile();

std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
std::string(InputFile), CI.getPCHContainerReader(),
ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts(),
CI.getHeaderSearchOptsPtr(), CI.getLangOptsPtr());
InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
CI.getFileSystemOpts(), CI.getHeaderSearchOptsPtr(),
CI.getLangOptsPtr());

if (!AST)
return false;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Frontend/MultiplexConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,13 @@ MultiplexConsumer::MultiplexConsumer(
}
}

MultiplexConsumer::MultiplexConsumer(std::unique_ptr<ASTConsumer> C)
: MultiplexConsumer([](std::unique_ptr<ASTConsumer> Consumer) {
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
Consumers.push_back(std::move(Consumer));
return Consumers;
}(std::move(C))) {}

MultiplexConsumer::~MultiplexConsumer() {}

void MultiplexConsumer::Initialize(ASTContext &Context) {
Expand Down
82 changes: 30 additions & 52 deletions clang/lib/Frontend/Rewrite/RewriteObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,8 @@ namespace {
SmallVector<DeclRefExpr *, 32> BlockDeclRefs;

// Block related declarations.
SmallVector<ValueDecl *, 8> BlockByCopyDecls;
llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet;
SmallVector<ValueDecl *, 8> BlockByRefDecls;
llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet;
llvm::SmallSetVector<ValueDecl *, 8> BlockByCopyDecls;
llvm::SmallSetVector<ValueDecl *, 8> BlockByRefDecls;
llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo;
llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
llvm::SmallPtrSet<VarDecl *, 8> ImportedLocalExternalDecls;
Expand Down Expand Up @@ -3292,8 +3290,8 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,

// Create local declarations to avoid rewriting all closure decl ref exprs.
// First, emit a declaration for all "by ref" decls.
for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
for (auto I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E;
++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
std::string TypeString;
Expand All @@ -3303,8 +3301,8 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
}
// Next, emit a declaration for all "by copy" declarations.
for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
for (auto I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E;
++I) {
S += " ";
// Handle nested closure invocation. For example:
//
Expand Down Expand Up @@ -3357,7 +3355,7 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
S += VD->getNameAsString();
S += ", (void*)src->";
S += VD->getNameAsString();
if (BlockByRefDeclsPtrSet.count(VD))
if (BlockByRefDecls.contains(VD))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else if (VD->getType()->isBlockPointerType())
S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
Expand All @@ -3374,7 +3372,7 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
for (ValueDecl *VD : ImportedBlockDecls) {
S += "_Block_object_dispose((void*)src->";
S += VD->getNameAsString();
if (BlockByRefDeclsPtrSet.count(VD))
if (BlockByRefDecls.contains(VD))
S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);";
else if (VD->getType()->isBlockPointerType())
S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);";
Expand All @@ -3400,8 +3398,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,

if (BlockDeclRefs.size()) {
// Output all "by copy" declarations.
for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
for (auto I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E;
++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
std::string ArgName = "_" + FieldName;
Expand Down Expand Up @@ -3429,8 +3427,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += FieldName + ";\n";
}
// Output all "by ref" declarations.
for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
for (auto I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E;
++I) {
S += " ";
std::string FieldName = (*I)->getNameAsString();
std::string ArgName = "_" + FieldName;
Expand All @@ -3448,8 +3446,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += ", int flags=0)";
// Initialize all "by copy" arguments.
bool firsTime = true;
for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
for (auto I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E;
++I) {
std::string Name = (*I)->getNameAsString();
if (firsTime) {
Constructor += " : ";
Expand All @@ -3463,8 +3461,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
Constructor += Name + "(_" + Name + ")";
}
// Initialize all "by ref" arguments.
for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
for (auto I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E;
++I) {
std::string Name = (*I)->getNameAsString();
if (firsTime) {
Constructor += " : ";
Expand Down Expand Up @@ -3553,14 +3551,10 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
DeclRefExpr *Exp = InnerDeclRefs[count++];
ValueDecl *VD = Exp->getDecl();
BlockDeclRefs.push_back(Exp);
if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) {
BlockByCopyDeclsPtrSet.insert(VD);
BlockByCopyDecls.push_back(VD);
}
if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) {
BlockByRefDeclsPtrSet.insert(VD);
BlockByRefDecls.push_back(VD);
}
if (VD->hasAttr<BlocksAttr>())
BlockByRefDecls.insert(VD);
else
BlockByCopyDecls.insert(VD);
// imported objects in the inner blocks not used in the outer
// blocks must be copied/disposed in the outer block as well.
if (VD->hasAttr<BlocksAttr>() ||
Expand Down Expand Up @@ -3590,9 +3584,7 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,

BlockDeclRefs.clear();
BlockByRefDecls.clear();
BlockByRefDeclsPtrSet.clear();
BlockByCopyDecls.clear();
BlockByCopyDeclsPtrSet.clear();
ImportedBlockDecls.clear();
}
if (RewriteSC) {
Expand Down Expand Up @@ -4314,20 +4306,12 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) {
if (BlockDeclRefs.size()) {
// Unique all "by copy" declarations.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
if (!BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) {
if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl());
}
}
if (!BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>())
BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
// Unique all "by ref" declarations.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>()) {
if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) {
BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl());
BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl());
}
}
if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>())
BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
// Find any imported blocks...they will need special attention.
for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
if (BlockDeclRefs[i]->getDecl()->hasAttr<BlocksAttr>() ||
Expand Down Expand Up @@ -4358,22 +4342,18 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) {
DeclRefExpr *Exp = InnerBlockDeclRefs[i];
ValueDecl *VD = Exp->getDecl();
if (!VD->hasAttr<BlocksAttr>() && !BlockByCopyDeclsPtrSet.count(VD)) {
if (!VD->hasAttr<BlocksAttr>() && BlockByCopyDecls.insert(VD)) {
// We need to save the copied-in variables in nested
// blocks because it is needed at the end for some of the API
// generations. See SynthesizeBlockLiterals routine.
InnerDeclRefs.push_back(Exp);
countOfInnerDecls++;
BlockDeclRefs.push_back(Exp);
BlockByCopyDeclsPtrSet.insert(VD);
BlockByCopyDecls.push_back(VD);
}
if (VD->hasAttr<BlocksAttr>() && !BlockByRefDeclsPtrSet.count(VD)) {
if (VD->hasAttr<BlocksAttr>() && BlockByRefDecls.insert(VD)) {
InnerDeclRefs.push_back(Exp);
countOfInnerDecls++;
BlockDeclRefs.push_back(Exp);
BlockByRefDeclsPtrSet.insert(VD);
BlockByRefDecls.push_back(VD);
}
}
// Find any imported blocks...they will need special attention.
Expand Down Expand Up @@ -4439,8 +4419,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
if (BlockDeclRefs.size()) {
Expr *Exp;
// Output all "by copy" declarations.
for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
for (auto I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E;
++I) {
if (isObjCType((*I)->getType())) {
// FIXME: Conform to ABI ([[obj retain] autorelease]).
FD = SynthBlockInitFunctionDecl((*I)->getName());
Expand Down Expand Up @@ -4476,8 +4456,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
InitExprs.push_back(Exp);
}
// Output all "by ref" declarations.
for (SmallVectorImpl<ValueDecl *>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
for (auto I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E;
++I) {
ValueDecl *ND = (*I);
std::string Name(ND->getNameAsString());
std::string RecName;
Expand Down Expand Up @@ -4534,9 +4514,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
NewRep);
BlockDeclRefs.clear();
BlockByRefDecls.clear();
BlockByRefDeclsPtrSet.clear();
BlockByCopyDecls.clear();
BlockByCopyDeclsPtrSet.clear();
ImportedBlockDecls.clear();
return NewRep;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Interpreter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_clang_library(clangInterpreter
IncrementalExecutor.cpp
IncrementalParser.cpp
Interpreter.cpp
InterpreterValuePrinter.cpp
InterpreterUtils.cpp
Value.cpp
${WASM_SRC}
Expand Down
21 changes: 12 additions & 9 deletions clang/lib/Interpreter/DeviceOffload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Interpreter/PartialTranslationUnit.h"

#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
Expand All @@ -24,15 +25,17 @@
namespace clang {

IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
Interpreter &Interp, std::unique_ptr<CompilerInstance> Instance,
IncrementalParser &HostParser, llvm::LLVMContext &LLVMCtx,
std::unique_ptr<CompilerInstance> DeviceInstance,
CompilerInstance &HostInstance,
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS,
llvm::Error &Err)
: IncrementalParser(Interp, std::move(Instance), LLVMCtx, Err),
HostParser(HostParser), VFS(FS) {
llvm::Error &Err, const std::list<PartialTranslationUnit> &PTUs)
: IncrementalParser(*DeviceInstance, Err), PTUs(PTUs), VFS(FS),
CodeGenOpts(HostInstance.getCodeGenOpts()),
TargetOpts(HostInstance.getTargetOpts()) {
if (Err)
return;
StringRef Arch = CI->getTargetOpts().CPU;
DeviceCI = std::move(DeviceInstance);
StringRef Arch = TargetOpts.CPU;
if (!Arch.starts_with("sm_") || Arch.substr(3).getAsInteger(10, SMVersion)) {
Err = llvm::joinErrors(std::move(Err), llvm::make_error<llvm::StringError>(
"Invalid CUDA architecture",
Expand All @@ -41,7 +44,7 @@ IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
}
}

llvm::Expected<PartialTranslationUnit &>
llvm::Expected<TranslationUnitDecl *>
IncrementalCUDADeviceParser::Parse(llvm::StringRef Input) {
auto PTU = IncrementalParser::Parse(Input);
if (!PTU)
Expand All @@ -62,7 +65,7 @@ IncrementalCUDADeviceParser::Parse(llvm::StringRef Input) {
llvm::StringRef(FatbinContent.data(), FatbinContent.size()),
"", false));

HostParser.getCI()->getCodeGenOpts().CudaGpuBinaryFileName = FatbinFileName;
CodeGenOpts.CudaGpuBinaryFileName = FatbinFileName;

FatbinContent.clear();

Expand All @@ -80,7 +83,7 @@ llvm::Expected<llvm::StringRef> IncrementalCUDADeviceParser::GeneratePTX() {
std::error_code());
llvm::TargetOptions TO = llvm::TargetOptions();
llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
PTU.TheModule->getTargetTriple(), getCI()->getTargetOpts().CPU, "", TO,
PTU.TheModule->getTargetTriple(), TargetOpts.CPU, "", TO,
llvm::Reloc::Model::PIC_);
PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());

Expand Down
21 changes: 14 additions & 7 deletions clang/lib/Interpreter/DeviceOffload.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,24 @@
#include "llvm/Support/VirtualFileSystem.h"

namespace clang {
struct PartialTranslationUnit;
class CompilerInstance;
class CodeGenOptions;
class TargetOptions;

class IncrementalCUDADeviceParser : public IncrementalParser {
const std::list<PartialTranslationUnit> &PTUs;

public:
IncrementalCUDADeviceParser(
Interpreter &Interp, std::unique_ptr<CompilerInstance> Instance,
IncrementalParser &HostParser, llvm::LLVMContext &LLVMCtx,
std::unique_ptr<CompilerInstance> DeviceInstance,
CompilerInstance &HostInstance,
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS,
llvm::Error &Err);
llvm::Error &Err, const std::list<PartialTranslationUnit> &PTUs);

llvm::Expected<PartialTranslationUnit &>
Parse(llvm::StringRef Input) override;
llvm::Expected<TranslationUnitDecl *> Parse(llvm::StringRef Input) override;

// Generate PTX for the last PTU
// Generate PTX for the last PTU.
llvm::Expected<llvm::StringRef> GeneratePTX();

// Generate fatbinary contents in memory
Expand All @@ -39,11 +44,13 @@ class IncrementalCUDADeviceParser : public IncrementalParser {
~IncrementalCUDADeviceParser();

protected:
IncrementalParser &HostParser;
std::unique_ptr<CompilerInstance> DeviceCI;
int SMVersion;
llvm::SmallString<1024> PTXCode;
llvm::SmallVector<char, 1024> FatbinContent;
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
CodeGenOptions &CodeGenOpts; // Intentionally a reference.
const TargetOptions &TargetOpts;
};

} // namespace clang
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Interpreter/IncrementalExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,4 @@ IncrementalExecutor::getSymbolAddress(llvm::StringRef Name,
return SymOrErr->getAddress();
}

} // end namespace clang
} // namespace clang
272 changes: 16 additions & 256 deletions clang/lib/Interpreter/IncrementalParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,246 +13,40 @@
#include "IncrementalParser.h"

#include "clang/AST/DeclContextInternals.h"
#include "clang/CodeGen/BackendUtil.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/FrontendTool/Utils.h"
#include "clang/Interpreter/Interpreter.h"
#include "clang/Interpreter/PartialTranslationUnit.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Sema.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Timer.h"

#include <sstream>

namespace clang {

class IncrementalASTConsumer final : public ASTConsumer {
Interpreter &Interp;
std::unique_ptr<ASTConsumer> Consumer;
// IncrementalParser::IncrementalParser() {}

public:
IncrementalASTConsumer(Interpreter &InterpRef, std::unique_ptr<ASTConsumer> C)
: Interp(InterpRef), Consumer(std::move(C)) {}

bool HandleTopLevelDecl(DeclGroupRef DGR) override final {
if (DGR.isNull())
return true;
if (!Consumer)
return true;

for (Decl *D : DGR)
if (auto *TSD = llvm::dyn_cast<TopLevelStmtDecl>(D);
TSD && TSD->isSemiMissing())
TSD->setStmt(Interp.SynthesizeExpr(cast<Expr>(TSD->getStmt())));

return Consumer->HandleTopLevelDecl(DGR);
}
void HandleTranslationUnit(ASTContext &Ctx) override final {
Consumer->HandleTranslationUnit(Ctx);
}
void HandleInlineFunctionDefinition(FunctionDecl *D) override final {
Consumer->HandleInlineFunctionDefinition(D);
}
void HandleInterestingDecl(DeclGroupRef D) override final {
Consumer->HandleInterestingDecl(D);
}
void HandleTagDeclDefinition(TagDecl *D) override final {
Consumer->HandleTagDeclDefinition(D);
}
void HandleTagDeclRequiredDefinition(const TagDecl *D) override final {
Consumer->HandleTagDeclRequiredDefinition(D);
}
void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override final {
Consumer->HandleCXXImplicitFunctionInstantiation(D);
}
void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override final {
Consumer->HandleTopLevelDeclInObjCContainer(D);
}
void HandleImplicitImportDecl(ImportDecl *D) override final {
Consumer->HandleImplicitImportDecl(D);
}
void CompleteTentativeDefinition(VarDecl *D) override final {
Consumer->CompleteTentativeDefinition(D);
}
void CompleteExternalDeclaration(DeclaratorDecl *D) override final {
Consumer->CompleteExternalDeclaration(D);
}
void AssignInheritanceModel(CXXRecordDecl *RD) override final {
Consumer->AssignInheritanceModel(RD);
}
void HandleCXXStaticMemberVarInstantiation(VarDecl *D) override final {
Consumer->HandleCXXStaticMemberVarInstantiation(D);
}
void HandleVTable(CXXRecordDecl *RD) override final {
Consumer->HandleVTable(RD);
}
ASTMutationListener *GetASTMutationListener() override final {
return Consumer->GetASTMutationListener();
}
ASTDeserializationListener *GetASTDeserializationListener() override final {
return Consumer->GetASTDeserializationListener();
}
void PrintStats() override final { Consumer->PrintStats(); }
bool shouldSkipFunctionBody(Decl *D) override final {
return Consumer->shouldSkipFunctionBody(D);
}
static bool classof(const clang::ASTConsumer *) { return true; }
};

/// A custom action enabling the incremental processing functionality.
///
/// The usual \p FrontendAction expects one call to ExecuteAction and once it
/// sees a call to \p EndSourceFile it deletes some of the important objects
/// such as \p Preprocessor and \p Sema assuming no further input will come.
///
/// \p IncrementalAction ensures it keep its underlying action's objects alive
/// as long as the \p IncrementalParser needs them.
///
class IncrementalAction : public WrapperFrontendAction {
private:
bool IsTerminating = false;

public:
IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx,
llvm::Error &Err)
: WrapperFrontendAction([&]() {
llvm::ErrorAsOutParameter EAO(&Err);
std::unique_ptr<FrontendAction> Act;
switch (CI.getFrontendOpts().ProgramAction) {
default:
Err = llvm::createStringError(
std::errc::state_not_recoverable,
"Driver initialization failed. "
"Incremental mode for action %d is not supported",
CI.getFrontendOpts().ProgramAction);
return Act;
case frontend::ASTDump:
[[fallthrough]];
case frontend::ASTPrint:
[[fallthrough]];
case frontend::ParseSyntaxOnly:
Act = CreateFrontendAction(CI);
break;
case frontend::PluginAction:
[[fallthrough]];
case frontend::EmitAssembly:
[[fallthrough]];
case frontend::EmitBC:
[[fallthrough]];
case frontend::EmitObj:
[[fallthrough]];
case frontend::PrintPreprocessedInput:
[[fallthrough]];
case frontend::EmitLLVMOnly:
Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
break;
}
return Act;
}()) {}
FrontendAction *getWrapped() const { return WrappedAction.get(); }
TranslationUnitKind getTranslationUnitKind() override {
return TU_Incremental;
}

void ExecuteAction() override {
CompilerInstance &CI = getCompilerInstance();
assert(CI.hasPreprocessor() && "No PP!");

// Use a code completion consumer?
CodeCompleteConsumer *CompletionConsumer = nullptr;
if (CI.hasCodeCompletionConsumer())
CompletionConsumer = &CI.getCodeCompletionConsumer();

Preprocessor &PP = CI.getPreprocessor();
PP.EnterMainSourceFile();

if (!CI.hasSema())
CI.createSema(getTranslationUnitKind(), CompletionConsumer);
}

// Do not terminate after processing the input. This allows us to keep various
// clang objects alive and to incrementally grow the current TU.
void EndSourceFile() override {
// The WrappedAction can be nullptr if we issued an error in the ctor.
if (IsTerminating && getWrapped())
WrapperFrontendAction::EndSourceFile();
}

void FinalizeAction() {
assert(!IsTerminating && "Already finalized!");
IsTerminating = true;
EndSourceFile();
}
};

CodeGenerator *IncrementalParser::getCodeGen() const {
FrontendAction *WrappedAct = Act->getWrapped();
if (!WrappedAct->hasIRSupport())
return nullptr;
return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
}

IncrementalParser::IncrementalParser() {}

IncrementalParser::IncrementalParser(Interpreter &Interp,
std::unique_ptr<CompilerInstance> Instance,
llvm::LLVMContext &LLVMCtx,
IncrementalParser::IncrementalParser(CompilerInstance &Instance,
llvm::Error &Err)
: CI(std::move(Instance)) {
: S(Instance.getSema()) {
llvm::ErrorAsOutParameter EAO(&Err);
Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err);
if (Err)
return;
CI->ExecuteAction(*Act);

if (getCodeGen())
CachedInCodeGenModule = GenModule();

std::unique_ptr<ASTConsumer> IncrConsumer =
std::make_unique<IncrementalASTConsumer>(Interp, CI->takeASTConsumer());
CI->setASTConsumer(std::move(IncrConsumer));
Consumer = &CI->getASTConsumer();
P.reset(
new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
Consumer = &S.getASTConsumer();
P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false));
P->Initialize();

// An initial PTU is needed as CUDA includes some headers automatically
auto PTU = ParseOrWrapTopLevelDecl();
if (auto E = PTU.takeError()) {
consumeError(std::move(E)); // FIXME
return; // PTU.takeError();
}

if (getCodeGen()) {
PTU->TheModule = GenModule();
assert(PTU->TheModule && "Failed to create initial PTU");
}
}

IncrementalParser::~IncrementalParser() {
P.reset();
Act->FinalizeAction();
}
IncrementalParser::~IncrementalParser() { P.reset(); }

llvm::Expected<PartialTranslationUnit &>
llvm::Expected<TranslationUnitDecl *>
IncrementalParser::ParseOrWrapTopLevelDecl() {
// Recover resources if we crash before exiting this method.
Sema &S = CI->getSema();
llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
Sema::LocalEagerInstantiationScope LocalInstantiations(S);

PTUs.emplace_back(PartialTranslationUnit());
PartialTranslationUnit &LastPTU = PTUs.back();
// Add a new PTU.
ASTContext &C = S.getASTContext();
C.addTranslationUnitDecl();
LastPTU.TUPart = C.getTranslationUnitDecl();

// Skip previous eof due to last incremental input.
if (P->getCurToken().is(tok::annot_repl_input_end)) {
Expand All @@ -276,11 +70,9 @@ IncrementalParser::ParseOrWrapTopLevelDecl() {
std::error_code());
}

DiagnosticsEngine &Diags = getCI()->getDiagnostics();
DiagnosticsEngine &Diags = S.getDiagnostics();
if (Diags.hasErrorOccurred()) {
PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(),
nullptr};
CleanUpPTU(MostRecentPTU);
CleanUpPTU(C.getTranslationUnitDecl());

Diags.Reset(/*soft=*/true);
Diags.getClient()->clear();
Expand All @@ -299,12 +91,12 @@ IncrementalParser::ParseOrWrapTopLevelDecl() {

Consumer->HandleTranslationUnit(C);

return LastPTU;
return C.getTranslationUnitDecl();
}

llvm::Expected<PartialTranslationUnit &>
llvm::Expected<TranslationUnitDecl *>
IncrementalParser::Parse(llvm::StringRef input) {
Preprocessor &PP = CI->getPreprocessor();
Preprocessor &PP = S.getPreprocessor();
assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");

std::ostringstream SourceName;
Expand All @@ -320,7 +112,7 @@ IncrementalParser::Parse(llvm::StringRef input) {
memcpy(MBStart, input.data(), InputSize);
MBStart[InputSize] = '\n';

SourceManager &SM = CI->getSourceManager();
SourceManager &SM = S.getSourceManager();

// FIXME: Create SourceLocation, which will allow clang to order the overload
// candidates for example
Expand Down Expand Up @@ -356,37 +148,10 @@ IncrementalParser::Parse(llvm::StringRef input) {
"Lexer must be EOF when starting incremental parse!");
}

if (std::unique_ptr<llvm::Module> M = GenModule())
PTU->TheModule = std::move(M);

return PTU;
}

std::unique_ptr<llvm::Module> IncrementalParser::GenModule() {
static unsigned ID = 0;
if (CodeGenerator *CG = getCodeGen()) {
// Clang's CodeGen is designed to work with a single llvm::Module. In many
// cases for convenience various CodeGen parts have a reference to the
// llvm::Module (TheModule or Module) which does not change when a new
// module is pushed. However, the execution engine wants to take ownership
// of the module which does not map well to CodeGen's design. To work this
// around we created an empty module to make CodeGen happy. We should make
// sure it always stays empty.
assert((!CachedInCodeGenModule ||
(CachedInCodeGenModule->empty() &&
CachedInCodeGenModule->global_empty() &&
CachedInCodeGenModule->alias_empty() &&
CachedInCodeGenModule->ifunc_empty())) &&
"CodeGen wrote to a readonly module");
std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());
return M;
}
return nullptr;
}

void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) {
TranslationUnitDecl *MostRecentTU = PTU.TUPart;
void IncrementalParser::CleanUpPTU(TranslationUnitDecl *MostRecentTU) {
if (StoredDeclsMap *Map = MostRecentTU->getPrimaryContext()->getLookupPtr()) {
for (auto &&[Key, List] : *Map) {
DeclContextLookupResult R = List.getLookupResult();
Expand Down Expand Up @@ -415,13 +180,8 @@ void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) {
// Check if we need to clean up the IdResolver chain.
if (ND->getDeclName().getFETokenInfo() && !D->getLangOpts().ObjC &&
!D->getLangOpts().CPlusPlus)
getCI()->getSema().IdResolver.RemoveDecl(ND);
S.IdResolver.RemoveDecl(ND);
}
}

llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const {
CodeGenerator *CG = getCodeGen();
assert(CG);
return CG->GetMangledName(GD);
}
} // end namespace clang
53 changes: 11 additions & 42 deletions clang/lib/Interpreter/IncrementalParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,27 @@
#ifndef LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H
#define LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H

#include "clang/AST/GlobalDecl.h"
#include "clang/Interpreter/PartialTranslationUnit.h"

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"

#include <list>
#include <memory>
namespace llvm {
class LLVMContext;
class Module;
} // namespace llvm

namespace clang {
class ASTConsumer;
class CodeGenerator;
class CompilerInstance;
class IncrementalAction;
class Interpreter;
class Parser;
class Sema;
class TranslationUnitDecl;

/// Provides support for incremental compilation. Keeps track of the state
/// changes between the subsequent incremental input.
///
class IncrementalParser {
protected:
/// Long-lived, incremental parsing action.
std::unique_ptr<IncrementalAction> Act;

/// Compiler instance performing the incremental compilation.
std::unique_ptr<CompilerInstance> CI;
/// The Sema performing the incremental compilation.
Sema &S;

/// Parser.
std::unique_ptr<Parser> P;
Expand All @@ -54,42 +44,21 @@ class IncrementalParser {
/// Counts the number of direct user input lines that have been parsed.
unsigned InputCount = 0;

/// List containing every information about every incrementally parsed piece
/// of code.
std::list<PartialTranslationUnit> PTUs;

/// When CodeGen is created the first llvm::Module gets cached in many places
/// and we must keep it alive.
std::unique_ptr<llvm::Module> CachedInCodeGenModule;

IncrementalParser();
// IncrementalParser();

public:
IncrementalParser(Interpreter &Interp,
std::unique_ptr<CompilerInstance> Instance,
llvm::LLVMContext &LLVMCtx, llvm::Error &Err);
IncrementalParser(CompilerInstance &Instance, llvm::Error &Err);
virtual ~IncrementalParser();

CompilerInstance *getCI() { return CI.get(); }
CodeGenerator *getCodeGen() const;

/// Parses incremental input by creating an in-memory file.
///\returns a \c PartialTranslationUnit which holds information about the
/// \c TranslationUnitDecl and \c llvm::Module corresponding to the input.
virtual llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Input);

/// Uses the CodeGenModule mangled name cache and avoids recomputing.
///\returns the mangled name of a \c GD.
llvm::StringRef GetMangledName(GlobalDecl GD) const;

void CleanUpPTU(PartialTranslationUnit &PTU);

std::list<PartialTranslationUnit> &getPTUs() { return PTUs; }
/// \c TranslationUnitDecl.
virtual llvm::Expected<TranslationUnitDecl *> Parse(llvm::StringRef Input);

std::unique_ptr<llvm::Module> GenModule();
void CleanUpPTU(TranslationUnitDecl *MostRecentTU);

private:
llvm::Expected<PartialTranslationUnit &> ParseOrWrapTopLevelDecl();
llvm::Expected<TranslationUnitDecl *> ParseOrWrapTopLevelDecl();
};
} // end namespace clang

Expand Down
Loading