426 changes: 244 additions & 182 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool visitVarDecl(const VarDecl *VD);
/// Visit an APValue.
bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
bool visitAPValueInitializer(const APValue &Val, const Expr *E);

/// Visits an expression and converts it to a boolean.
bool visitBool(const Expr *E);
Expand Down Expand Up @@ -224,7 +225,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
return this->emitFinishInitPop(I);
}

bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *E);
bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *ArrayFiller,
const Expr *E);
bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init);

/// Creates a local primitive value.
Expand Down Expand Up @@ -283,8 +285,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,

bool emitRecordDestruction(const Record *R);
bool emitDestruction(const Descriptor *Desc);
unsigned collectBaseOffset(const RecordType *BaseType,
const RecordType *DerivedType);
unsigned collectBaseOffset(const QualType BaseType,
const QualType DerivedType);

protected:
/// Variable to storage mapping.
Expand Down
24 changes: 17 additions & 7 deletions clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,23 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
if (!emitFieldInitializer(F, F->Offset, InitExpr))
return false;
} else if (const Type *Base = Init->getBaseClass()) {
// Base class initializer.
// Get This Base and call initializer on it.
const auto *BaseDecl = Base->getAsCXXRecordDecl();
assert(BaseDecl);
const Record::Base *B = R->getBase(BaseDecl);
assert(B);
if (!this->emitGetPtrThisBase(B->Offset, InitExpr))
return false;

if (Init->isBaseVirtual()) {
assert(R->getVirtualBase(BaseDecl));
if (!this->emitGetPtrThisVirtBase(BaseDecl, InitExpr))
return false;

} else {
// Base class initializer.
// Get This Base and call initializer on it.
const Record::Base *B = R->getBase(BaseDecl);
assert(B);
if (!this->emitGetPtrThisBase(B->Offset, InitExpr))
return false;
}

if (!this->visitInitializer(InitExpr))
return false;
if (!this->emitFinishInitPop(InitExpr))
Expand Down Expand Up @@ -323,7 +332,8 @@ bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
template <class Emitter>
bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
for (auto *D : DS->decls()) {
if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, UsingEnumDecl>(D))
if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, UsingEnumDecl,
FunctionDecl>(D))
continue;

const auto *VD = dyn_cast<VarDecl>(D);
Expand Down
33 changes: 33 additions & 0 deletions clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,36 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FD) {

return Func;
}

unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,
const RecordDecl *DerivedDecl) const {
assert(BaseDecl);
assert(DerivedDecl);
const auto *FinalDecl = cast<CXXRecordDecl>(BaseDecl);
const RecordDecl *CurDecl = DerivedDecl;
const Record *CurRecord = P->getOrCreateRecord(CurDecl);
assert(CurDecl && FinalDecl);

unsigned OffsetSum = 0;
for (;;) {
assert(CurRecord->getNumBases() > 0);
// One level up
for (const Record::Base &B : CurRecord->bases()) {
const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl);

if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {
OffsetSum += B.Offset;
CurRecord = B.R;
CurDecl = BaseDecl;
break;
}
}
if (CurDecl == FinalDecl)
break;

// break;
}

assert(OffsetSum > 0);
return OffsetSum;
}
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ class Context final {
/// Returns the program. This is only needed for unittests.
Program &getProgram() const { return *P.get(); }

unsigned collectBaseOffset(const RecordDecl *BaseDecl,
const RecordDecl *DerivedDecl) const;

private:
/// Runs a function.
bool Run(State &Parent, const Function *Func, APValue &Result);
Expand Down
74 changes: 56 additions & 18 deletions clang/lib/AST/Interp/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,28 +136,66 @@ static void moveArrayDesc(Block *B, const std::byte *Src, std::byte *Dst,
}
}

static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
bool IsActive, const Descriptor *D,
unsigned FieldOffset) {
bool IsUnion = false; // FIXME
auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
Desc->Offset = FieldOffset;
Desc->Desc = D;
Desc->IsInitialized = D->IsArray;
Desc->IsBase = false;
Desc->IsActive = IsActive && !IsUnion;
Desc->IsConst = IsConst || D->IsConst;
Desc->IsFieldMutable = IsMutable || D->IsMutable;

if (auto Fn = D->CtorFn)
Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,
Desc->IsActive, D);
}

static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
bool IsActive, const Descriptor *D, unsigned FieldOffset,
bool IsVirtualBase) {
assert(D);
assert(D->ElemRecord);

bool IsUnion = D->ElemRecord->isUnion();
auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
Desc->Offset = FieldOffset;
Desc->Desc = D;
Desc->IsInitialized = D->IsArray;
Desc->IsBase = true;
Desc->IsActive = IsActive && !IsUnion;
Desc->IsConst = IsConst || D->IsConst;
Desc->IsFieldMutable = IsMutable || D->IsMutable;

for (const auto &V : D->ElemRecord->bases())
initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc,
V.Offset, false);
for (const auto &F : D->ElemRecord->fields())
initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, F.Desc,
F.Offset);

// If this is initializing a virtual base, we do NOT want to consider its
// virtual bases, those are already flattened into the parent record when
// creating it.
if (IsVirtualBase)
return;

for (const auto &V : D->ElemRecord->virtual_bases())
initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc,
V.Offset, true);
}

static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
bool IsActive, const Descriptor *D) {
const bool IsUnion = D->ElemRecord->isUnion();
auto CtorSub = [=](unsigned SubOff, const Descriptor *F, bool IsBase) {
auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
Desc->Offset = SubOff;
Desc->Desc = F;
Desc->IsInitialized = F->IsArray && !IsBase;
Desc->IsBase = IsBase;
Desc->IsActive = IsActive && !IsUnion;
Desc->IsConst = IsConst || F->IsConst;
Desc->IsFieldMutable = IsMutable || F->IsMutable;
if (auto Fn = F->CtorFn)
Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsFieldMutable, Desc->IsActive,
F);
};
for (const auto &B : D->ElemRecord->bases())
CtorSub(B.Offset, B.Desc, /*isBase=*/true);
for (const auto &V : D->ElemRecord->bases())
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false);
for (const auto &F : D->ElemRecord->fields())
CtorSub(F.Offset, F.Desc, /*isBase=*/false);
initField(B, Ptr, IsConst, IsMutable, IsActive, F.Desc, F.Offset);
for (const auto &V : D->ElemRecord->virtual_bases())
CtorSub(V.Offset, V.Desc, /*isBase=*/true);
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, true);
}

static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ struct InlineDescriptor {
InlineDescriptor(const Descriptor *D)
: Offset(sizeof(InlineDescriptor)), IsConst(false), IsInitialized(false),
IsBase(false), IsActive(false), IsFieldMutable(false), Desc(D) {}

void dump() const { dump(llvm::errs()); }
void dump(llvm::raw_ostream &OS) const;
};

/// Describes a memory block created by an allocation site.
Expand Down
31 changes: 28 additions & 3 deletions clang/lib/AST/Interp/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,33 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
OS << " primitive";

if (isZeroSizeArray())
OS << " zero-size-arrary";
OS << " zero-size-array";
else if (isUnknownSizeArray())
OS << " unknown-size-array";

if (isDummy())
OS << " dummy";
}

LLVM_DUMP_METHOD void InlineDescriptor::dump(llvm::raw_ostream &OS) const {
{
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
OS << "InlineDescriptor " << (const void *)this << "\n";
}
OS << "Offset: " << Offset << "\n";
OS << "IsConst: " << IsConst << "\n";
OS << "IsInitialized: " << IsInitialized << "\n";
OS << "IsBase: " << IsBase << "\n";
OS << "IsActive: " << IsActive << "\n";
OS << "IsFieldMutable: " << IsFieldMutable << "\n";
OS << "Desc: ";
if (Desc)
Desc->dump(OS);
else
OS << "nullptr";
OS << "\n";
}

LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
unsigned Indent) const {
unsigned Spaces = Indent * 2;
Expand Down Expand Up @@ -251,8 +270,6 @@ LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
++I;
}

// FIXME: Virtual bases.

I = 0;
for (const Record::Field &F : fields()) {
OS.indent(Indent) << "- Field " << I << ": ";
Expand All @@ -263,6 +280,14 @@ LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
OS << ". Offset " << (Offset + F.Offset) << "\n";
++I;
}

I = 0;
for (const Record::Base &B : virtual_bases()) {
OS.indent(Indent) << "- Virtual Base " << I << ". Offset "
<< (Offset + B.Offset) << "\n";
B.R->dump(OS, Indentation + 1, Offset + B.Offset);
++I;
}
}

LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1355,20 +1355,26 @@ inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
while (Base.isBaseClass())
Base = Base.getBase();

auto *Field = Base.getRecord()->getVirtualBase(Decl);
S.Stk.push<Pointer>(Base.atField(Field->Offset));
const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
return true;
}

inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
const RecordDecl *D) {
assert(D);
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
return false;
if (Ptr.isDummy()) // FIXME: Once we have type info for dummy pointers, this
// needs to go.
return false;
return VirtBaseHelper(S, OpPC, D, Ptr);
}

inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
const RecordDecl *D) {
assert(D);
if (S.checkingPotentialConstantExpression())
return false;
const Pointer &This = S.Current->getThis();
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ def GetPtrDerivedPop : Opcode {
}

// [Pointer] -> [Pointer]
def GetPtrVirtBase : Opcode {
def GetPtrVirtBasePop : Opcode {
// RecordDecl of base class.
let Args = [ArgRecordDecl];
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
if (const auto *Var = dyn_cast<VarDecl>(VD)) {
IsStatic = Context::shouldBeGloballyIndexed(VD);
IsExtern = Var->hasExternalStorage();
} else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl>(VD)) {
} else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl,
TemplateParamObjectDecl>(VD)) {
IsStatic = true;
IsExtern = false;
} else {
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2510,6 +2510,18 @@ bool Type::isSveVLSBuiltinType() const {
return false;
}

QualType Type::getSizelessVectorEltType(const ASTContext &Ctx) const {
assert(isSizelessVectorType() && "Must be sizeless vector type");
// Currently supports SVE and RVV
if (isSVESizelessBuiltinType())
return getSveEltType(Ctx);

if (isRVVSizelessBuiltinType())
return getRVVEltType(Ctx);

llvm_unreachable("Unhandled type");
}

QualType Type::getSveEltType(const ASTContext &Ctx) const {
assert(isSveVLSBuiltinType() && "unsupported type!");

Expand Down
16 changes: 12 additions & 4 deletions clang/lib/Analysis/FlowSensitive/ASTOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,20 @@ namespace clang::dataflow {

const Expr &ignoreCFGOmittedNodes(const Expr &E) {
const Expr *Current = &E;
if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) {
Current = EWC->getSubExpr();
const Expr *Last = nullptr;
while (Current != Last) {
Last = Current;
if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) {
Current = EWC->getSubExpr();
assert(Current != nullptr);
}
if (auto *CE = dyn_cast<ConstantExpr>(Current)) {
Current = CE->getSubExpr();
assert(Current != nullptr);
}
Current = Current->IgnoreParens();
assert(Current != nullptr);
}
Current = Current->IgnoreParens();
assert(Current != nullptr);
return *Current;
}

Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ namespace dataflow {

const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const {
auto BlockIt = ACFG.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
assert(BlockIt != ACFG.getStmtToBlock().end());
if (BlockIt == ACFG.getStmtToBlock().end()) {
assert(false);
// Return null to avoid dereferencing the end iterator in non-assert builds.
return nullptr;
}
if (!ACFG.isBlockReachable(*BlockIt->getSecond()))
return nullptr;
if (BlockIt->getSecond()->getBlockID() == CurBlockID)
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/ARM.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
bool hasBitIntType() const override { return true; }

const char *getBFloat16Mangling() const override { return "u6__bf16"; };

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(getTriple().isArch64Bit() ? 256 : 64, 64);
}
};

class LLVM_LIBRARY_VISIBILITY ARMleTargetInfo : public ARMTargetInfo {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/AVR.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo {
std::optional<std::string> handleAsmEscapedChar(char EscChar) const override;
StringRef getABI() const override { return ABI; }

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}

protected:
std::string CPU;
StringRef ABI;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/BPF.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
StringRef CPUName(Name);
return isValidCPUName(CPUName);
}

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}
};
} // namespace targets
} // namespace clang
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/M68k.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ class LLVM_LIBRARY_VISIBILITY M68kTargetInfo : public TargetInfo {
BuiltinVaListKind getBuiltinVaListKind() const override;
bool setCPU(const std::string &Name) override;
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override;

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}
};

} // namespace targets
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/Mips.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo {

bool validateTarget(DiagnosticsEngine &Diags) const override;
bool hasBitIntType() const override { return true; }

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}
};
} // namespace targets
} // namespace clang
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,10 @@ class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo {
// This is the ELF definition
return TargetInfo::PowerABIBuiltinVaList;
}

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}
};

// Note: ABI differences may eventually require us to have a separate
Expand Down Expand Up @@ -503,6 +507,10 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
return CCCR_Warning;
}
}

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(128, 128);
}
};

class LLVM_LIBRARY_VISIBILITY AIXPPC32TargetInfo :
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ class RISCVTargetInfo : public TargetInfo {
void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool supportsTargetAttributeTune() const override { return true; }
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}
};
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
public:
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/Sparc.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo {
CPU = getCPUKind(Name);
return CPU != CK_GENERIC;
}

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}
};

// SPARC v8 is the 32-bit mode selected by Triple::sparc.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/SystemZ.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
int getEHDataRegisterNumber(unsigned RegNo) const override {
return RegNo < 4 ? 6 + RegNo : -1;
}

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(256, 256);
}
};
} // namespace targets
} // namespace clang
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Basic/Targets/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
.Case("simd128", SIMDLevel >= SIMD128)
.Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
.Case("half-precision", HasHalfPrecision)
.Case("nontrapping-fptoint", HasNontrappingFPToInt)
.Case("sign-ext", HasSignExt)
.Case("exception-handling", HasExceptionHandling)
Expand Down Expand Up @@ -156,6 +157,7 @@ bool WebAssemblyTargetInfo::initFeatureMap(
Features["reference-types"] = true;
Features["sign-ext"] = true;
Features["tail-call"] = true;
Features["half-precision"] = true;
setSIMDLevel(Features, SIMD128, true);
} else if (CPU == "generic") {
Features["mutable-globals"] = true;
Expand Down Expand Up @@ -216,6 +218,15 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
HasBulkMemory = false;
continue;
}
if (Feature == "+half-precision") {
SIMDLevel = std::max(SIMDLevel, SIMD128);
HasHalfPrecision = true;
continue;
}
if (Feature == "-half-precision") {
HasHalfPrecision = false;
continue;
}
if (Feature == "+atomics") {
HasAtomics = true;
continue;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/WebAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
bool HasReferenceTypes = false;
bool HasExtendedConst = false;
bool HasMultiMemory = false;
bool HasHalfPrecision = false;

std::string ABI;

Expand Down
10 changes: 8 additions & 2 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3885,9 +3885,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}

