87 changes: 61 additions & 26 deletions clang/lib/CodeGen/CGExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "EHScopeStack.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
Expand All @@ -25,7 +24,6 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
using namespace clang;
Expand Down Expand Up @@ -560,27 +558,24 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
// For that, we'll need an EH cleanup.
QualType::DestructionKind dtorKind = elementType.isDestructedType();
Address endOfInit = Address::invalid();
CodeGenFunction::CleanupDeactivationScope deactivation(CGF);

if (dtorKind) {
CodeGenFunction::AllocaTrackerRAII allocaTracker(CGF);
EHScopeStack::stable_iterator cleanup;
llvm::Instruction *cleanupDominator = nullptr;
if (CGF.needsEHCleanup(dtorKind)) {
// In principle we could tell the cleanup where we are more
// directly, but the control flow can get so varied here that it
// would actually be quite complex. Therefore we go through an
// alloca.
llvm::Instruction *dominatingIP =
Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(CGF.Int8PtrTy));
endOfInit = CGF.CreateTempAlloca(begin->getType(), CGF.getPointerAlign(),
"arrayinit.endOfInit");
Builder.CreateStore(begin, endOfInit);
cleanupDominator = Builder.CreateStore(begin, endOfInit);
CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
elementAlign,
CGF.getDestroyer(dtorKind));
cast<EHCleanupScope>(*CGF.EHStack.find(CGF.EHStack.stable_begin()))
.AddAuxAllocas(allocaTracker.Take());
cleanup = CGF.EHStack.stable_begin();

CGF.DeferredDeactivationCleanupStack.push_back(
{CGF.EHStack.stable_begin(), dominatingIP});
// Otherwise, remember that we didn't need a cleanup.
} else {
dtorKind = QualType::DK_none;
}

llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
Expand Down Expand Up @@ -676,6 +671,9 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,

CGF.EmitBlock(endBB);
}

// Leave the partial-array cleanup if we entered one.
if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator);
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1376,8 +1374,9 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
LValue SlotLV = CGF.MakeAddrLValue(Slot.getAddress(), E->getType());

// We'll need to enter cleanup scopes in case any of the element
// initializers throws an exception or contains branch out of the expressions.
CodeGenFunction::CleanupDeactivationScope scope(CGF);
// initializers throws an exception.
SmallVector<EHScopeStack::stable_iterator, 16> Cleanups;
llvm::Instruction *CleanupDominator = nullptr;

CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(),
Expand All @@ -1396,12 +1395,28 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
if (QualType::DestructionKind DtorKind =
CurField->getType().isDestructedType()) {
assert(LV.isSimple());
if (DtorKind)
CGF.pushDestroyAndDeferDeactivation(
NormalAndEHCleanup, LV.getAddress(CGF), CurField->getType(),
CGF.getDestroyer(DtorKind), false);
if (CGF.needsEHCleanup(DtorKind)) {
if (!CleanupDominator)
CleanupDominator = CGF.Builder.CreateAlignedLoad(
CGF.Int8Ty,
llvm::Constant::getNullValue(CGF.Int8PtrTy),
CharUnits::One()); // placeholder

CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), CurField->getType(),
CGF.getDestroyer(DtorKind), false);
Cleanups.push_back(CGF.EHStack.stable_begin());
}
}
}

// Deactivate all the partial cleanups in reverse order, which
// generally means popping them.
for (unsigned i = Cleanups.size(); i != 0; --i)
CGF.DeactivateCleanupBlock(Cleanups[i-1], CleanupDominator);

// Destroy the placeholder if we made one.
if (CleanupDominator)
CleanupDominator->eraseFromParent();
}

void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
Expand Down Expand Up @@ -1690,7 +1705,14 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
// We'll need to enter cleanup scopes in case any of the element
// initializers throws an exception.
SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
CodeGenFunction::CleanupDeactivationScope DeactivateCleanups(CGF);
llvm::Instruction *cleanupDominator = nullptr;
auto addCleanup = [&](const EHScopeStack::stable_iterator &cleanup) {
cleanups.push_back(cleanup);
if (!cleanupDominator) // create placeholder once needed
cleanupDominator = CGF.Builder.CreateAlignedLoad(
CGF.Int8Ty, llvm::Constant::getNullValue(CGF.Int8PtrTy),
CharUnits::One());
};

unsigned curInitIndex = 0;

Expand All @@ -1713,8 +1735,10 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
CGF.EmitAggExpr(InitExprs[curInitIndex++], AggSlot);

if (QualType::DestructionKind dtorKind =
Base.getType().isDestructedType())
CGF.pushDestroyAndDeferDeactivation(dtorKind, V, Base.getType());
Base.getType().isDestructedType()) {
CGF.pushDestroy(dtorKind, V, Base.getType());
addCleanup(CGF.EHStack.stable_begin());
}
}
}

Expand Down Expand Up @@ -1789,10 +1813,10 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
if (QualType::DestructionKind dtorKind
= field->getType().isDestructedType()) {
assert(LV.isSimple());
if (dtorKind) {
CGF.pushDestroyAndDeferDeactivation(
NormalAndEHCleanup, LV.getAddress(CGF), field->getType(),
CGF.getDestroyer(dtorKind), false);
if (CGF.needsEHCleanup(dtorKind)) {
CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), field->getType(),
CGF.getDestroyer(dtorKind), false);
addCleanup(CGF.EHStack.stable_begin());
pushedCleanup = true;
}
}
Expand All @@ -1805,6 +1829,17 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
if (GEP->use_empty())
GEP->eraseFromParent();
}

// Deactivate all the partial cleanups in reverse order, which
// generally means popping them.
assert((cleanupDominator || cleanups.empty()) &&
"Missing cleanupDominator before deactivating cleanup blocks");
for (unsigned i = cleanups.size(); i != 0; --i)
CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator);

// Destroy the placeholder if we made one.
if (cleanupDominator)
cleanupDominator->eraseFromParent();
}

void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
Expand Down
38 changes: 19 additions & 19 deletions clang/lib/CodeGen/CGExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1008,8 +1008,8 @@ void CodeGenFunction::EmitNewArrayInitializer(
const Expr *Init = E->getInitializer();
Address EndOfInit = Address::invalid();
QualType::DestructionKind DtorKind = ElementType.isDestructedType();
CleanupDeactivationScope deactivation(*this);
bool pushedCleanup = false;
EHScopeStack::stable_iterator Cleanup;
llvm::Instruction *CleanupDominator = nullptr;

CharUnits ElementSize = getContext().getTypeSizeInChars(ElementType);
CharUnits ElementAlign =
Expand Down Expand Up @@ -1105,24 +1105,19 @@ void CodeGenFunction::EmitNewArrayInitializer(
}

// Enter a partial-destruction Cleanup if necessary.
if (DtorKind) {
AllocaTrackerRAII AllocaTracker(*this);
if (needsEHCleanup(DtorKind)) {
// In principle we could tell the Cleanup where we are more
// directly, but the control flow can get so varied here that it
// would actually be quite complex. Therefore we go through an
// alloca.
llvm::Instruction *DominatingIP =
Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy));
EndOfInit = CreateTempAlloca(BeginPtr.getType(), getPointerAlign(),
"array.init.end");
CleanupDominator =
Builder.CreateStore(BeginPtr.emitRawPointer(*this), EndOfInit);
pushIrregularPartialArrayCleanup(BeginPtr.emitRawPointer(*this),
EndOfInit, ElementType, ElementAlign,
getDestroyer(DtorKind));
cast<EHCleanupScope>(*EHStack.find(EHStack.stable_begin()))
.AddAuxAllocas(AllocaTracker.Take());
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
pushedCleanup = true;
Cleanup = EHStack.stable_begin();
}

CharUnits StartAlign = CurPtr.getAlignment();
Expand Down Expand Up @@ -1169,6 +1164,9 @@ void CodeGenFunction::EmitNewArrayInitializer(
// initialization.
llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements);
if (ConstNum && ConstNum->getZExtValue() <= InitListElements) {
// If there was a Cleanup, deactivate it.
if (CleanupDominator)
DeactivateCleanupBlock(Cleanup, CleanupDominator);
return;
}

Expand Down Expand Up @@ -1283,22 +1281,24 @@ void CodeGenFunction::EmitNewArrayInitializer(
Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit);