case Builtin::BI__builtin_reduce_max: {
auto GetIntrinsicID = [](QualType QT) {
auto GetIntrinsicID = [this](QualType QT) {
if (auto *VecTy = QT->getAs<VectorType>())
QT = VecTy->getElementType();
else if (QT->isSizelessVectorType())
QT = QT->getSizelessVectorEltType(CGM.getContext());

if (QT->isSignedIntegerType())
return llvm::Intrinsic::vector_reduce_smax;
if (QT->isUnsignedIntegerType())
Expand All @@ -3900,9 +3903,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}

case Builtin::BI__builtin_reduce_min: {
auto GetIntrinsicID = [](QualType QT) {
auto GetIntrinsicID = [this](QualType QT) {
if (auto *VecTy = QT->getAs<VectorType>())
QT = VecTy->getElementType();
else if (QT->isSizelessVectorType())
QT = QT->getSizelessVectorEltType(CGM.getContext());

if (QT->isSignedIntegerType())
return llvm::Intrinsic::vector_reduce_smin;
if (QT->isUnsignedIntegerType())
Expand Down
13 changes: 7 additions & 6 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4698,11 +4698,11 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
AggValueSlot Slot = args.isUsingInAlloca()
? createPlaceholderSlot(*this, type) : CreateAggTemp(type, "agg.tmp");

bool DestroyedInCallee = true, NeedsEHCleanup = true;
bool DestroyedInCallee = true, NeedsCleanup = true;
if (const auto *RD = type->getAsCXXRecordDecl())
DestroyedInCallee = RD->hasNonTrivialDestructor();
else
NeedsEHCleanup = needsEHCleanup(type.isDestructedType());
NeedsCleanup = type.isDestructedType();

if (DestroyedInCallee)
Slot.setExternallyDestructed();
Expand All @@ -4711,14 +4711,15 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
RValue RV = Slot.asRValue();
args.add(RV, type);

if (DestroyedInCallee && NeedsEHCleanup) {
if (DestroyedInCallee && NeedsCleanup) {
// Create a no-op GEP between the placeholder and the cleanup so we can
// RAUW it successfully. It also serves as a marker of the first
// instruction where the cleanup is active.
pushFullExprCleanup<DestroyUnpassedArg>(EHCleanup, Slot.getAddress(),
type);
pushFullExprCleanup<DestroyUnpassedArg>(NormalAndEHCleanup,
Slot.getAddress(), type);
// This unreachable is a temporary marker which will be removed later.
llvm::Instruction *IsActive = Builder.CreateUnreachable();
llvm::Instruction *IsActive =
Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
args.addArgCleanupDeactivation(EHStack.stable_begin(), IsActive);
}
return;
Expand Down
76 changes: 38 additions & 38 deletions clang/lib/CodeGen/CGCleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,12 +634,19 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
/// Pops a cleanup block. If the block includes a normal cleanup, the
/// current insertion point is threaded through the cleanup, as are
/// any branch fixups on the cleanup.
void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough,
bool ForDeactivation) {
assert(!EHStack.empty() && "cleanup stack is empty!");
assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!");
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups());

// If we are deactivating a normal cleanup, we need to pretend that the
// fallthrough is unreachable. We restore this IP before returning.
CGBuilderTy::InsertPoint NormalDeactivateOrigIP;
if (ForDeactivation && (Scope.isNormalCleanup() || !getLangOpts().EHAsynch)) {
NormalDeactivateOrigIP = Builder.saveAndClearIP();
}
// Remember activation information.
bool IsActive = Scope.isActive();
Address NormalActiveFlag =
Expand Down Expand Up @@ -667,7 +674,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {

// - whether there's a fallthrough
llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock();
bool HasFallthrough = (FallthroughSource != nullptr && IsActive);
bool HasFallthrough =
FallthroughSource != nullptr && (IsActive || HasExistingBranches);

// Branch-through fall-throughs leave the insertion point set to the
// end of the last cleanup, which points to the current scope. The
Expand All @@ -692,7 +700,11 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {

// If we have a prebranched fallthrough into an inactive normal
// cleanup, rewrite it so that it leads to the appropriate place.
if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) {
if (Scope.isNormalCleanup() && HasPrebranchedFallthrough &&
!RequiresNormalCleanup) {
// FIXME: Come up with a program which would need forwarding prebranched
// fallthrough and add tests. Otherwise delete this and assert against it.
assert(!IsActive);
llvm::BasicBlock *prebranchDest;

// If the prebranch is semantically branching through the next
Expand Down Expand Up @@ -724,6 +736,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EHStack.popCleanup(); // safe because there are no fixups
assert(EHStack.getNumBranchFixups() == 0 ||
EHStack.hasNormalCleanups());
if (NormalDeactivateOrigIP.isSet())
Builder.restoreIP(NormalDeactivateOrigIP);
return;
}

Expand Down Expand Up @@ -760,11 +774,19 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
if (!RequiresNormalCleanup) {
// Mark CPP scope end for passed-by-value Arg temp
// per Windows ABI which is "normally" Cleanup in callee
if (IsEHa && getInvokeDest() && Builder.GetInsertBlock()) {
if (Personality.isMSVCXXPersonality())
if (IsEHa && getInvokeDest()) {
// If we are deactivating a normal cleanup then we don't have a
// fallthrough. Restore original IP to emit CPP scope ends in the correct
// block.
if (NormalDeactivateOrigIP.isSet())
Builder.restoreIP(NormalDeactivateOrigIP);
if (Personality.isMSVCXXPersonality() && Builder.GetInsertBlock())
EmitSehCppScopeEnd();
if (NormalDeactivateOrigIP.isSet())
NormalDeactivateOrigIP = Builder.saveAndClearIP();
}
destroyOptimisticNormalEntry(*this, Scope);
Scope.MarkEmitted();
EHStack.popCleanup();
} else {
// If we have a fallthrough and no other need for the cleanup,
Expand All @@ -781,6 +803,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}

destroyOptimisticNormalEntry(*this, Scope);
Scope.MarkEmitted();
EHStack.popCleanup();

EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
Expand Down Expand Up @@ -916,6 +939,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}

// IV. Pop the cleanup and emit it.
Scope.MarkEmitted();
EHStack.popCleanup();
assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups);

Expand Down Expand Up @@ -984,6 +1008,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}
}

if (NormalDeactivateOrigIP.isSet())
Builder.restoreIP(NormalDeactivateOrigIP);
assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0);

// Emit the EH cleanup if required.
Expand Down Expand Up @@ -1143,25 +1169,6 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
Builder.ClearInsertionPoint();
}

static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack,
EHScopeStack::stable_iterator C) {
// If we needed a normal block for any reason, that counts.
if (cast<EHCleanupScope>(*EHStack.find(C)).getNormalBlock())
return true;

// Check whether any enclosed cleanups were needed.
for (EHScopeStack::stable_iterator
I = EHStack.getInnermostNormalCleanup();
I != C; ) {
assert(C.strictlyEncloses(I));
EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I));
if (S.getNormalBlock()) return true;
I = S.getEnclosingNormalCleanup();
}

return false;
}

static bool IsUsedAsEHCleanup(EHScopeStack &EHStack,
EHScopeStack::stable_iterator cleanup) {
// If we needed an EH block for any reason, that counts.
Expand Down Expand Up @@ -1210,8 +1217,7 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF,
// Calculate whether the cleanup was used:

// - as a normal cleanup
if (Scope.isNormalCleanup() &&
(isActivatedInConditional || IsUsedAsNormalCleanup(CGF.EHStack, C))) {
if (Scope.isNormalCleanup()) {
Scope.setTestFlagInNormalCleanup();
needFlag = true;
}
Expand All @@ -1224,13 +1230,16 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF,
}

// If it hasn't yet been used as either, we're done.
if (!needFlag) return;
if (!needFlag)
return;

Address var = Scope.getActiveFlag();
if (!var.isValid()) {
CodeGenFunction::AllocaTrackerRAII AllocaTracker(CGF);
var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), CharUnits::One(),
"cleanup.isactive");
Scope.setActiveFlag(var);
Scope.AddAuxAllocas(AllocaTracker.Take());

assert(dominatingIP && "no existing variable and no dominating IP!");

Expand Down Expand Up @@ -1273,17 +1282,8 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C,
// to the current RunCleanupsScope.
if (C == EHStack.stable_begin() &&
CurrentCleanupScopeDepth.strictlyEncloses(C)) {
// Per comment below, checking EHAsynch is not really necessary
// it's there to assure zero-impact w/o EHAsynch option
if (!Scope.isNormalCleanup() && getLangOpts().EHAsynch) {
PopCleanupBlock();
} else {
// If it's a normal cleanup, we need to pretend that the
// fallthrough is unreachable.
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
PopCleanupBlock();
Builder.restoreIP(SavedIP);
}
PopCleanupBlock(/*FallthroughIsBranchThrough=*/false,
/*ForDeactivation=*/true);
return;
}

Expand Down
57 changes: 56 additions & 1 deletion clang/lib/CodeGen/CGCleanup.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
#include "EHScopeStack.h"

#include "Address.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Instruction.h"