// Enter a partial-destruction Cleanup if necessary.
if (!pushedCleanup && needsEHCleanup(DtorKind)) {
llvm::Instruction *DominatingIP =
Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy));
pushRegularPartialArrayCleanup(BeginPtr.emitRawPointer(*this),
CurPtr.emitRawPointer(*this), ElementType,
if (!CleanupDominator && needsEHCleanup(DtorKind)) {
llvm::Value *BeginPtrRaw = BeginPtr.emitRawPointer(*this);
llvm::Value *CurPtrRaw = CurPtr.emitRawPointer(*this);
pushRegularPartialArrayCleanup(BeginPtrRaw, CurPtrRaw, ElementType,
ElementAlign, getDestroyer(DtorKind));
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
Cleanup = EHStack.stable_begin();
CleanupDominator = Builder.CreateUnreachable();
}

// Emit the initializer into this element.
StoreAnyExprIntoOneUnit(*this, Init, Init->getType(), CurPtr,
AggValueSlot::DoesNotOverlap);

// Leave the Cleanup if we entered one.
deactivation.ForceDeactivate();
if (CleanupDominator) {
DeactivateCleanupBlock(Cleanup, CleanupDominator);
CleanupDominator->eraseFromParent();
}

// Advance to the next element by adjusting the pointer type as necessary.
llvm::Value *NextPtr = Builder.CreateConstInBoundsGEP1_32(
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class CGHLSLRuntime {
//===----------------------------------------------------------------------===//

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

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

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

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

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

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

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

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

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

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

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

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

return std::move(Result);
}

Expand Down
6 changes: 0 additions & 6 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)

CodeGenFunction::~CodeGenFunction() {
assert(LifetimeExtendedCleanupStack.empty() && "failed to emit a cleanup");
assert(DeferredDeactivationCleanupStack.empty() &&
"missed to deactivate a cleanup");

if (getLangOpts().OpenMP && CurFn)
CGM.getOpenMPRuntime().functionFinished(*this);
Expand Down Expand Up @@ -348,10 +346,6 @@ static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) {
void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
assert(BreakContinueStack.empty() &&
"mismatched push/pop in break/continue stack!");
assert(LifetimeExtendedCleanupStack.empty() &&
"mismatched push/pop of cleanups in EHStack!");
assert(DeferredDeactivationCleanupStack.empty() &&
"mismatched activate/deactivate of cleanups!");

bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0
&& NumSimpleReturnExprs == NumReturnExprs
Expand Down
96 changes: 2 additions & 94 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
Expand Down Expand Up @@ -671,51 +670,6 @@ class CodeGenFunction : public CodeGenTypeCache {

EHScopeStack EHStack;
llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;

// A stack of cleanups which were added to EHStack but have to be deactivated
// later before being popped or emitted. These are usually deactivated on
// exiting a `CleanupDeactivationScope` scope. For instance, after a
// full-expr.
//
// These are specially useful for correctly emitting cleanups while
// encountering branches out of expression (through stmt-expr or coroutine
// suspensions).
struct DeferredDeactivateCleanup {
EHScopeStack::stable_iterator Cleanup;
llvm::Instruction *DominatingIP;
};
llvm::SmallVector<DeferredDeactivateCleanup> DeferredDeactivationCleanupStack;

// Enters a new scope for capturing cleanups which are deferred to be
// deactivated, all of which will be deactivated once the scope is exited.
struct CleanupDeactivationScope {
CodeGenFunction &CGF;
size_t OldDeactivateCleanupStackSize;
bool Deactivated;
CleanupDeactivationScope(CodeGenFunction &CGF)
: CGF(CGF), OldDeactivateCleanupStackSize(
CGF.DeferredDeactivationCleanupStack.size()),
Deactivated(false) {}

void ForceDeactivate() {
assert(!Deactivated && "Deactivating already deactivated scope");
auto &Stack = CGF.DeferredDeactivationCleanupStack;
for (size_t I = Stack.size(); I > OldDeactivateCleanupStackSize; I--) {
CGF.DeactivateCleanupBlock(Stack[I - 1].Cleanup,
Stack[I - 1].DominatingIP);
Stack[I - 1].DominatingIP->eraseFromParent();
}
Stack.resize(OldDeactivateCleanupStackSize);
Deactivated = true;
}

~CleanupDeactivationScope() {
if (Deactivated)
return;
ForceDeactivate();
}
};

llvm::SmallVector<const JumpDest *, 2> SEHTryEpilogueStack;

llvm::Instruction *CurrentFuncletPad = nullptr;
Expand Down Expand Up @@ -921,19 +875,6 @@ class CodeGenFunction : public CodeGenTypeCache {
new (Buffer + sizeof(Header) + sizeof(T)) RawAddress(ActiveFlag);
}

// Push a cleanup onto EHStack and deactivate it later. It is usually
// deactivated when exiting a `CleanupDeactivationScope` (for example: after a
// full expression).
template <class T, class... As>
void pushCleanupAndDeferDeactivation(CleanupKind Kind, As... A) {
// Placeholder dominating IP for this cleanup.
llvm::Instruction *DominatingIP =
Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
EHStack.pushCleanup<T>(Kind, A...);
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
}

/// Set up the last cleanup that was pushed as a conditional
/// full-expression cleanup.
void initFullExprCleanup() {
Expand Down Expand Up @@ -985,7 +926,6 @@ class CodeGenFunction : public CodeGenTypeCache {
class RunCleanupsScope {
EHScopeStack::stable_iterator CleanupStackDepth, OldCleanupScopeDepth;
size_t LifetimeExtendedCleanupStackSize;
CleanupDeactivationScope DeactivateCleanups;
bool OldDidCallStackSave;
protected:
bool PerformCleanup;
Expand All @@ -1000,7 +940,8 @@ class CodeGenFunction : public CodeGenTypeCache {
public:
/// Enter a new cleanup scope.
explicit RunCleanupsScope(CodeGenFunction &CGF)
: DeactivateCleanups(CGF), PerformCleanup(true), CGF(CGF) {
: PerformCleanup(true), CGF(CGF)
{
CleanupStackDepth = CGF.EHStack.stable_begin();
LifetimeExtendedCleanupStackSize =
CGF.LifetimeExtendedCleanupStack.size();
Expand Down Expand Up @@ -1030,7 +971,6 @@ class CodeGenFunction : public CodeGenTypeCache {
void ForceCleanup(std::initializer_list<llvm::Value**> ValuesToReload = {}) {
assert(PerformCleanup && "Already forced cleanup");
CGF.DidCallStackSave = OldDidCallStackSave;
DeactivateCleanups.ForceDeactivate();
CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize,
ValuesToReload);
PerformCleanup = false;
Expand Down Expand Up @@ -2220,11 +2160,6 @@ class CodeGenFunction : public CodeGenTypeCache {
Address addr, QualType type);
void pushDestroy(CleanupKind kind, Address addr, QualType type,
Destroyer *destroyer, bool useEHCleanupForArray);
void pushDestroyAndDeferDeactivation(QualType::DestructionKind dtorKind,
Address addr, QualType type);
void pushDestroyAndDeferDeactivation(CleanupKind cleanupKind, Address addr,
QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
void pushLifetimeExtendedDestroy(CleanupKind kind, Address addr,
QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
Expand Down Expand Up @@ -2763,33 +2698,6 @@ class CodeGenFunction : public CodeGenTypeCache {
TBAAAccessInfo *TBAAInfo = nullptr);
LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy);

private:
struct AllocaTracker {
void Add(llvm::AllocaInst *I) { Allocas.push_back(I); }
llvm::SmallVector<llvm::AllocaInst *> Take() { return std::move(Allocas); }

private:
llvm::SmallVector<llvm::AllocaInst *> Allocas;
};
AllocaTracker *Allocas = nullptr;

public:
// Captures all the allocas created during the scope of its RAII object.
struct AllocaTrackerRAII {
AllocaTrackerRAII(CodeGenFunction &CGF)
: CGF(CGF), OldTracker(CGF.Allocas) {
CGF.Allocas = &Tracker;
}
~AllocaTrackerRAII() { CGF.Allocas = OldTracker; }

llvm::SmallVector<llvm::AllocaInst *> Take() { return Tracker.Take(); }

private:
CodeGenFunction &CGF;
AllocaTracker *OldTracker;
AllocaTracker Tracker;
};

/// CreateTempAlloca - This creates an alloca and inserts it into the entry
/// block if \p ArraySize is nullptr, otherwise inserts it at the current
/// insertion point of the builder. The caller is responsible for setting an
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3952,8 +3952,20 @@ bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
// behavior may break ABI compatibility of the current unit.
if (const Module *M = F->getOwningModule();
M && M->getTopLevelModule()->isNamedModule() &&
getContext().getCurrentNamedModule() != M->getTopLevelModule())
return false;
getContext().getCurrentNamedModule() != M->getTopLevelModule()) {
// There are practices to mark template member function as always-inline
// and mark the template as extern explicit instantiation but not give
// the definition for member function. So we have to emit the function
// from explicitly instantiation with always-inline.
//
// See https://github.com/llvm/llvm-project/issues/86893 for details.
//
// TODO: Maybe it is better to give it a warning if we call a non-inline
// function from other module units which is marked as always-inline.
if (!F->isTemplateInstantiation() || !F->hasAttr<AlwaysInlineAttr>()) {
return false;
}
}

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

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

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

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

std::optional<std::string> ToolChain::getStdlibPath() const {
Expand Down
46 changes: 38 additions & 8 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,14 @@ static bool addExceptionArgs(const ArgList &Args, types::ID InputType,
bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
false);

bool EHa = Args.hasFlag(options::OPT_fasync_exceptions,
options::OPT_fno_async_exceptions, false);
if (EHa) {
CmdArgs.push_back("-fasync-exceptions");
EH = true;
// Async exceptions are Windows MSVC only.
if (Triple.isWindowsMSVCEnvironment()) {
bool EHa = Args.hasFlag(options::OPT_fasync_exceptions,
options::OPT_fno_async_exceptions, false);
if (EHa) {
CmdArgs.push_back("-fasync-exceptions");
EH = true;
}
}

// Obj-C exceptions are enabled by default, regardless of -fexceptions. This
Expand Down Expand Up @@ -4045,6 +4048,24 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D,
// module fragment.
CmdArgs.push_back("-fskip-odr-check-in-gmf");

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

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

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

// We need to include the case the input file is a module file here.
// Since the default compilation model for C++ module interface unit will
// create temporary module file and compile the temporary module file
Expand Down Expand Up @@ -8084,7 +8105,8 @@ struct EHFlags {
/// The 'a' modifier is unimplemented and fundamentally hard in LLVM IR.
/// - c: Assume that extern "C" functions are implicitly nounwind.
/// The default is /EHs-c-, meaning cleanups are disabled.
static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args,
bool isWindowsMSVC) {
EHFlags EH;

std::vector<std::string> EHArgs =
Expand All @@ -8094,8 +8116,15 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
switch (EHVal[I]) {
case 'a':
EH.Asynch = maybeConsumeDash(EHVal, I);
if (EH.Asynch)
if (EH.Asynch) {
// Async exceptions are Windows MSVC only.
if (!isWindowsMSVC) {
EH.Asynch = false;
D.Diag(clang::diag::warn_drv_unused_argument) << "/EHa" << EHVal;
continue;
}
EH.Synch = false;
}
continue;
case 'c':
EH.NoUnwindC = maybeConsumeDash(EHVal, I);
Expand Down Expand Up @@ -8159,7 +8188,8 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,

const Driver &D = getToolChain().getDriver();

EHFlags EH = parseClangCLEHFlags(D, Args);
bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment();
EHFlags EH = parseClangCLEHFlags(D, Args, IsWindowsMSVC);
if (!isNVPTX && (EH.Synch || EH.Asynch)) {
if (types::isCXX(InputType))
CmdArgs.push_back("-fcxx-exceptions");
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
case llvm::Triple::csky:
case llvm::Triple::loongarch32:
case llvm::Triple::loongarch64:
case llvm::Triple::m68k:
return !clang::driver::tools::areOptimizationsEnabled(Args);
default:
break;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,13 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
if (Consumers.empty())
return nullptr;

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

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

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

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

if (LangOpts.Char8)
Builder.defineMacro("__cpp_char8_t", "202207L");
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Index/USRGeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,13 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
Out << '>';
}

QualType CanonicalType = D->getType().getCanonicalType();
// Mangle in type information for the arguments.
for (auto *PD : D->parameters()) {
Out << '#';
VisitType(PD->getType());
if (const auto *FPT = CanonicalType->getAs<FunctionProtoType>()) {
for (QualType PT : FPT->param_types()) {
Out << '#';
VisitType(PT);
}
}
if (D->isVariadic())
Out << '.';
Expand Down
46 changes: 45 additions & 1 deletion clang/lib/Parse/ParseCXXInlineMethods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,49 @@

using namespace clang;

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

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

BT.consumeClose();
return Message;
}

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

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

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

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

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

if (getLangOpts().OpenMP)
Actions.startOpenMPCXXRangeFor();
Actions.OpenMP().startOpenMPCXXRangeFor();
if (Tok.is(tok::l_brace))
FRI->RangeExpr = ParseBraceInitializer();
else
Expand Down Expand Up @@ -2664,7 +2662,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
}
}

Sema::CUDATargetContextRAII X(Actions, Sema::CTCK_InitGlobalVar, ThisDecl);
SemaCUDA::CUDATargetContextRAII X(Actions.CUDA(),
SemaCUDA::CTCK_InitGlobalVar, ThisDecl);
switch (TheInitKind) {
// Parse declarator '=' initializer.
case InitKind::Equal: {
Expand All @@ -2676,6 +2675,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
<< 1 /* delete */;
else
Diag(ConsumeToken(), diag::err_deleted_non_function);
SkipDeletedFunctionBody();
} else if (Tok.is(tok::kw_default)) {
if (D.isFunctionDeclarator())
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3397,6 +3397,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
<< 1 /* delete */;
else
Diag(ConsumeToken(), diag::err_deleted_non_function);
SkipDeletedFunctionBody();
return ExprError();
}
} else if (Tok.is(tok::kw_default)) {
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -2074,7 +2076,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// replace this call to ActOnOpenACCArraySectionExpr in the future.
// Eventually we'll genericize the OPenMPArraySectionExpr type as
// well.
LHS = Actions.ActOnOMPArraySectionExpr(
LHS = Actions.OpenMP().ActOnOMPArraySectionExpr(
LHS.get(), Loc, ArgExprs.empty() ? nullptr : ArgExprs[0],
ColonLocFirst, ColonLocSecond, Length.get(), Stride.get(), RLoc);
} else {
Expand Down Expand Up @@ -2129,10 +2131,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
}

if (!LHS.isInvalid()) {
ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(),
OpenLoc,
ExecConfigExprs,
CloseLoc);
ExprResult ECResult = Actions.CUDA().ActOnExecConfigExpr(
getCurScope(), OpenLoc, ExecConfigExprs, CloseLoc);
if (ECResult.isInvalid())
LHS = ExprError();
else
Expand Down Expand Up @@ -3278,7 +3278,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
if (ErrorFound) {
Result = ExprError();
} else if (!Result.isInvalid()) {
Result = Actions.ActOnOMPArrayShapingExpr(
Result = Actions.OpenMP().ActOnOMPArrayShapingExpr(
Result.get(), OpenLoc, RParenLoc, OMPDimensions, OMPBracketsRanges);
}
return Result;
Expand Down
16 changes: 11 additions & 5 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -835,19 +835,23 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
case OpenACCClauseKind::Default: {
Token DefKindTok = getCurToken();

if (expectIdentifierOrKeyword(*this))
break;
if (expectIdentifierOrKeyword(*this)) {
Parens.skipToEnd();
return OpenACCCanContinue();
}

ConsumeToken();

OpenACCDefaultClauseKind DefKind =
getOpenACCDefaultClauseKind(DefKindTok);

if (DefKind == OpenACCDefaultClauseKind::Invalid)
if (DefKind == OpenACCDefaultClauseKind::Invalid) {
Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
else
ParsedClause.setDefaultDetails(DefKind);
Parens.skipToEnd();
return OpenACCCanContinue();
}

ParsedClause.setDefaultDetails(DefKind);
break;
}
case OpenACCClauseKind::If: {
Expand Down Expand Up @@ -977,6 +981,8 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
case OpenACCClauseKind::Self: {
assert(DirKind != OpenACCDirectiveKind::Update);
ExprResult CondExpr = ParseOpenACCConditionExpr();
ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()
: nullptr);

if (CondExpr.isInvalid()) {
Parens.skipToEnd();
Expand Down
240 changes: 128 additions & 112 deletions clang/lib/Parse/ParseOpenMP.cpp

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions clang/lib/Parse/ParsePragma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaCUDA.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSwitch.h"
#include <optional>
Expand Down Expand Up @@ -3900,8 +3901,8 @@ void PragmaForceCUDAHostDeviceHandler::HandlePragma(
}

if (Info->isStr("begin"))
Actions.PushForceCUDAHostDevice();
else if (!Actions.PopForceCUDAHostDevice())
Actions.CUDA().PushForceHostDevice();
else if (!Actions.CUDA().PopForceHostDevice())
PP.Diag(FirstTok.getLocation(),
diag::err_pragma_cannot_end_force_cuda_host_device);

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/STLExtras.h"
#include <optional>
Expand Down Expand Up @@ -2301,7 +2302,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// In OpenMP loop region loop control variable must be captured and be
// private. Perform analysis of first part (if any).
if (getLangOpts().OpenMP && FirstPart.isUsable()) {
Actions.ActOnOpenMPLoopInitialization(ForLoc, FirstPart.get());
Actions.OpenMP().ActOnOpenMPLoopInitialization(ForLoc, FirstPart.get());
}
}

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1404,6 +1404,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,

// Parse function body eagerly if it is either '= delete;' or '= default;' as
// ActOnStartOfFunctionDef needs to know whether the function is deleted.
StringLiteral *DeletedMessage = nullptr;
Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other;
SourceLocation KWLoc;
if (TryConsumeToken(tok::equal)) {
Expand All @@ -1415,6 +1416,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
: diag::ext_defaulted_deleted_function)
<< 1 /* deleted */;
BodyKind = Sema::FnBodyKind::Delete;
DeletedMessage = ParseCXXDeletedFunctionMessage();
} else if (TryConsumeToken(tok::kw_default, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_defaulted_deleted_function
Expand Down Expand Up @@ -1473,7 +1475,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
D.getMutableDeclSpec().abort();

if (BodyKind != Sema::FnBodyKind::Other) {
Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind);
Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind, DeletedMessage);
Stmt *GeneratedBody = Res ? Res->getBody() : nullptr;
Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false);
return Res;
Expand Down
43 changes: 24 additions & 19 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@
#include "clang/Sema/RISCVIntrinsicManager.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaConsumer.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaOpenACC.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
Expand Down Expand Up @@ -199,8 +201,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr),
OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr),
CurScope(nullptr), Ident_super(nullptr),
CUDAPtr(std::make_unique<SemaCUDA>(*this)),
HLSLPtr(std::make_unique<SemaHLSL>(*this)),
OpenACCPtr(std::make_unique<SemaOpenACC>(*this)),
OpenMPPtr(std::make_unique<SemaOpenMP>(*this)),
SYCLPtr(std::make_unique<SemaSYCL>(*this)),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
Expand All @@ -224,8 +228,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
StringWithUTF8StringMethod(nullptr),
ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr),
ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr),
DictionaryWithObjectsMethod(nullptr), CodeCompleter(CodeCompleter),
VarDataSharingAttributesStack(nullptr) {
DictionaryWithObjectsMethod(nullptr), CodeCompleter(CodeCompleter) {
assert(pp.TUKind == TUKind);
TUScope = nullptr;

Expand All @@ -250,7 +253,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
nullptr, ExpressionEvaluationContextRecord::EK_Other);

// Initialization of data sharing attributes stack for OpenMP
InitDataSharingAttributesStack();
OpenMP().InitDataSharingAttributesStack();

std::unique_ptr<sema::SemaPPCallbacks> Callbacks =
std::make_unique<sema::SemaPPCallbacks>();
Expand Down Expand Up @@ -499,7 +502,7 @@ Sema::~Sema() {
threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache);

// Destroys data sharing attributes stack for OpenMP
DestroyDataSharingAttributesStack();
OpenMP().DestroyDataSharingAttributesStack();

// Detach from the PP callback handler which outlives Sema since it's owned
// by the preprocessor.
Expand Down Expand Up @@ -1157,7 +1160,7 @@ void Sema::ActOnEndOfTranslationUnit() {

DiagnoseUnterminatedPragmaAlignPack();
DiagnoseUnterminatedPragmaAttribute();
DiagnoseUnterminatedOpenMPDeclareTarget();
OpenMP().DiagnoseUnterminatedOpenMPDeclareTarget();

// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
Expand Down Expand Up @@ -1635,15 +1638,15 @@ bool Sema::hasUncompilableErrorOccurred() const {
// Print notes showing how we can reach FD starting from an a priori
// known-callable function.
static void emitCallStackNotes(Sema &S, const FunctionDecl *FD) {
auto FnIt = S.DeviceKnownEmittedFns.find(FD);
while (FnIt != S.DeviceKnownEmittedFns.end()) {
auto FnIt = S.CUDA().DeviceKnownEmittedFns.find(FD);
while (FnIt != S.CUDA().DeviceKnownEmittedFns.end()) {
// Respect error limit.
if (S.Diags.hasFatalErrorOccurred())
return;
DiagnosticBuilder Builder(
S.Diags.Report(FnIt->second.Loc, diag::note_called_by));
Builder << FnIt->second.FD;
FnIt = S.DeviceKnownEmittedFns.find(FnIt->second.FD);
FnIt = S.CUDA().DeviceKnownEmittedFns.find(FnIt->second.FD);
}
}

Expand Down Expand Up @@ -1745,9 +1748,9 @@ class DeferredDiagnosticsEmitter
// Finalize analysis of OpenMP-specific constructs.
if (Caller && S.LangOpts.OpenMP && UsePath.size() == 1 &&
(ShouldEmitRootNode || InOMPDeviceContext))
S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc);
S.OpenMP().finalizeOpenMPDelayedAnalysis(Caller, FD, Loc);
if (Caller)
S.DeviceKnownEmittedFns[FD] = {Caller, Loc};
S.CUDA().DeviceKnownEmittedFns[FD] = {Caller, Loc};
// Always emit deferred diagnostics for the direct users. This does not
// lead to explosion of diagnostics since each user is visited at most
// twice.
Expand Down Expand Up @@ -1836,8 +1839,8 @@ void Sema::emitDeferredDiags() {
// which other not-known-emitted functions.
//
// When we see something which is illegal if the current function is emitted
// (usually by way of CUDADiagIfDeviceCode, CUDADiagIfHostCode, or
// CheckCUDACall), we first check if the current function is known-emitted. If
// (usually by way of DiagIfDeviceCode, DiagIfHostCode, or
// CheckCall), we first check if the current function is known-emitted. If
// so, we immediately output the diagnostic.
//
// Otherwise, we "defer" the diagnostic. It sits in Sema::DeviceDeferredDiags
Expand Down Expand Up @@ -1897,11 +1900,11 @@ Sema::targetDiag(SourceLocation Loc, unsigned DiagID, const FunctionDecl *FD) {
FD = FD ? FD : getCurFunctionDecl();
if (LangOpts.OpenMP)
return LangOpts.OpenMPIsTargetDevice
? diagIfOpenMPDeviceCode(Loc, DiagID, FD)
: diagIfOpenMPHostCode(Loc, DiagID, FD);
? OpenMP().diagIfOpenMPDeviceCode(Loc, DiagID, FD)
: OpenMP().diagIfOpenMPHostCode(Loc, DiagID, FD);
if (getLangOpts().CUDA)
return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
return getLangOpts().CUDAIsDevice ? CUDA().DiagIfDeviceCode(Loc, DiagID)
: CUDA().DiagIfHostCode(Loc, DiagID);

if (getLangOpts().SYCLIsDevice)
return SYCL().DiagIfDeviceCode(Loc, DiagID);
Expand Down Expand Up @@ -2129,7 +2132,7 @@ void Sema::PushFunctionScope() {
FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics()));
}
if (LangOpts.OpenMP)
pushOpenMPFunctionRegion();
OpenMP().pushOpenMPFunctionRegion();
}

void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
Expand Down Expand Up @@ -2249,7 +2252,7 @@ Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
PoppedFunctionScopeDeleter(this));

if (LangOpts.OpenMP)
popOpenMPFunctionRegion(Scope.get());
OpenMP().popOpenMPFunctionRegion(Scope.get());

// Issue any analysis-based warnings.
if (WP && D)
Expand Down Expand Up @@ -2685,7 +2688,9 @@ void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD,
unsigned OpenMPCaptureLevel) {
auto *CSI = new CapturedRegionScopeInfo(
getDiagnostics(), S, CD, RD, CD->getContextParam(), K,
(getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0,
(getLangOpts().OpenMP && K == CR_OpenMP)
? OpenMP().getOpenMPNestingLevel()
: 0,
OpenMPCaptureLevel);
CSI->ReturnType = Context.VoidTy;
FunctionScopes.push_back(CSI);
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/SemaBase.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "clang/Sema/SemaBase.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaCUDA.h"

namespace clang {

Expand Down Expand Up @@ -70,8 +71,8 @@ Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, unsigned DiagID,
}

SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice
? SemaRef.CUDADiagIfDeviceCode(Loc, DiagID)
: SemaRef.CUDADiagIfHostCode(Loc, DiagID);
? SemaRef.CUDA().DiagIfDeviceCode(Loc, DiagID)
: SemaRef.CUDA().DiagIfHostCode(Loc, DiagID);
SetIsLastErrorImmediate(DB.isImmediate());
return DB;
}
Expand Down
277 changes: 143 additions & 134 deletions clang/lib/Sema/SemaCUDA.cpp

Large diffs are not rendered by default.

20 changes: 16 additions & 4 deletions clang/lib/Sema/SemaCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,22 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
howManyCandidates = OCD_AmbiguousCandidates;
break;

case OR_Deleted:
msg = diag::err_ovl_deleted_conversion_in_cast;
howManyCandidates = OCD_ViableCandidates;
break;
case OR_Deleted: {
OverloadCandidateSet::iterator Best;
[[maybe_unused]] OverloadingResult Res =
candidates.BestViableFunction(S, range.getBegin(), Best);
assert(Res == OR_Deleted && "Inconsistent overload resolution");

StringLiteral *Msg = Best->Function->getDeletedMessage();
candidates.NoteCandidates(
PartialDiagnosticAt(range.getBegin(),
S.PDiag(diag::err_ovl_deleted_conversion_in_cast)
<< CT << srcType << destType << (Msg != nullptr)
<< (Msg ? Msg->getString() : StringRef())
<< range << src->getSourceRange()),
S, OCD_ViableCandidates, src);
return true;
}
}

candidates.NoteCandidates(
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19721,6 +19721,27 @@ bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const {
return isLayoutCompatible(getASTContext(), T1, T2);
}

//===-------------- Pointer interconvertibility ----------------------------//

bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base,
const TypeSourceInfo *Derived) {
QualType BaseT = Base->getType()->getCanonicalTypeUnqualified();
QualType DerivedT = Derived->getType()->getCanonicalTypeUnqualified();

if (BaseT->isStructureOrClassType() && DerivedT->isStructureOrClassType() &&
getASTContext().hasSameType(BaseT, DerivedT))
return true;

if (!IsDerivedFrom(Derived->getTypeLoc().getBeginLoc(), DerivedT, BaseT))
return false;

// Per [basic.compound]/4.3, containing object has to be standard-layout.
if (DerivedT->getAsCXXRecordDecl()->isStandardLayout())
return true;

return false;
}

//===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----//

/// Given a type tag expression find the type tag itself.
Expand Down
91 changes: 50 additions & 41 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/SmallString.h"
Expand Down Expand Up @@ -6167,11 +6169,12 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
// Check if we are in an `omp begin/end declare variant` scope. Handle this
// declaration only if the `bind_to_declaration` extension is set.
SmallVector<FunctionDecl *, 4> Bases;
if (LangOpts.OpenMP && isInOpenMPDeclareVariantScope())
if (getOMPTraitInfoForSurroundingScope()->isExtensionActive(llvm::omp::TraitProperty::
implementation_extension_bind_to_declaration))
ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
S, D, MultiTemplateParamsArg(), Bases);
if (LangOpts.OpenMP && OpenMP().isInOpenMPDeclareVariantScope())
if (OpenMP().getOMPTraitInfoForSurroundingScope()->isExtensionActive(
llvm::omp::TraitProperty::
implementation_extension_bind_to_declaration))
OpenMP().ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
S, D, MultiTemplateParamsArg(), Bases);

Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg());

Expand All @@ -6180,7 +6183,8 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
Dcl->setTopLevelDeclInObjCContainer();

if (!Bases.empty())
ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl, Bases);
OpenMP().ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl,
Bases);

return Dcl;
}
Expand Down Expand Up @@ -6567,8 +6571,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (New->getDeclName() && AddToScope)
PushOnScopeChains(New, S);

if (isInOpenMPDeclareTargetContext())
checkDeclIsAllowedInOpenMPTarget(nullptr, New);
if (OpenMP().isInOpenMPDeclareTargetContext())
OpenMP().checkDeclIsAllowedInOpenMPTarget(nullptr, New);

return New;
}
Expand Down Expand Up @@ -10595,12 +10599,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,

// We do not add HD attributes to specializations here because
// they may have different constexpr-ness compared to their
// templates and, after maybeAddCUDAHostDeviceAttrs() is applied,
// templates and, after maybeAddHostDeviceAttrs() is applied,
// may end up with different effective targets. Instead, a
// specialization inherits its target attributes from its template
// in the CheckFunctionTemplateSpecialization() call below.
if (getLangOpts().CUDA && !isFunctionTemplateSpecialization)
maybeAddCUDAHostDeviceAttrs(NewFD, Previous);
CUDA().maybeAddHostDeviceAttrs(NewFD, Previous);

// Handle explict specializations of function templates
// and friend function declarations with an explicit
Expand Down Expand Up @@ -10898,12 +10902,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,

if (getLangOpts().CUDA) {
IdentifierInfo *II = NewFD->getIdentifier();
if (II && II->isStr(getCudaConfigureFuncName()) &&
if (II && II->isStr(CUDA().getConfigureFuncName()) &&
!NewFD->isInvalidDecl() &&
NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
if (!R->castAs<FunctionType>()->getReturnType()->isScalarType())
Diag(NewFD->getLocation(), diag::err_config_scalar_return)
<< getCudaConfigureFuncName();
<< CUDA().getConfigureFuncName();
Context.setcudaConfigureCallDecl(NewFD);
}

Expand Down Expand Up @@ -12267,7 +12271,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}

if (LangOpts.OpenMP)
ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(NewFD);
OpenMP().ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(NewFD);

// Semantic checking for this function declaration (in isolation).

Expand Down Expand Up @@ -12398,7 +12402,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}

if (!Redeclaration && LangOpts.CUDA)
checkCUDATargetOverload(NewFD, Previous);
CUDA().checkTargetOverload(NewFD, Previous);
}

// Check if the function definition uses any AArch64 SME features without
Expand Down Expand Up @@ -12667,7 +12671,7 @@ void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) {
}
}

bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
bool Sema::CheckForConstantInitializer(Expr *Init, unsigned DiagID) {
// FIXME: Need strict checking. In C89, we need to check for
// any assignment, increment, decrement, function-calls, or
// commas outside of a sizeof. In C99, it's the same list,
Expand All @@ -12685,8 +12689,7 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
const Expr *Culprit;
if (Init->isConstantInitializer(Context, false, &Culprit))
return false;
Diag(Culprit->getExprLoc(), diag::err_init_element_not_constant)
<< Culprit->getSourceRange();
Diag(Culprit->getExprLoc(), DiagID) << Culprit->getSourceRange();
return true;
}

Expand Down Expand Up @@ -13804,29 +13807,24 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// OpenCL v1.2 s6.5.3: __constant locals must be constant-initialized.
// This is true even in C++ for OpenCL.
} else if (VDecl->getType().getAddressSpace() == LangAS::opencl_constant) {
CheckForConstantInitializer(Init, DclT);
CheckForConstantInitializer(Init);

// Otherwise, C++ does not restrict the initializer.
// Otherwise, C++ does not restrict the initializer.
} else if (getLangOpts().CPlusPlus) {
// do nothing

// C99 6.7.8p4: All the expressions in an initializer for an object that has
// static storage duration shall be constant expressions or string literals.
} else if (VDecl->getStorageClass() == SC_Static) {
CheckForConstantInitializer(Init, DclT);
CheckForConstantInitializer(Init);

// C89 is stricter than C99 for aggregate initializers.
// C89 6.5.7p3: All the expressions [...] in an initializer list
// for an object that has aggregate or union type shall be
// constant expressions.
// C89 is stricter than C99 for aggregate initializers.
// C89 6.5.7p3: All the expressions [...] in an initializer list
// for an object that has aggregate or union type shall be
// constant expressions.
} else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() &&
isa<InitListExpr>(Init)) {
const Expr *Culprit;
if (!Init->isConstantInitializer(Context, false, &Culprit)) {
Diag(Culprit->getExprLoc(),
diag::ext_aggregate_init_not_constant)
<< Culprit->getSourceRange();
}
CheckForConstantInitializer(Init, diag::ext_aggregate_init_not_constant);
}