namespace llvm {
class BasicBlock;
Expand Down Expand Up @@ -266,6 +269,51 @@ class alignas(8) EHCleanupScope : public EHScope {
};
mutable struct ExtInfo *ExtInfo;

/// Erases auxillary allocas and their usages for an unused cleanup.
/// Cleanups should mark these allocas as 'used' if the cleanup is
/// emitted, otherwise these instructions would be erased.
struct AuxillaryAllocas {
SmallVector<llvm::Instruction *, 1> AuxAllocas;
bool used = false;

// Records a potentially unused instruction to be erased later.
void Add(llvm::AllocaInst *Alloca) { AuxAllocas.push_back(Alloca); }

// Mark all recorded instructions as used. These will not be erased later.
void MarkUsed() {
used = true;
AuxAllocas.clear();
}

~AuxillaryAllocas() {
if (used)
return;
llvm::SetVector<llvm::Instruction *> Uses;
for (auto *Inst : llvm::reverse(AuxAllocas))
CollectUses(Inst, Uses);
// Delete uses in the reverse order of insertion.
for (auto *I : llvm::reverse(Uses))
I->eraseFromParent();
}

private:
void CollectUses(llvm::Instruction *I,
llvm::SetVector<llvm::Instruction *> &Uses) {
if (!I || !Uses.insert(I))
return;
for (auto *User : I->users())
CollectUses(cast<llvm::Instruction>(User), Uses);
}
};
mutable struct AuxillaryAllocas *AuxAllocas;

AuxillaryAllocas &getAuxillaryAllocas() {
if (!AuxAllocas) {
AuxAllocas = new struct AuxillaryAllocas();
}
return *AuxAllocas;
}

/// The number of fixups required by enclosing scopes (not including
/// this one). If this is the top cleanup scope, all the fixups
/// from this index onwards belong to this scope.
Expand Down Expand Up @@ -298,7 +346,7 @@ class alignas(8) EHCleanupScope : public EHScope {
EHScopeStack::stable_iterator enclosingEH)
: EHScope(EHScope::Cleanup, enclosingEH),
EnclosingNormal(enclosingNormal), NormalBlock(nullptr),
ActiveFlag(Address::invalid()), ExtInfo(nullptr),
ActiveFlag(Address::invalid()), ExtInfo(nullptr), AuxAllocas(nullptr),
FixupDepth(fixupDepth) {
CleanupBits.IsNormalCleanup = isNormal;
CleanupBits.IsEHCleanup = isEH;
Expand All @@ -312,8 +360,15 @@ class alignas(8) EHCleanupScope : public EHScope {
}

void Destroy() {
if (AuxAllocas)
delete AuxAllocas;
delete ExtInfo;
}
void AddAuxAllocas(llvm::SmallVector<llvm::AllocaInst *> Allocas) {
for (auto *Alloca : Allocas)
getAuxillaryAllocas().Add(Alloca);
}
void MarkEmitted() { getAuxillaryAllocas().MarkUsed(); }
// Objects of EHCleanupScope are not destructed. Use Destroy().
~EHCleanupScope() = delete;

Expand Down
87 changes: 59 additions & 28 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "EHScopeStack.h"
#include "PatternInit.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
Expand All @@ -35,6 +36,7 @@
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
#include <optional>
Expand Down Expand Up @@ -2201,6 +2203,27 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr,
destroyer, useEHCleanupForArray);
}

// Pushes a destroy and defers its deactivation until its
// CleanupDeactivationScope is exited.
void CodeGenFunction::pushDestroyAndDeferDeactivation(
QualType::DestructionKind dtorKind, Address addr, QualType type) {
assert(dtorKind && "cannot push destructor for trivial type");

CleanupKind cleanupKind = getCleanupKind(dtorKind);
pushDestroyAndDeferDeactivation(
cleanupKind, addr, type, getDestroyer(dtorKind), cleanupKind & EHCleanup);
}

void CodeGenFunction::pushDestroyAndDeferDeactivation(
CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray) {
llvm::Instruction *DominatingIP =
Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
pushDestroy(cleanupKind, addr, type, destroyer, useEHCleanupForArray);
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
}

void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) {
EHStack.pushCleanup<CallStackRestore>(Kind, SPMem);
}
Expand All @@ -2217,39 +2240,48 @@ void CodeGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind,
// If we're not in a conditional branch, we don't need to bother generating a
// conditional cleanup.
if (!isInConditionalBranch()) {
// Push an EH-only cleanup for the object now.
// FIXME: When popping normal cleanups, we need to keep this EH cleanup
// around in case a temporary's destructor throws an exception.
if (cleanupKind & EHCleanup)
EHStack.pushCleanup<DestroyObject>(
static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), addr, type,
destroyer, useEHCleanupForArray);

// Add the cleanup to the EHStack. After the full-expr, this would be
// deactivated before being popped from the stack.
pushDestroyAndDeferDeactivation(cleanupKind, addr, type, destroyer,
useEHCleanupForArray);

// Since this is lifetime-extended, push it once again to the EHStack after
// the full expression.
return pushCleanupAfterFullExprWithActiveFlag<DestroyObject>(
cleanupKind, Address::invalid(), addr, type, destroyer, useEHCleanupForArray);
cleanupKind, Address::invalid(), addr, type, destroyer,
useEHCleanupForArray);
}

// Otherwise, we should only destroy the object if it's been initialized.
// Re-use the active flag and saved address across both the EH and end of
// scope cleanups.

using SavedType = typename DominatingValue<Address>::saved_type;
using ConditionalCleanupType =
EHScopeStack::ConditionalCleanup<DestroyObject, Address, QualType,
Destroyer *, bool>;

Address ActiveFlag = createCleanupActiveFlag();
SavedType SavedAddr = saveValueInCond(addr);

if (cleanupKind & EHCleanup) {
EHStack.pushCleanup<ConditionalCleanupType>(
static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), SavedAddr, type,
destroyer, useEHCleanupForArray);
initFullExprCleanupWithFlag(ActiveFlag);
}

DominatingValue<Address>::saved_type SavedAddr = saveValueInCond(addr);

// Remember to emit cleanup if we branch-out before end of full-expression
// (eg: through stmt-expr or coro suspensions).
AllocaTrackerRAII DeactivationAllocas(*this);
Address ActiveFlagForDeactivation = createCleanupActiveFlag();

pushCleanupAndDeferDeactivation<ConditionalCleanupType>(
cleanupKind, SavedAddr, type, destroyer, useEHCleanupForArray);
initFullExprCleanupWithFlag(ActiveFlagForDeactivation);
EHCleanupScope &cleanup = cast<EHCleanupScope>(*EHStack.begin());
// Erase the active flag if the cleanup was not emitted.
cleanup.AddAuxAllocas(std::move(DeactivationAllocas).Take());

// Since this is lifetime-extended, push it once again to the EHStack after
// the full expression.
// The previous active flag would always be 'false' due to forced deferred
// deactivation. Use a separate flag for lifetime-extension to correctly
// remember if this branch was taken and the object was initialized.
Address ActiveFlagForLifetimeExt = createCleanupActiveFlag();
pushCleanupAfterFullExprWithActiveFlag<ConditionalCleanupType>(
cleanupKind, ActiveFlag, SavedAddr, type, destroyer,
cleanupKind, ActiveFlagForLifetimeExt, SavedAddr, type, destroyer,
useEHCleanupForArray);
}

Expand Down Expand Up @@ -2442,9 +2474,9 @@ namespace {
};
} // end anonymous namespace

/// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy
/// already-constructed elements of the given array. The cleanup
/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
/// pushIrregularPartialArrayCleanup - Push a NormalAndEHCleanup to
/// destroy already-constructed elements of the given array. The cleanup may be
/// popped with DeactivateCleanupBlock or PopCleanupBlock.
///
/// \param elementType - the immediate element type of the array;
/// possibly still an array type
Expand All @@ -2453,10 +2485,9 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
QualType elementType,
CharUnits elementAlign,
Destroyer *destroyer) {
pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEndPointer,
elementType, elementAlign,
destroyer);
pushFullExprCleanup<IrregularPartialArrayDestroy>(
NormalAndEHCleanup, arrayBegin, arrayEndPointer, elementType,
elementAlign, destroyer);
}

/// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,16 @@ RawAddress CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
const Twine &Name,
llvm::Value *ArraySize) {
llvm::AllocaInst *Alloca;
if (ArraySize)
return Builder.CreateAlloca(Ty, ArraySize, Name);
return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
ArraySize, Name, AllocaInsertPt);
Alloca = Builder.CreateAlloca(Ty, ArraySize, Name);
else
Alloca = new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
ArraySize, Name, AllocaInsertPt);
if (Allocas) {
Allocas->Add(Alloca);
}
return Alloca;
}