if (auto *E = dyn_cast<ExprWithCleanups>(Init))
Expand Down Expand Up @@ -13959,7 +13957,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// Avoid duplicate diagnostics for constexpr variables.
if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl() &&
!VDecl->isConstexpr())
CheckForConstantInitializer(Init, DclT);
CheckForConstantInitializer(Init);
}

QualType InitType = Init->getType();
Expand Down Expand Up @@ -14415,7 +14413,7 @@ StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isInvalidDecl()) return;

MaybeAddCUDAConstantAttr(var);
CUDA().MaybeAddConstantAttr(var);

if (getLangOpts().OpenCL) {
// OpenCL v2.0 s6.12.5 - Every block variable declaration must have an
Expand Down Expand Up @@ -14829,7 +14827,7 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
// variables whether they are local or not. CUDA also allows
// constant initializers for __constant__ and __device__ variables.
if (getLangOpts().CUDA)
checkAllowedCUDAInitializer(VD);
CUDA().checkAllowedInitializer(VD);

// Grab the dllimport or dllexport attribute off of the VarDecl.
const InheritableAttr *DLLAttr = getDLLAttr(VD);
Expand Down Expand Up @@ -14955,7 +14953,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (auto *VD = dyn_cast<VarDecl>(D);
LangOpts.OpenMP && VD && VD->hasAttr<OMPDeclareTargetDeclAttr>() &&
VD->hasGlobalStorage())
ActOnOpenMPDeclareTargetInitializer(D);
OpenMP().ActOnOpenMPDeclareTargetInitializer(D);
// For declarators, there are some additional syntactic-ish checks we need
// to perform.
if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
Expand Down Expand Up @@ -15494,16 +15492,17 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D,
// specialization function under the OpenMP context defined as part of the
// `omp begin declare variant`.
SmallVector<FunctionDecl *, 4> Bases;
if (LangOpts.OpenMP && isInOpenMPDeclareVariantScope())
ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
if (LangOpts.OpenMP && OpenMP().isInOpenMPDeclareVariantScope())
OpenMP().ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
ParentScope, D, TemplateParameterLists, Bases);