/// CreateDefaultAlignTempAlloca - This creates an alloca with the
Expand Down
87 changes: 26 additions & 61 deletions clang/lib/CodeGen/CGExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#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 @@ -24,6 +25,7 @@
#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 @@ -558,24 +560,27 @@ 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();
EHScopeStack::stable_iterator cleanup;
llvm::Instruction *cleanupDominator = nullptr;
if (CGF.needsEHCleanup(dtorKind)) {
CodeGenFunction::CleanupDeactivationScope deactivation(CGF);

if (dtorKind) {
CodeGenFunction::AllocaTrackerRAII allocaTracker(CGF);
// 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");
cleanupDominator = Builder.CreateStore(begin, endOfInit);
Builder.CreateStore(begin, endOfInit);
CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
elementAlign,
CGF.getDestroyer(dtorKind));
cleanup = CGF.EHStack.stable_begin();
cast<EHCleanupScope>(*CGF.EHStack.find(CGF.EHStack.stable_begin()))
.AddAuxAllocas(allocaTracker.Take());

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

llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
Expand Down Expand Up @@ -671,9 +676,6 @@ 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 @@ -1374,9 +1376,8 @@ 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.
SmallVector<EHScopeStack::stable_iterator, 16> Cleanups;
llvm::Instruction *CleanupDominator = nullptr;
// initializers throws an exception or contains branch out of the expressions.
CodeGenFunction::CleanupDeactivationScope scope(CGF);

CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(),
Expand All @@ -1395,28 +1396,12 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
if (QualType::DestructionKind DtorKind =
CurField->getType().isDestructedType()) {
assert(LV.isSimple());
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());
}
if (DtorKind)
CGF.pushDestroyAndDeferDeactivation(
NormalAndEHCleanup, LV.getAddress(CGF), CurField->getType(),
CGF.getDestroyer(DtorKind), false);
}
}

// 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 @@ -1705,14 +1690,7 @@ 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;
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());
};
CodeGenFunction::CleanupDeactivationScope DeactivateCleanups(CGF);

unsigned curInitIndex = 0;

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

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

Expand Down Expand Up @@ -1815,10 +1791,10 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
if (QualType::DestructionKind dtorKind
= field->getType().isDestructedType()) {
assert(LV.isSimple());
if (CGF.needsEHCleanup(dtorKind)) {
CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), field->getType(),
CGF.getDestroyer(dtorKind), false);
addCleanup(CGF.EHStack.stable_begin());
if (dtorKind) {
CGF.pushDestroyAndDeferDeactivation(
NormalAndEHCleanup, LV.getAddress(CGF), field->getType(),
CGF.getDestroyer(dtorKind), false);
pushedCleanup = true;
}
}
Expand All @@ -1831,17 +1807,6 @@ 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();
EHScopeStack::stable_iterator Cleanup;
llvm::Instruction *CleanupDominator = nullptr;
CleanupDeactivationScope deactivation(*this);
bool pushedCleanup = false;

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

// Enter a partial-destruction Cleanup if necessary.
if (needsEHCleanup(DtorKind)) {
if (DtorKind) {
AllocaTrackerRAII AllocaTracker(*this);
// 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));
Cleanup = EHStack.stable_begin();
cast<EHCleanupScope>(*EHStack.find(EHStack.stable_begin()))
.AddAuxAllocas(AllocaTracker.Take());
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
pushedCleanup = true;
}

CharUnits StartAlign = CurPtr.getAlignment();
Expand Down Expand Up @@ -1164,9 +1169,6 @@ 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 @@ -1281,24 +1283,22 @@ void CodeGenFunction::EmitNewArrayInitializer(
Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit);

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

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

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

// Advance to the next element by adjusting the pointer type as necessary.
llvm::Value *NextPtr = Builder.CreateConstInBoundsGEP1_32(
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2330,7 +2330,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}

// Perform VLAT <-> VLST bitcast through memory.
// TODO: since the llvm.experimental.vector.{insert,extract} intrinsics
// TODO: since the llvm.vector.{insert,extract} intrinsics
// require the element types of the vectors to be the same, we
// need to keep this around for bitcasts between VLAT <-> VLST where
// the element types of the vectors are not the same, until we figure
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/CodeGen/CGLoopInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,8 +673,6 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
setPipelineDisabled(true);
break;
case LoopHintAttr::UnrollCount:
setUnrollState(LoopAttributes::Disable);
break;
case LoopHintAttr::UnrollAndJamCount:
case LoopHintAttr::VectorizeWidth:
case LoopHintAttr::InterleaveCount:
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ 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 @@ -346,6 +348,10 @@ 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
99 changes: 96 additions & 3 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#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 @@ -670,6 +671,51 @@ 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 @@ -875,6 +921,19 @@ 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 All @@ -898,7 +957,8 @@ class CodeGenFunction : public CodeGenTypeCache {

/// PopCleanupBlock - Will pop the cleanup entry on the stack and
/// process all branch fixups.
void PopCleanupBlock(bool FallThroughIsBranchThrough = false);
void PopCleanupBlock(bool FallThroughIsBranchThrough = false,
bool ForDeactivation = false);

/// DeactivateCleanupBlock - Deactivates the given cleanup block.
/// The block cannot be reactivated. Pops it if it's the top of the
Expand Down Expand Up @@ -926,6 +986,7 @@ class CodeGenFunction : public CodeGenTypeCache {
class RunCleanupsScope {
EHScopeStack::stable_iterator CleanupStackDepth, OldCleanupScopeDepth;
size_t LifetimeExtendedCleanupStackSize;
CleanupDeactivationScope DeactivateCleanups;
bool OldDidCallStackSave;
protected:
bool PerformCleanup;
Expand All @@ -940,8 +1001,7 @@ class CodeGenFunction : public CodeGenTypeCache {
public:
/// Enter a new cleanup scope.
explicit RunCleanupsScope(CodeGenFunction &CGF)
: PerformCleanup(true), CGF(CGF)
{
: DeactivateCleanups(CGF), PerformCleanup(true), CGF(CGF) {
CleanupStackDepth = CGF.EHStack.stable_begin();
LifetimeExtendedCleanupStackSize =
CGF.LifetimeExtendedCleanupStack.size();
Expand Down Expand Up @@ -971,6 +1031,7 @@ 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 @@ -2160,6 +2221,11 @@ 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 @@ -2698,6 +2764,33 @@ 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
110 changes: 1 addition & 109 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1191,118 +1191,10 @@ bool tools::addOpenMPRuntime(const Compilation &C, ArgStringList &CmdArgs,
return true;
}

/// Determines if --whole-archive is active in the list of arguments.
static bool isWholeArchivePresent(const ArgList &Args) {
bool WholeArchiveActive = false;
for (auto *Arg : Args.filtered(options::OPT_Wl_COMMA)) {
if (Arg) {
for (StringRef ArgValue : Arg->getValues()) {
if (ArgValue == "--whole-archive")
WholeArchiveActive = true;
if (ArgValue == "--no-whole-archive")
WholeArchiveActive = false;
}
}
}

return WholeArchiveActive;
}

/// Determine if driver is invoked to create a shared object library (-static)
static bool isSharedLinkage(const ArgList &Args) {
return Args.hasArg(options::OPT_shared);
}

/// Determine if driver is invoked to create a static object library (-shared)
static bool isStaticLinkage(const ArgList &Args) {
return Args.hasArg(options::OPT_static);
}

/// Add Fortran runtime libs for MSVC
static void addFortranRuntimeLibsMSVC(const ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) {
unsigned RTOptionID = options::OPT__SLASH_MT;
if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {
RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue())
.Case("static", options::OPT__SLASH_MT)
.Case("static_dbg", options::OPT__SLASH_MTd)
.Case("dll", options::OPT__SLASH_MD)
.Case("dll_dbg", options::OPT__SLASH_MDd)
.Default(options::OPT__SLASH_MT);
}
switch (RTOptionID) {
case options::OPT__SLASH_MT:
CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static.lib");
break;
case options::OPT__SLASH_MTd:
CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.static_dbg.lib");
break;
case options::OPT__SLASH_MD:
CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic.lib");
break;
case options::OPT__SLASH_MDd:
CmdArgs.push_back("/WHOLEARCHIVE:Fortran_main.dynamic_dbg.lib");
break;
}
}

// Add FortranMain runtime lib
static void addFortranMain(const ToolChain &TC, const ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) {
// 0. Shared-library linkage
// If we are attempting to link a library, we should not add
// -lFortran_main.a to the link line, as the `main` symbol is not
// required for a library and should also be provided by one of
// the translation units of the code that this shared library
// will be linked against eventually.
if (isSharedLinkage(Args) || isStaticLinkage(Args)) {
return;
}

// 1. MSVC
if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
addFortranRuntimeLibsMSVC(Args, CmdArgs);
return;
}

// 2. GNU and similar
const Driver &D = TC.getDriver();
const char *FortranMainLinkFlag = "-lFortran_main";

// Warn if the user added `-lFortran_main` - this library is an implementation
// detail of Flang and should be handled automaticaly by the driver.
for (const char *arg : CmdArgs) {
if (strncmp(arg, FortranMainLinkFlag, strlen(FortranMainLinkFlag)) == 0)
D.Diag(diag::warn_drv_deprecated_custom)
<< FortranMainLinkFlag
<< "see the Flang driver documentation for correct usage";
}

// The --whole-archive option needs to be part of the link line to make
// sure that the main() function from Fortran_main.a is pulled in by the
// linker. However, it shouldn't be used if it's already active.
// TODO: Find an equivalent of `--whole-archive` for Darwin and AIX.
if (!isWholeArchivePresent(Args) && !TC.getTriple().isMacOSX() &&
!TC.getTriple().isOSAIX()) {
CmdArgs.push_back("--whole-archive");
CmdArgs.push_back(FortranMainLinkFlag);
CmdArgs.push_back("--no-whole-archive");
return;
}

CmdArgs.push_back(FortranMainLinkFlag);
}

/// Add Fortran runtime libs
void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) {
// 1. Link FortranMain
// FortranMain depends on FortranRuntime, so needs to be listed first. If
// -fno-fortran-main has been passed, skip linking Fortran_main.a
if (!Args.hasArg(options::OPT_no_fortran_main))
addFortranMain(TC, Args, CmdArgs);

// 2. Link FortranRuntime and FortranDecimal
// Link FortranRuntime and FortranDecimal
// These are handled earlier on Windows by telling the frontend driver to
// add the correct libraries to link against as dependents in the object
// file.
Expand Down
9 changes: 0 additions & 9 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,6 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
assert(TC.getTriple().isKnownWindowsMSVCEnvironment() &&
"can only add VS runtime library on Windows!");
// if -fno-fortran-main has been passed, skip linking Fortran_main.a
bool LinkFortranMain = !Args.hasArg(options::OPT_no_fortran_main);
if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
CmdArgs.push_back(Args.MakeArgString(
"--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins")));
Expand All @@ -300,26 +299,20 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
case options::OPT__SLASH_MT:
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("--dependent-lib=libcmt");
if (LinkFortranMain)
CmdArgs.push_back("--dependent-lib=Fortran_main.static.lib");
CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib");
CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib");
break;
case options::OPT__SLASH_MTd:
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("--dependent-lib=libcmtd");
if (LinkFortranMain)
CmdArgs.push_back("--dependent-lib=Fortran_main.static_dbg.lib");
CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib");
CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib");
break;
case options::OPT__SLASH_MD:
CmdArgs.push_back("-D_MT");
CmdArgs.push_back("-D_DLL");
CmdArgs.push_back("--dependent-lib=msvcrt");
if (LinkFortranMain)
CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic.lib");
CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib");
CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib");
break;
Expand All @@ -328,8 +321,6 @@ static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back("-D_DEBUG");
CmdArgs.push_back("-D_DLL");
CmdArgs.push_back("--dependent-lib=msvcrtd");
if (LinkFortranMain)
CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib");
CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib");
CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib");
break;
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Driver/ToolChains/Gnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1796,9 +1796,7 @@ selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch,
}
auto &MLConfigISAInfo = *MLConfigParseResult;

const llvm::RISCVISAInfo::OrderedExtensionMap &MLConfigArchExts =
MLConfigISAInfo->getExtensions();
for (auto MLConfigArchExt : MLConfigArchExts) {
for (auto &MLConfigArchExt : MLConfigISAInfo->getExtensions()) {
auto ExtName = MLConfigArchExt.first;
NewMultilib.flag(Twine("-", ExtName).str());

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3116,6 +3116,7 @@ static void sortCppIncludes(const FormatStyle &Style,
return;
}

const auto OldCursor = Cursor ? *Cursor : 0;
std::string result;
for (unsigned Index : Indices) {
if (!result.empty()) {
Expand All @@ -3139,6 +3140,8 @@ static void sortCppIncludes(const FormatStyle &Style,
// the entire range of blocks. Otherwise, no replacement is generated.
if (replaceCRLF(result) == replaceCRLF(std::string(Code.substr(
IncludesBeginOffset, IncludesBlockSize)))) {
if (Cursor)
*Cursor = OldCursor;
return;
}

Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -1623,10 +1623,10 @@ struct AdditionalKeywords {
IdentifierInfo *kw_then;

/// Returns \c true if \p Tok is a keyword or an identifier.
bool isWordLike(const FormatToken &Tok) const {
bool isWordLike(const FormatToken &Tok, bool IsVerilog = true) const {
// getIdentifierinfo returns non-null for keywords as well as identifiers.
return Tok.Tok.getIdentifierInfo() &&
!Tok.isOneOf(kw_verilogHash, kw_verilogHashHash, kw_apostrophe);
(!IsVerilog || !isVerilogKeywordSymbol(Tok));
}

/// Returns \c true if \p Tok is a true JavaScript identifier, returns
Expand Down Expand Up @@ -1755,6 +1755,10 @@ struct AdditionalKeywords {
}
}

bool isVerilogKeywordSymbol(const FormatToken &Tok) const {
return Tok.isOneOf(kw_verilogHash, kw_verilogHashHash, kw_apostrophe);
}

bool isVerilogWordOperator(const FormatToken &Tok) const {
return Tok.isOneOf(kw_before, kw_intersect, kw_dist, kw_iff, kw_inside,
kw_with);
Expand Down
39 changes: 15 additions & 24 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4780,9 +4780,14 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Left.Finalized)
return Right.hasWhitespaceBefore();

const bool IsVerilog = Style.isVerilog();
assert(!IsVerilog || !IsCpp);

// Never ever merge two words.
if (Keywords.isWordLike(Right) && Keywords.isWordLike(Left))
if (Keywords.isWordLike(Right, IsVerilog) &&
Keywords.isWordLike(Left, IsVerilog)) {
return true;
}

// Leave a space between * and /* to avoid C4138 `comment end` found outside
// of comment.
Expand Down Expand Up @@ -4834,10 +4839,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Right.is(TT_TemplateOpener)) {
return true;
}
if (Left.is(tok::identifier) && Right.is(tok::numeric_constant) &&
Right.TokenText[0] == '.') {
return false;
}
if (Left.Tok.getIdentifierInfo() && Right.is(tok::numeric_constant))
return Right.TokenText[0] != '.';
} else if (Style.isProto()) {
if (Right.is(tok::period) &&
Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
Expand Down Expand Up @@ -5065,12 +5068,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Right.is(TT_TemplateOpener)) {
return true;
}
} else if (Style.isVerilog()) {
} else if (IsVerilog) {
// An escaped identifier ends with whitespace.
if (Style.isVerilog() && Left.is(tok::identifier) &&
Left.TokenText[0] == '\\') {
if (Left.is(tok::identifier) && Left.TokenText[0] == '\\')
return true;
}
// Add space between things in a primitive's state table unless in a
// transition like `(0?)`.
if ((Left.is(TT_VerilogTableItem) &&
Expand Down Expand Up @@ -5266,21 +5267,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return true;
}
if (Left.is(TT_UnaryOperator)) {
if (Right.isNot(tok::l_paren)) {
// The alternative operators for ~ and ! are "compl" and "not".
// If they are used instead, we do not want to combine them with
// the token to the right, unless that is a left paren.
if (Left.is(tok::exclaim) && Left.TokenText == "not")
return true;
if (Left.is(tok::tilde) && Left.TokenText == "compl")
return true;
// Lambda captures allow for a lone &, so "&]" needs to be properly
// handled.
if (Left.is(tok::amp) && Right.is(tok::r_square))
return Style.SpacesInSquareBrackets;
}
return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) ||
Right.is(TT_BinaryOperator);
// Lambda captures allow for a lone &, so "&]" needs to be properly
// handled.
if (Left.is(tok::amp) && Right.is(tok::r_square))
return Style.SpacesInSquareBrackets;
return Style.SpaceAfterLogicalNot && Left.is(tok::exclaim);
}

// If the next token is a binary operator or a selector name, we have
Expand Down
42 changes: 21 additions & 21 deletions clang/lib/Format/WhitespaceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,14 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() {
void WhitespaceManager::calculateLineBreakInformation() {
Changes[0].PreviousEndOfTokenColumn = 0;
Change *LastOutsideTokenChange = &Changes[0];
for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
for (unsigned I = 1, e = Changes.size(); I != e; ++I) {
auto &C = Changes[I];
auto &P = Changes[I - 1];
auto &PrevTokLength = P.TokenLength;
SourceLocation OriginalWhitespaceStart =
Changes[i].OriginalWhitespaceRange.getBegin();
C.OriginalWhitespaceRange.getBegin();
SourceLocation PreviousOriginalWhitespaceEnd =
Changes[i - 1].OriginalWhitespaceRange.getEnd();
P.OriginalWhitespaceRange.getEnd();
unsigned OriginalWhitespaceStartOffset =
SourceMgr.getFileOffset(OriginalWhitespaceStart);
unsigned PreviousOriginalWhitespaceEndOffset =
Expand Down Expand Up @@ -167,31 +170,28 @@ void WhitespaceManager::calculateLineBreakInformation() {
// line of the token.
auto NewlinePos = Text.find_first_of('\n');
if (NewlinePos == StringRef::npos) {
Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset -
PreviousOriginalWhitespaceEndOffset +
Changes[i].PreviousLinePostfix.size() +
Changes[i - 1].CurrentLinePrefix.size();
PrevTokLength = OriginalWhitespaceStartOffset -
PreviousOriginalWhitespaceEndOffset +
C.PreviousLinePostfix.size() + P.CurrentLinePrefix.size();
if (!P.IsInsideToken)
PrevTokLength = std::min(PrevTokLength, P.Tok->ColumnWidth);
} else {
Changes[i - 1].TokenLength =
NewlinePos + Changes[i - 1].CurrentLinePrefix.size();
PrevTokLength = NewlinePos + P.CurrentLinePrefix.size();
}

// If there are multiple changes in this token, sum up all the changes until
// the end of the line.
if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0) {
LastOutsideTokenChange->TokenLength +=
Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
} else {
LastOutsideTokenChange = &Changes[i - 1];
}
if (P.IsInsideToken && P.NewlinesBefore == 0)
LastOutsideTokenChange->TokenLength += PrevTokLength + P.Spaces;
else
LastOutsideTokenChange = &P;

Changes[i].PreviousEndOfTokenColumn =
Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
C.PreviousEndOfTokenColumn = P.StartOfTokenColumn + PrevTokLength;

Changes[i - 1].IsTrailingComment =
(Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) ||
(Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) &&
Changes[i - 1].Tok->is(tok::comment) &&
P.IsTrailingComment =
(C.NewlinesBefore > 0 || C.Tok->is(tok::eof) ||
(C.IsInsideToken && C.Tok->is(tok::comment))) &&
P.Tok->is(tok::comment) &&
// FIXME: This is a dirty hack. The problem is that
// BreakableLineCommentSection does comment reflow changes and here is
// the aligning of trailing comments. Consider the case where we reflow
Expand Down
12 changes: 11 additions & 1 deletion clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_nested_namespace_definitions", "201411L");
Builder.defineMacro("__cpp_variadic_using", "201611L");
Builder.defineMacro("__cpp_aggregate_bases", "201603L");
Builder.defineMacro("__cpp_structured_bindings", "201606L");
Builder.defineMacro("__cpp_structured_bindings", "202403L");
Builder.defineMacro("__cpp_nontype_template_args",
"201411L"); // (not latest)
Builder.defineMacro("__cpp_fold_expressions", "201603L");
Expand Down Expand Up @@ -1308,6 +1308,16 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
}

// GCC defines these macros in both C and C++ modes despite them being needed
// mostly for STL implementations in C++.
auto [Destructive, Constructive] = TI.hardwareInterferenceSizes();
Builder.defineMacro("__GCC_DESTRUCTIVE_SIZE", Twine(Destructive));
Builder.defineMacro("__GCC_CONSTRUCTIVE_SIZE", Twine(Constructive));
// We need to use push_macro to allow users to redefine these macros from the
// command line with -D and not issue a -Wmacro-redefined warning.
Builder.append("#pragma push_macro(\"__GCC_DESTRUCTIVE_SIZE\")");
Builder.append("#pragma push_macro(\"__GCC_CONSTRUCTIVE_SIZE\")");

auto addLockFreeMacros = [&](const llvm::Twine &Prefix) {
// Used by libc++ and libstdc++ to implement ATOMIC_<foo>_LOCK_FREE.
#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Headers/cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#ifndef __CPUID_H
#define __CPUID_H

#if !(__x86_64__ || __i386__)
#if !defined(__x86_64__) && !defined(__i386__)
#error this header is for x86 only
#endif

Expand Down Expand Up @@ -256,7 +256,7 @@
#define bit_AVX10_256 0x00020000
#define bit_AVX10_512 0x00040000

#if __i386__
#ifdef __i386__
#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \
__asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
: "0"(__leaf))
Expand Down Expand Up @@ -285,7 +285,7 @@ static __inline unsigned int __get_cpuid_max (unsigned int __leaf,
unsigned int *__sig)
{
unsigned int __eax, __ebx, __ecx, __edx;
#if __i386__
#ifdef __i386__
int __cpuid_supported;

__asm(" pushfl\n"
Expand Down
43 changes: 32 additions & 11 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2998,7 +2998,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
<< TokenName << TagName << getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(Tok.getLocation(), FixitTagName);

if (Actions.LookupName(R, getCurScope())) {
if (Actions.LookupParsedName(R, getCurScope(), SS)) {
for (LookupResult::iterator I = R.begin(), IEnd = R.end();
I != IEnd; ++I)
Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type)
Expand Down Expand Up @@ -7038,18 +7038,23 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
void Parser::ParseDecompositionDeclarator(Declarator &D) {
assert(Tok.is(tok::l_square));

TentativeParsingAction PA(*this);
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();

if (isCXX11AttributeSpecifier())
DiagnoseAndSkipCXX11Attributes();

// If this doesn't look like a structured binding, maybe it's a misplaced
// array declarator.
// FIXME: Consume the l_square first so we don't need extra lookahead for
// this.
if (!(NextToken().is(tok::identifier) &&
GetLookAheadToken(2).isOneOf(tok::comma, tok::r_square)) &&
!(NextToken().is(tok::r_square) &&
GetLookAheadToken(2).isOneOf(tok::equal, tok::l_brace)))
if (!(Tok.is(tok::identifier) &&
NextToken().isOneOf(tok::comma, tok::r_square, tok::kw_alignas,
tok::l_square)) &&
!(Tok.is(tok::r_square) &&
NextToken().isOneOf(tok::equal, tok::l_brace))) {
PA.Revert();
return ParseMisplacedBracketDeclarator(D);

BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
}

SmallVector<DecompositionDeclarator::Binding, 32> Bindings;
while (Tok.isNot(tok::r_square)) {
Expand All @@ -7074,13 +7079,27 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
}
}

if (isCXX11AttributeSpecifier())
DiagnoseAndSkipCXX11Attributes();

if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected) << tok::identifier;
break;
}

Bindings.push_back({Tok.getIdentifierInfo(), Tok.getLocation()});
IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation Loc = Tok.getLocation();
ConsumeToken();

ParsedAttributes Attrs(AttrFactory);
if (isCXX11AttributeSpecifier()) {
Diag(Tok, getLangOpts().CPlusPlus26
? diag::warn_cxx23_compat_decl_attrs_on_binding
: diag::ext_decl_attrs_on_binding);
MaybeParseCXX11Attributes(Attrs);
}

Bindings.push_back({II, Loc, std::move(Attrs)});
}

if (Tok.isNot(tok::r_square))
Expand All @@ -7095,6 +7114,8 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) {
T.consumeClose();
}

PA.Commit();

return D.setDecompositionBindings(T.getOpenLocation(), Bindings,
T.getCloseLocation());
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/DeclSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,

void Declarator::setDecompositionBindings(
SourceLocation LSquareLoc,
ArrayRef<DecompositionDeclarator::Binding> Bindings,
MutableArrayRef<DecompositionDeclarator::Binding> Bindings,
SourceLocation RSquareLoc) {
assert(!hasName() && "declarator given multiple names!");

Expand All @@ -317,7 +317,7 @@ void Declarator::setDecompositionBindings(
new DecompositionDeclarator::Binding[Bindings.size()];
BindingGroup.DeleteBindings = true;
}
std::uninitialized_copy(Bindings.begin(), Bindings.end(),
std::uninitialized_move(Bindings.begin(), Bindings.end(),
BindingGroup.Bindings);
}
}
Expand Down
7 changes: 2 additions & 5 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,12 @@ struct BuiltinTypeDeclBuilder {

static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
StringRef Name) {
CXXScopeSpec SS;
IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
DeclarationNameInfo NameInfo =
DeclarationNameInfo(DeclarationName(&II), SourceLocation());
LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
// AllowBuiltinCreation is false but LookupDirect will create
// the builtin when searching the global scope anyways...
S.LookupName(R, S.getCurScope());
// FIXME: If the builtin function was user-declared in global scope,
// this assert *will* fail. Should this call LookupBuiltin instead?
S.LookupParsedName(R, S.getCurScope(), &SS, false);
assert(R.isSingleResult() &&
"Since this is a builtin it should always resolve!");
auto *VD = cast<ValueDecl>(R.getFoundDecl());
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaAPINotes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,11 @@ static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
D->addAttr(
SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value()));

if (auto Copyable = Info.isSwiftCopyable()) {
if (!*Copyable)
D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable"));
}

if (auto Extensibility = Info.EnumExtensibility) {
using api_notes::EnumExtensibilityKind;
bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,

IdentifierInfo *Name = IdTok.getIdentifierInfo();
LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
LookupName(Lookup, curScope, /*AllowBuiltinCreation=*/true);
LookupParsedName(Lookup, curScope, nullptr, true);

if (Lookup.empty()) {
Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
Expand Down
34 changes: 30 additions & 4 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3164,13 +3164,20 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,

const Expr *Arg = TheCall->getArg(0);
const auto *TyA = Arg->getType()->getAs<VectorType>();
if (!TyA) {

QualType ElTy;
if (TyA)
ElTy = TyA->getElementType();
else if (Arg->getType()->isSizelessVectorType())
ElTy = Arg->getType()->getSizelessVectorEltType(Context);

if (ElTy.isNull()) {
Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< 1 << /* vector ty*/ 4 << Arg->getType();
return ExprError();
}

TheCall->setType(TyA->getElementType());
TheCall->setType(ElTy);
break;
}

Expand All @@ -3186,12 +3193,20 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,

const Expr *Arg = TheCall->getArg(0);
const auto *TyA = Arg->getType()->getAs<VectorType>();
if (!TyA || !TyA->getElementType()->isIntegerType()) {

QualType ElTy;
if (TyA)
ElTy = TyA->getElementType();
else if (Arg->getType()->isSizelessVectorType())
ElTy = Arg->getType()->getSizelessVectorEltType(Context);

if (ElTy.isNull() || !ElTy->isIntegerType()) {
Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
<< 1 << /* vector of integers */ 6 << Arg->getType();
return ExprError();
}
TheCall->setType(TyA->getElementType());

TheCall->setType(ElTy);
break;
}

Expand Down Expand Up @@ -12544,6 +12559,17 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
return true;
}

// Diagnose attempts to use '%P' with ObjC object types, which will result in
// dumping raw class data (like is-a pointer), not actual data.
if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::PArg &&
ExprTy->isObjCObjectPointerType()) {
const CharSourceRange &CSR =
getSpecifierRange(StartSpecifier, SpecifierLen);
EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_with_objc_pointer),
E->getExprLoc(), false, CSR);
return true;
}

ArgType::MatchKind ImplicitMatch = ArgType::NoMatch;
ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
ArgType::MatchKind OrigMatch = Match;
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
IdentifierInfo *&Name,
SourceLocation NameLoc) {
LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName);
SemaRef.LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
SemaRef.LookupParsedName(R, S, &SS);
if (TagDecl *Tag = R.getAsSingle<TagDecl>()) {
StringRef FixItTagName;
switch (Tag->getTagKind()) {
Expand Down Expand Up @@ -869,7 +869,7 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,

// Replace lookup results with just the tag decl.
Result.clear(Sema::LookupTagName);
SemaRef.LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType());
SemaRef.LookupParsedName(Result, S, &SS);
return true;
}

Expand All @@ -896,8 +896,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
}

LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
LookupParsedName(Result, S, &SS, /*ObjectType=*/QualType(),
/*AllowBuiltinCreation=*/!CurMethod);
LookupParsedName(Result, S, &SS, !CurMethod);

if (SS.isInvalid())
return NameClassification::Error();
Expand Down Expand Up @@ -1975,7 +1974,7 @@ static bool ShouldDiagnoseUnusedDecl(const LangOptions &LangOpts,
// it is, by the bindings' expressions).
bool IsAllPlaceholders = true;
for (const auto *BD : DD->bindings()) {
if (BD->isReferenced())
if (BD->isReferenced() || BD->hasAttr<UnusedAttr>())
return false;
IsAllPlaceholders = IsAllPlaceholders && BD->isPlaceholderVar(LangOpts);
}
Expand Down
24 changes: 16 additions & 8 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,8 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,

auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, VarName);

ProcessDeclAttributeList(S, BD, *B.Attrs);

// Find the shadowed declaration before filtering for scope.
NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty()
? getShadowedDeclaration(BD, Previous)
Expand Down Expand Up @@ -4517,7 +4519,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
DS.getBeginLoc(), DS.getEllipsisLoc());
} else {
LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
LookupParsedName(R, S, &SS);

TypeDecl *TyD = R.getAsSingle<TypeDecl>();
if (!TyD) {
Expand Down Expand Up @@ -12052,11 +12054,17 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {

Template = Specialization->getSpecializedTemplate();
Arguments = Specialization->getTemplateArgs().data();
} else if (const TemplateSpecializationType *TST =
Ty->getAs<TemplateSpecializationType>()) {
Template = dyn_cast_or_null<ClassTemplateDecl>(
TST->getTemplateName().getAsTemplateDecl());
Arguments = TST->template_arguments().begin();
} else {
const TemplateSpecializationType *TST = nullptr;
if (auto *ICN = Ty->getAs<InjectedClassNameType>())
TST = ICN->getInjectedTST();
else
TST = Ty->getAs<TemplateSpecializationType>();
if (TST) {
Template = dyn_cast_or_null<ClassTemplateDecl>(
TST->getTemplateName().getAsTemplateDecl());
Arguments = TST->template_arguments().begin();
}
}
if (!Template)
return false;
Expand Down Expand Up @@ -12262,7 +12270,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,

// Lookup namespace name.
LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
LookupParsedName(R, S, &SS);
if (R.isAmbiguous())
return nullptr;

Expand Down Expand Up @@ -13721,7 +13729,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,

// Lookup the namespace name.
LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName);
LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
LookupParsedName(R, S, &SS);

if (R.isAmbiguous())
return nullptr;
Expand Down
20 changes: 10 additions & 10 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,9 +673,8 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// expressions of certain types in C++.
if (getLangOpts().CPlusPlus &&
(E->getType() == Context.OverloadTy ||
// FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied
// to pointer types even if the pointee type is dependent.
(T->isDependentType() && !T->isPointerType()) || T->isRecordType()))
T->isDependentType() ||
T->isRecordType()))
return E;

// The C standard is actually really unclear on this point, and
Expand Down Expand Up @@ -2752,8 +2751,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
if (isBoundsAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) {
// See if this is reference to a field of struct.
LookupResult R(*this, NameInfo, LookupMemberName);
// LookupName handles a name lookup from within anonymous struct.
if (LookupName(R, S)) {
// LookupParsedName handles a name lookup from within anonymous struct.
if (LookupParsedName(R, S, &SS)) {
if (auto *VD = dyn_cast<ValueDecl>(R.getFoundDecl())) {
QualType type = VD->getType().getNonReferenceType();
// This will eventually be translated into MemberExpr upon
Expand All @@ -2774,19 +2773,20 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// lookup to determine that it was a template name in the first place. If
// this becomes a performance hit, we can work harder to preserve those
// results until we get here but it's likely not worth it.
bool MemberOfUnknownSpecialization;
AssumedTemplateKind AssumedTemplate;
if (LookupTemplateName(R, S, SS, /*ObjectType=*/QualType(),
/*EnteringContext=*/false, TemplateKWLoc,
if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false,
MemberOfUnknownSpecialization, TemplateKWLoc,
&AssumedTemplate))
return ExprError();

if (R.wasNotFoundInCurrentInstantiation())
if (MemberOfUnknownSpecialization ||
(R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation))
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
IsAddressOfOperand, TemplateArgs);
} else {
bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl();
LookupParsedName(R, S, &SS, /*ObjectType=*/QualType(),
/*AllowBuiltinCreation=*/!IvarLookupFollowUp);
LookupParsedName(R, S, &SS, !IvarLookupFollowUp);

// If the result might be in a dependent base class, this is a dependent
// id-expression.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9157,7 +9157,7 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
// Do the redeclaration lookup in the current scope.
LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName,
RedeclarationKind::NotForRedeclaration);
LookupParsedName(R, S, &SS, /*ObjectType=*/QualType());
LookupParsedName(R, S, &SS);
R.suppressDiagnostics();

switch (R.getResultKind()) {
Expand Down
Loading