D.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists);
Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody, BodyKind);

if (!Bases.empty())
ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl, Bases);
OpenMP().ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl,
Bases);

return Dcl;
}
Expand Down Expand Up @@ -16082,7 +16081,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// This is meant to pop the context added in ActOnStartOfFunctionDef().
ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD));
if (FD) {
FD->setBody(Body);
// If this is called by Parser::ParseFunctionDefinition() after marking
// the declaration as deleted, and if the deleted-function-body contains
// a message (C++26), then a DefaultedOrDeletedInfo will have already been
// added to store that message; do not overwrite it in that case.
//
// Since this would always set the body to 'nullptr' in that case anyway,
// which is already done when the function decl is initially created,
// always skipping this irrespective of whether there is a delete message
// should not be a problem.
if (!FD->isDeletedAsWritten())
FD->setBody(Body);
FD->setWillHaveBody(false);
CheckImmediateEscalatingFunctionDefinition(FD, FSI);

Expand Down Expand Up @@ -20640,7 +20649,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(const FunctionDecl *FD,
return FunctionEmissionStatus::OMPDiscarded;
// If we have an explicit value for the device type, or we are in a target
// declare context, we need to emit all extern and used symbols.
if (isInOpenMPDeclareTargetContext() || DevTy)
if (OpenMP().isInOpenMPDeclareTargetContext() || DevTy)
if (IsEmittedForExternalSymbol())
return FunctionEmissionStatus::Emitted;
// Device mode only emits what it must, if it wasn't tagged yet and needed,
Expand All @@ -20666,7 +20675,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(const FunctionDecl *FD,
// when compiling for host, device and global functions are never emitted.
// (Technically, we do emit a host-side stub for global functions, but this
// doesn't count for our purposes here.)
CUDAFunctionTarget T = IdentifyCUDATarget(FD);
CUDAFunctionTarget T = CUDA().IdentifyTarget(FD);
if (LangOpts.CUDAIsDevice && T == CUDAFunctionTarget::Host)
return FunctionEmissionStatus::CUDADiscarded;
if (!LangOpts.CUDAIsDevice &&
Expand All @@ -20691,5 +20700,5 @@ bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) {
// for host, only HD functions actually called from the host get marked as
// known-emitted.
return LangOpts.CUDA && !LangOpts.CUDAIsDevice &&
IdentifyCUDATarget(Callee) == CUDAFunctionTarget::Global;
CUDA().IdentifyTarget(Callee) == CUDAFunctionTarget::Global;
}
12 changes: 7 additions & 5 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "clang/Sema/ParsedAttr.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/STLExtras.h"
Expand Down Expand Up @@ -5099,8 +5100,8 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
if (S.getLangOpts().CUDA && VD->hasLocalStorage() &&
S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
<< llvm::to_underlying(S.CurrentCUDATarget()))
S.CUDA().DiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
<< llvm::to_underlying(S.CUDA().CurrentTarget()))
return;
D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL));
}
Expand Down Expand Up @@ -5189,8 +5190,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Diagnostic is emitted elsewhere: here we store the (valid) AL
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
CallingConv CC;
if (S.CheckCallingConvAttr(AL, CC, /*FD*/ nullptr,
S.IdentifyCUDATarget(dyn_cast<FunctionDecl>(D))))
if (S.CheckCallingConvAttr(
AL, CC, /*FD*/ nullptr,
S.CUDA().IdentifyTarget(dyn_cast<FunctionDecl>(D))))
return;

if (!isa<ObjCMethodDecl>(D)) {
Expand Down Expand Up @@ -5495,7 +5497,7 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
if (LangOpts.CUDA) {
auto *Aux = Context.getAuxTargetInfo();
assert(FD || CFT != CUDAFunctionTarget::InvalidTarget);
auto CudaTarget = FD ? IdentifyCUDATarget(FD) : CFT;
auto CudaTarget = FD ? CUDA().IdentifyTarget(FD) : CFT;
bool CheckHost = false, CheckDevice = false;
switch (CudaTarget) {
case CUDAFunctionTarget::HostDevice:
Expand Down
48 changes: 26 additions & 22 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
Expand Down Expand Up @@ -961,8 +963,8 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
CurContext->addHiddenDecl(New);
}

if (isInOpenMPDeclareTargetContext())
checkDeclIsAllowedInOpenMPTarget(nullptr, New);
if (OpenMP().isInOpenMPDeclareTargetContext())
OpenMP().checkDeclIsAllowedInOpenMPTarget(nullptr, New);

return New;
}
Expand Down Expand Up @@ -7981,7 +7983,7 @@ class DefaultedComparisonVisitor {
DefaultedComparisonVisitor(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD,
DefaultedComparisonKind DCK)
: S(S), RD(RD), FD(FD), DCK(DCK) {
if (auto *Info = FD->getDefaultedFunctionInfo()) {
if (auto *Info = FD->getDefalutedOrDeletedInfo()) {
// FIXME: Change CreateOverloadedBinOp to take an ArrayRef instead of an
// UnresolvedSet to avoid this copy.
Fns.assign(Info->getUnqualifiedLookups().begin(),
Expand Down Expand Up @@ -8849,8 +8851,9 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
UnresolvedSet<32> Operators;
lookupOperatorsForDefaultedComparison(*this, S, Operators,
FD->getOverloadedOperator());
FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create(
Context, Operators.pairs()));
FD->setDefaultedOrDeletedInfo(
FunctionDecl::DefaultedOrDeletedFunctionInfo::Create(
Context, Operators.pairs()));
}

// C++2a [class.compare.default]p1:
Expand Down Expand Up @@ -9876,15 +9879,15 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD,
// failed.
// For inherited constructors (non-null ICI), CSM may be passed so that MD
// is treated as certain special member, which may not reflect what special
// member MD really is. However inferCUDATargetForImplicitSpecialMember
// member MD really is. However inferTargetForImplicitSpecialMember
// expects CSM to match MD, therefore recalculate CSM.
assert(ICI || CSM == getSpecialMember(MD));
auto RealCSM = CSM;
if (ICI)
RealCSM = getSpecialMember(MD);

return inferCUDATargetForImplicitSpecialMember(RD, RealCSM, MD,
SMI.ConstArg, Diagnose);
return CUDA().inferTargetForImplicitSpecialMember(RD, RealCSM, MD,
SMI.ConstArg, Diagnose);
}

return false;
Expand Down Expand Up @@ -14055,7 +14058,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, std::nullopt);

if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(
CUDA().inferTargetForImplicitSpecialMember(
ClassDecl, CXXSpecialMemberKind::DefaultConstructor, DefaultCon,
/* ConstRHS */ false,
/* Diagnose */ false);
Expand Down Expand Up @@ -14341,7 +14344,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
setupImplicitSpecialMemberType(Destructor, Context.VoidTy, std::nullopt);

if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(
CUDA().inferTargetForImplicitSpecialMember(
ClassDecl, CXXSpecialMemberKind::Destructor, Destructor,
/* ConstRHS */ false,
/* Diagnose */ false);
Expand Down Expand Up @@ -14983,7 +14986,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
setupImplicitSpecialMemberType(CopyAssignment, RetType, ArgType);

if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(
CUDA().inferTargetForImplicitSpecialMember(
ClassDecl, CXXSpecialMemberKind::CopyAssignment, CopyAssignment,
/* ConstRHS */ Const,
/* Diagnose */ false);
Expand Down Expand Up @@ -15335,7 +15338,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
setupImplicitSpecialMemberType(MoveAssignment, RetType, ArgType);

if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(
CUDA().inferTargetForImplicitSpecialMember(
ClassDecl, CXXSpecialMemberKind::MoveAssignment, MoveAssignment,
/* ConstRHS */ false,
/* Diagnose */ false);
Expand Down Expand Up @@ -15733,7 +15736,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
setupImplicitSpecialMemberType(CopyConstructor, Context.VoidTy, ArgType);

if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(
CUDA().inferTargetForImplicitSpecialMember(
ClassDecl, CXXSpecialMemberKind::CopyConstructor, CopyConstructor,
/* ConstRHS */ Const,
/* Diagnose */ false);
Expand Down Expand Up @@ -15878,7 +15881,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
setupImplicitSpecialMemberType(MoveConstructor, Context.VoidTy, ArgType);

if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(
CUDA().inferTargetForImplicitSpecialMember(
ClassDecl, CXXSpecialMemberKind::MoveConstructor, MoveConstructor,
/* ConstRHS */ false,
/* Diagnose */ false);
Expand Down Expand Up @@ -16184,7 +16187,7 @@ ExprResult Sema::BuildCXXConstructExpr(
DeclInitType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) &&
"given constructor for wrong type");
MarkFunctionReferenced(ConstructLoc, Constructor);
if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor))
if (getLangOpts().CUDA && !CUDA().CheckCall(ConstructLoc, Constructor))
return ExprError();

return CheckForImmediateInvocation(
Expand Down Expand Up @@ -18158,7 +18161,8 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
return ND;
}

void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc,
StringLiteral *Message) {
AdjustDeclIfTemplate(Dcl);

FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(Dcl);
Expand Down Expand Up @@ -18207,7 +18211,7 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
// C++11 [dcl.fct.def.delete]p4:
// A deleted function is implicitly inline.
Fn->setImplicitlyInline();
Fn->setDeletedAsWritten();
Fn->setDeletedAsWritten(true, Message);
}

void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
Expand Down Expand Up @@ -18320,11 +18324,11 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
}
}

void Sema::SetFunctionBodyKind(Decl *D, SourceLocation Loc,
FnBodyKind BodyKind) {
void Sema::SetFunctionBodyKind(Decl *D, SourceLocation Loc, FnBodyKind BodyKind,
StringLiteral *DeletedMessage) {
switch (BodyKind) {
case FnBodyKind::Delete:
SetDeclDeleted(D, Loc);
SetDeclDeleted(D, Loc, DeletedMessage);
break;
case FnBodyKind::Default:
SetDeclDefaulted(D, Loc);
Expand Down Expand Up @@ -18651,8 +18655,8 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
// Do not mark as used if compiling for the device outside of the target
// region.
if (TUKind != TU_Prefix && LangOpts.OpenMP && LangOpts.OpenMPIsTargetDevice &&
!isInOpenMPDeclareTargetContext() &&
!isInOpenMPTargetExecutionDirective()) {
!OpenMP().isInOpenMPDeclareTargetContext() &&
!OpenMP().isInOpenMPTargetExecutionDirective()) {
if (!DefinitionRequired)
MarkVirtualMembersReferenced(Loc, Class);
return;
Expand Down
674 changes: 73 additions & 601 deletions clang/lib/Sema/SemaExpr.cpp

Large diffs are not rendered by default.

176 changes: 94 additions & 82 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/Template.h"
Expand Down Expand Up @@ -884,8 +885,8 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,

// Exceptions aren't allowed in CUDA device code.
if (getLangOpts().CUDA)
CUDADiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions)
<< "throw" << llvm::to_underlying(CurrentCUDATarget());
CUDA().DiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions)
<< "throw" << llvm::to_underlying(CUDA().CurrentTarget());

if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
Expand Down Expand Up @@ -1415,42 +1416,26 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
}

ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
// C++20 [expr.prim.this]p1:
// The keyword this names a pointer to the object for which an
// implicit object member function is invoked or a non-static
// data member's initializer is evaluated.
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.
QualType ThisTy = getCurrentThisType();

if (CheckCXXThisType(Loc, ThisTy))
return ExprError();
if (ThisTy.isNull()) {
DeclContext *DC = getFunctionLevelDeclContext();

return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
}
if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
Method && Method->isExplicitObjectMemberFunction()) {
return Diag(Loc, diag::err_invalid_this_use) << 1;
}

bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) {
if (!Type.isNull())
return false;
if (isLambdaCallWithExplicitObjectParameter(CurContext))
return Diag(Loc, diag::err_invalid_this_use) << 1;

// C++20 [expr.prim.this]p3:
// If a declaration declares a member function or member function template
// of a class X, the expression this is a prvalue of type
// "pointer to cv-qualifier-seq X" wherever X is the current class between
// the optional cv-qualifier-seq and the end of the function-definition,
// member-declarator, or declarator. It shall not appear within the
// declaration of either a static member function or an explicit object
// member function of the current class (although its type and value
// category are defined within such member functions as they are within
// an implicit object member function).
DeclContext *DC = getFunctionLevelDeclContext();
if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
Method && Method->isExplicitObjectMemberFunction()) {
Diag(Loc, diag::err_invalid_this_use) << 1;
} else if (isLambdaCallWithExplicitObjectParameter(CurContext)) {
Diag(Loc, diag::err_invalid_this_use) << 1;
} else {
Diag(Loc, diag::err_invalid_this_use) << 0;
return Diag(Loc, diag::err_invalid_this_use) << 0;
}
return true;

return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
}

Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
Expand Down Expand Up @@ -1708,17 +1693,17 @@ bool Sema::isUsualDeallocationFunction(const CXXMethodDecl *Method) {
// [CUDA] Ignore this function, if we can't call it.
const FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true);
if (getLangOpts().CUDA) {
auto CallPreference = IdentifyCUDAPreference(Caller, Method);
auto CallPreference = CUDA().IdentifyPreference(Caller, Method);
// If it's not callable at all, it's not the right function.
if (CallPreference < CFP_WrongSide)
if (CallPreference < SemaCUDA::CFP_WrongSide)
return false;
if (CallPreference == CFP_WrongSide) {
if (CallPreference == SemaCUDA::CFP_WrongSide) {
// Maybe. We have to check if there are better alternatives.
DeclContext::lookup_result R =
Method->getDeclContext()->lookup(Method->getDeclName());
for (const auto *D : R) {
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (IdentifyCUDAPreference(Caller, FD) > CFP_WrongSide)
if (CUDA().IdentifyPreference(Caller, FD) > SemaCUDA::CFP_WrongSide)
return false;
}
}
Expand All @@ -1737,7 +1722,7 @@ bool Sema::isUsualDeallocationFunction(const CXXMethodDecl *Method) {
return llvm::none_of(PreventedBy, [&](const FunctionDecl *FD) {
assert(FD->getNumParams() == 1 &&
"Only single-operand functions should be in PreventedBy");
return IdentifyCUDAPreference(Caller, FD) >= CFP_HostDevice;
return CUDA().IdentifyPreference(Caller, FD) >= SemaCUDA::CFP_HostDevice;
});
}

Expand Down Expand Up @@ -1774,7 +1759,7 @@ namespace {
UsualDeallocFnInfo(Sema &S, DeclAccessPair Found)
: Found(Found), FD(dyn_cast<FunctionDecl>(Found->getUnderlyingDecl())),
Destroying(false), HasSizeT(false), HasAlignValT(false),
CUDAPref(Sema::CFP_Native) {
CUDAPref(SemaCUDA::CFP_Native) {
// A function template declaration is never a usual deallocation function.
if (!FD)
return;
Expand All @@ -1800,7 +1785,7 @@ namespace {

// In CUDA, determine how much we'd like / dislike to call this.
if (S.getLangOpts().CUDA)
CUDAPref = S.IdentifyCUDAPreference(
CUDAPref = S.CUDA().IdentifyPreference(
S.getCurFunctionDecl(/*AllowLambda=*/true), FD);
}

Expand Down Expand Up @@ -1831,7 +1816,7 @@ namespace {
DeclAccessPair Found;
FunctionDecl *FD;
bool Destroying, HasSizeT, HasAlignValT;
Sema::CUDAFunctionPreference CUDAPref;
SemaCUDA::CUDAFunctionPreference CUDAPref;
};
}

Expand All @@ -1855,7 +1840,7 @@ static UsualDeallocFnInfo resolveDeallocationOverload(
for (auto I = R.begin(), E = R.end(); I != E; ++I) {
UsualDeallocFnInfo Info(S, I.getPair());
if (!Info || !isNonPlacementDeallocationFunction(S, Info.FD) ||
Info.CUDAPref == Sema::CFP_Never)
Info.CUDAPref == SemaCUDA::CFP_Never)
continue;

if (!Best) {
Expand Down Expand Up @@ -2715,13 +2700,9 @@ static bool resolveAllocationOverload(
return true;

case OR_Deleted: {
if (Diagnose) {
Candidates.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_deleted_call)
<< R.getLookupName() << Range),
S, OCD_AllCandidates, Args);
}
if (Diagnose)
S.DiagnoseUseOfDeletedFunction(R.getNameLoc(), Range, R.getLookupName(),
Candidates, Best->Function, Args);
return true;
}
}
Expand Down Expand Up @@ -2956,8 +2937,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
}

if (getLangOpts().CUDA)
EraseUnwantedCUDAMatches(getCurFunctionDecl(/*AllowLambda=*/true),
Matches);
CUDA().EraseUnwantedMatches(getCurFunctionDecl(/*AllowLambda=*/true),
Matches);
} else {
// C++1y [expr.new]p22:
// For a non-placement allocation function, the normal deallocation
Expand Down Expand Up @@ -3375,7 +3356,9 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
// FIXME: DiagnoseUseOfDecl?
if (Operator->isDeleted()) {
if (Diagnose) {
Diag(StartLoc, diag::err_deleted_function_use);
StringLiteral *Msg = Operator->getDeletedMessage();
Diag(StartLoc, diag::err_deleted_function_use)
<< (Msg != nullptr) << (Msg ? Msg->getString() : StringRef());
NoteDeletedFunction(Operator);
}
return true;
Expand Down Expand Up @@ -3979,14 +3962,11 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
S, OCD_AmbiguousCandidates, Args);
return true;

case OR_Deleted: {
Candidates.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_deleted_call)
<< R.getLookupName() << Range),
S, OCD_AllCandidates, Args);
case OR_Deleted:
S.DiagnoseUseOfDeletedFunction(R.getNameLoc(), Range, R.getLookupName(),
Candidates, Best->Function, Args);
return true;
}
}
llvm_unreachable("Unreachable, bad result from BestViableFunction");
}

Expand Down Expand Up @@ -5011,6 +4991,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return From;
}

/// Checks that type T is not a VLA.
///
/// @returns @c true if @p T is VLA and a diagnostic was emitted,
/// @c false otherwise.
static bool DiagnoseVLAInCXXTypeTrait(Sema &S, const TypeSourceInfo *T,
clang::tok::TokenKind TypeTraitID) {
if (!T->getType()->isVariableArrayType())
return false;

S.Diag(T->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
<< 1 << TypeTraitID;
return true;
}

/// Check the completeness of a type in a unary type trait.
///
/// If the particular type trait requires a complete type, tries to complete
Expand Down Expand Up @@ -5187,7 +5181,9 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
}

static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
SourceLocation KeyLoc, QualType T) {
SourceLocation KeyLoc,
TypeSourceInfo *TInfo) {
QualType T = TInfo->getType();
assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");

ASTContext &C = Self.Context;
Expand All @@ -5204,21 +5200,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
case UTT_IsArray:
return T->isArrayType();
case UTT_IsBoundedArray:
if (!T->isVariableArrayType()) {
return T->isArrayType() && !T->isIncompleteArrayType();
}

Self.Diag(KeyLoc, diag::err_vla_unsupported)
<< 1 << tok::kw___is_bounded_array;
return false;
if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_bounded_array))
return false;
return T->isArrayType() && !T->isIncompleteArrayType();
case UTT_IsUnboundedArray:
if (!T->isVariableArrayType()) {
return T->isIncompleteArrayType();
}

Self.Diag(KeyLoc, diag::err_vla_unsupported)
<< 1 << tok::kw___is_unbounded_array;
return false;
if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_unbounded_array))
return false;
return T->isIncompleteArrayType();
case UTT_IsPointer:
return T->isAnyPointerType();
case UTT_IsNullPointer:
Expand Down Expand Up @@ -5630,7 +5618,7 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
return false;

if (Kind <= UTT_Last)
return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType());
return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]);

// Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary
// alongside the IsConstructible traits to avoid duplication.
Expand Down Expand Up @@ -6092,13 +6080,24 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
diag::err_incomplete_type);

if (LhsT->isVariableArrayType())
Self.Diag(Lhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
<< 1 << tok::kw___is_layout_compatible;
if (RhsT->isVariableArrayType())
Self.Diag(Rhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
<< 1 << tok::kw___is_layout_compatible;
DiagnoseVLAInCXXTypeTrait(Self, Lhs, tok::kw___is_layout_compatible);
DiagnoseVLAInCXXTypeTrait(Self, Rhs, tok::kw___is_layout_compatible);

return Self.IsLayoutCompatible(LhsT, RhsT);
}
case BTT_IsPointerInterconvertibleBaseOf: {
if (LhsT->isStructureOrClassType() && RhsT->isStructureOrClassType() &&
!Self.getASTContext().hasSameUnqualifiedType(LhsT, RhsT)) {
Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
diag::err_incomplete_type);
}

DiagnoseVLAInCXXTypeTrait(Self, Lhs,
tok::kw___is_pointer_interconvertible_base_of);
DiagnoseVLAInCXXTypeTrait(Self, Rhs,
tok::kw___is_pointer_interconvertible_base_of);

return Self.IsPointerInterconvertibleBaseOf(Lhs, Rhs);
}
default: llvm_unreachable("not a BTT");
}
Expand Down Expand Up @@ -8430,7 +8429,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// unnecessary temporary objects. If we skip this step, IR generation is
// able to synthesize the storage for itself in the aggregate case, and
// adding the extra node to the AST is just clutter.
if (isInMaterializeTemporaryObjectContext() && getLangOpts().CPlusPlus17 &&
if (isInLifetimeExtendingContext() && getLangOpts().CPlusPlus17 &&
E->isPRValue() && !E->getType()->isVoidType()) {
ExprResult Res = TemporaryMaterializationConversion(E);
if (Res.isInvalid())
Expand Down Expand Up @@ -8643,8 +8642,21 @@ static ExprResult attemptRecovery(Sema &SemaRef,

// Detect and handle the case where the decl might be an implicit
// member.
if (SemaRef.isPotentialImplicitMemberAccess(
NewSS, R, Consumer.isAddressOfOperand()))
bool MightBeImplicitMember;
if (!Consumer.isAddressOfOperand())
MightBeImplicitMember = true;
else if (!NewSS.isEmpty())
MightBeImplicitMember = false;
else if (R.isOverloadedResult())
MightBeImplicitMember = false;
else if (R.isUnresolvableResult())
MightBeImplicitMember = true;
else
MightBeImplicitMember = isa<FieldDecl>(ND) ||
isa<IndirectFieldDecl>(ND) ||
isa<MSPropertyDecl>(ND);

if (MightBeImplicitMember)
return SemaRef.BuildPossibleImplicitMemberExpr(
NewSS, /*TemplateKWLoc*/ SourceLocation(), R,
/*TemplateArgs*/ nullptr, /*S*/ nullptr);
Expand Down
72 changes: 19 additions & 53 deletions clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
// This file implements semantic analysis member access expressions.
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/Overload.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
Expand All @@ -18,9 +17,11 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaOpenMP.h"

using namespace clang;
using namespace sema;
Expand Down Expand Up @@ -61,10 +62,6 @@ enum IMAKind {
/// The reference is a contextually-permitted abstract member reference.
IMA_Abstract,

/// Whether the context is static is dependent on the enclosing template (i.e.
/// in a dependent class scope explicit specialization).
IMA_Dependent,

/// The reference may be to an unresolved using declaration and the
/// context is not an instance method.
IMA_Unresolved_StaticOrExplicitContext,
Expand Down Expand Up @@ -95,18 +92,10 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,

DeclContext *DC = SemaRef.getFunctionLevelDeclContext();

bool couldInstantiateToStatic = false;
bool isStaticOrExplicitContext = SemaRef.CXXThisTypeOverride.isNull();

if (auto *MD = dyn_cast<CXXMethodDecl>(DC)) {
if (MD->isImplicitObjectMemberFunction()) {
isStaticOrExplicitContext = false;
// A dependent class scope function template explicit specialization
// that is neither declared 'static' nor with an explicit object
// parameter could instantiate to a static or non-static member function.
couldInstantiateToStatic = MD->getDependentSpecializationInfo();
}
}
bool isStaticOrExplicitContext =
SemaRef.CXXThisTypeOverride.isNull() &&
(!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic() ||
cast<CXXMethodDecl>(DC)->isExplicitObjectMemberFunction());

if (R.isUnresolvableResult())
return isStaticOrExplicitContext ? IMA_Unresolved_StaticOrExplicitContext
Expand Down Expand Up @@ -135,9 +124,6 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
if (Classes.empty())
return IMA_Static;

if (couldInstantiateToStatic)
return IMA_Dependent;

// C++11 [expr.prim.general]p12:
// An id-expression that denotes a non-static data member or non-static
// member function of a class can only be used:
Expand Down Expand Up @@ -278,52 +264,32 @@ static void diagnoseInstanceReference(Sema &SemaRef,
}
}

bool Sema::isPotentialImplicitMemberAccess(const CXXScopeSpec &SS,
LookupResult &R,
bool IsAddressOfOperand) {
if (!getLangOpts().CPlusPlus)
return false;
else if (R.empty() || !R.begin()->isCXXClassMember())
return false;
else if (!IsAddressOfOperand)
return true;
else if (!SS.isEmpty())
return false;
else if (R.isOverloadedResult())
return false;
else if (R.isUnresolvableResult())
return true;
else
return isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(R.getFoundDecl());
}

/// Builds an expression which might be an implicit member expression.
ExprResult Sema::BuildPossibleImplicitMemberExpr(
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S) {
switch (IMAKind Classification = ClassifyImplicitMemberAccess(*this, R)) {
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
UnresolvedLookupExpr *AsULE) {
switch (ClassifyImplicitMemberAccess(*this, R)) {
case IMA_Instance:
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S);

case IMA_Mixed:
case IMA_Mixed_Unrelated:
case IMA_Unresolved:
return BuildImplicitMemberExpr(
SS, TemplateKWLoc, R, TemplateArgs,
/*IsKnownInstance=*/Classification == IMA_Instance, S);
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false,
S);

case IMA_Field_Uneval_Context:
Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
<< R.getLookupNameInfo().getName();
[[fallthrough]];
case IMA_Static:
case IMA_Abstract:
case IMA_Dependent:
case IMA_Mixed_StaticOrExplicitContext:
case IMA_Unresolved_StaticOrExplicitContext:
if (TemplateArgs || TemplateKWLoc.isValid())
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*RequiresADL=*/false,
TemplateArgs);
return BuildDeclarationNameExpr(
SS, R, /*NeedsADL=*/false, /*AcceptInvalidDecl=*/false,
/*NeedUnresolved=*/Classification == IMA_Dependent);
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
return AsULE ? AsULE : BuildDeclarationNameExpr(SS, R, false);

case IMA_Error_StaticOrExplicitContext:
case IMA_Error_Unrelated:
Expand Down Expand Up @@ -1935,9 +1901,9 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
if (getLangOpts().OpenMP && IsArrow &&
!CurContext->isDependentContext() &&
isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) {
if (auto *PrivateCopy = isOpenMPCapturedDecl(Field)) {
return getOpenMPCapturedExpr(PrivateCopy, VK, OK,
MemberNameInfo.getLoc());
if (auto *PrivateCopy = OpenMP().isOpenMPCapturedDecl(Field)) {
return OpenMP().getOpenMPCapturedExpr(PrivateCopy, VK, OK,
MemberNameInfo.getLoc());
}
}

Expand Down
19 changes: 14 additions & 5 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9763,12 +9763,15 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}
case OR_Deleted: {
S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
<< OnlyArg->getType() << DestType.getNonReferenceType()
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);

StringLiteral *Msg = Best->Function->getDeletedMessage();
S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
<< OnlyArg->getType() << DestType.getNonReferenceType()
<< (Msg != nullptr) << (Msg ? Msg->getString() : StringRef())
<< Args[0]->getSourceRange();
if (Ovl == OR_Deleted) {
S.NoteDeletedFunction(Best->Function);
} else {
Expand Down Expand Up @@ -10027,9 +10030,12 @@ bool InitializationSequence::Diagnose(Sema &S,
<< llvm::to_underlying(
S.getSpecialMember(cast<CXXMethodDecl>(Best->Function)))
<< DestType << ArgsRange;
else
else {
StringLiteral *Msg = Best->Function->getDeletedMessage();
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
<< DestType << ArgsRange;
<< DestType << (Msg != nullptr)
<< (Msg ? Msg->getString() : StringRef()) << ArgsRange;
}

S.NoteDeletedFunction(Best->Function);
break;
Expand Down Expand Up @@ -11061,6 +11067,9 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
}

case OR_Deleted: {
// FIXME: There are no tests for this diagnostic, and it doesn't seem
// like we ever get here; attempts to trigger this seem to yield a
// generic c'all to deleted function' diagnostic instead.
Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted)
<< TemplateName;
NoteDeletedFunction(Best->Function);
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@
// This file implements semantic analysis for C++ lambda expressions.
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/SemaLambda.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include <optional>
Expand Down Expand Up @@ -1393,11 +1395,11 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,

// CUDA lambdas get implicit host and device attributes.
if (getLangOpts().CUDA)
CUDASetLambdaAttrs(Method);
CUDA().SetLambdaAttrs(Method);

// OpenMP lambdas might get assumumption attributes.
if (LangOpts.OpenMP)
ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method);
OpenMP().ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method);

handleLambdaNumbering(Class, Method);

Expand Down Expand Up @@ -2136,7 +2138,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
CaptureInits.push_back(Init.get());

if (LangOpts.CUDA)
CUDACheckLambdaCapture(CallOperator, From);
CUDA().CheckLambdaCapture(CallOperator, From);
}

Class->setCaptures(Context, Captures);
Expand Down
Loading