355 changes: 191 additions & 164 deletions clang/lib/Analysis/ExprMutationAnalyzer.cpp

Large diffs are not rendered by default.

7 changes: 1 addition & 6 deletions clang/lib/Analysis/PathDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,7 @@
using namespace clang;
using namespace ento;

static StringRef StripTrailingDots(StringRef s) {
for (StringRef::size_type i = s.size(); i != 0; --i)
if (s[i - 1] != '.')
return s.substr(0, i);
return {};
}
static StringRef StripTrailingDots(StringRef s) { return s.rtrim('.'); }

PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
Kind k, DisplayHint hint)
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,

BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement;
BPI.BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
BPI.GuardedControlStack = PBP.GuardedControlStack;
return true;
}

Expand Down Expand Up @@ -532,6 +533,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (Opts.BranchTargetEnforcement)
Builder.defineMacro("__ARM_FEATURE_BTI_DEFAULT", "1");

if (Opts.GuardedControlStack)
Builder.defineMacro("__ARM_FEATURE_GCS_DEFAULT", "1");

if (HasLS64)
Builder.defineMacro("__ARM_FEATURE_LS64", "1");

Expand All @@ -544,6 +548,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasD128)
Builder.defineMacro("__ARM_FEATURE_SYSREG128", "1");

if (HasGCS)
Builder.defineMacro("__ARM_FEATURE_GCS", "1");

if (*ArchInfo == llvm::AArch64::ARMV8_1A)
getTargetDefinesARMV81A(Opts, Builder);
else if (*ArchInfo == llvm::AArch64::ARMV8_2A)
Expand Down
64 changes: 64 additions & 0 deletions clang/lib/Basic/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/TargetParser/ARMTargetParser.h"

using namespace clang;
using namespace clang::targets;
Expand Down Expand Up @@ -837,6 +838,69 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
if (Opts.RWPI)
Builder.defineMacro("__ARM_RWPI", "1");

// Macros for enabling co-proc intrinsics
uint64_t FeatureCoprocBF = 0;
switch (ArchKind) {
default:
break;
case llvm::ARM::ArchKind::ARMV4:
case llvm::ARM::ArchKind::ARMV4T:
// Filter __arm_ldcl and __arm_stcl in acle.h
FeatureCoprocBF = isThumb() ? 0 : FEATURE_COPROC_B1;
break;
case llvm::ARM::ArchKind::ARMV5T:
FeatureCoprocBF = isThumb() ? 0 : FEATURE_COPROC_B1 | FEATURE_COPROC_B2;
break;
case llvm::ARM::ArchKind::ARMV5TE:
case llvm::ARM::ArchKind::ARMV5TEJ:
if (!isThumb())
FeatureCoprocBF =
FEATURE_COPROC_B1 | FEATURE_COPROC_B2 | FEATURE_COPROC_B3;
break;
case llvm::ARM::ArchKind::ARMV6:
case llvm::ARM::ArchKind::ARMV6K:
case llvm::ARM::ArchKind::ARMV6KZ:
case llvm::ARM::ArchKind::ARMV6T2:
if (!isThumb() || ArchKind == llvm::ARM::ArchKind::ARMV6T2)
FeatureCoprocBF = FEATURE_COPROC_B1 | FEATURE_COPROC_B2 |
FEATURE_COPROC_B3 | FEATURE_COPROC_B4;
break;
case llvm::ARM::ArchKind::ARMV7A:
case llvm::ARM::ArchKind::ARMV7R:
case llvm::ARM::ArchKind::ARMV7M:
case llvm::ARM::ArchKind::ARMV7S:
case llvm::ARM::ArchKind::ARMV7EM:
FeatureCoprocBF = FEATURE_COPROC_B1 | FEATURE_COPROC_B2 |
FEATURE_COPROC_B3 | FEATURE_COPROC_B4;
break;
case llvm::ARM::ArchKind::ARMV8A:
case llvm::ARM::ArchKind::ARMV8R:
case llvm::ARM::ArchKind::ARMV8_1A:
case llvm::ARM::ArchKind::ARMV8_2A:
case llvm::ARM::ArchKind::ARMV8_3A:
case llvm::ARM::ArchKind::ARMV8_4A:
case llvm::ARM::ArchKind::ARMV8_5A:
case llvm::ARM::ArchKind::ARMV8_6A:
case llvm::ARM::ArchKind::ARMV8_7A:
case llvm::ARM::ArchKind::ARMV8_8A:
case llvm::ARM::ArchKind::ARMV8_9A:
case llvm::ARM::ArchKind::ARMV9A:
case llvm::ARM::ArchKind::ARMV9_1A:
case llvm::ARM::ArchKind::ARMV9_2A:
case llvm::ARM::ArchKind::ARMV9_3A:
case llvm::ARM::ArchKind::ARMV9_4A:
// Filter __arm_cdp, __arm_ldcl, __arm_stcl in arm_acle.h
FeatureCoprocBF = FEATURE_COPROC_B1 | FEATURE_COPROC_B3;
break;
case llvm::ARM::ArchKind::ARMV8MMainline:
case llvm::ARM::ArchKind::ARMV8_1MMainline:
FeatureCoprocBF = FEATURE_COPROC_B1 | FEATURE_COPROC_B2 |
FEATURE_COPROC_B3 | FEATURE_COPROC_B4;
break;
}
Builder.defineMacro("__ARM_FEATURE_COPROC",
"0x" + Twine::utohexstr(FeatureCoprocBF));

if (ArchKind == llvm::ARM::ArchKind::XSCALE)
Builder.defineMacro("__XSCALE__");

Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Basic/Targets/ARM.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
};
uint32_t HW_FP;

enum {
/// __arm_cdp __arm_ldc, __arm_ldcl, __arm_stc,
/// __arm_stcl, __arm_mcr and __arm_mrc
FEATURE_COPROC_B1 = (1 << 0),
/// __arm_cdp2, __arm_ldc2, __arm_stc2, __arm_ldc2l,
/// __arm_stc2l, __arm_mcr2 and __arm_mrc2
FEATURE_COPROC_B2 = (1 << 1),
/// __arm_mcrr, __arm_mrrc
FEATURE_COPROC_B3 = (1 << 2),
/// __arm_mcrr2, __arm_mrrc2
FEATURE_COPROC_B4 = (1 << 3),
};

void setABIAAPCS();
void setABIAPCS(bool IsAAPCS16);

Expand Down
28 changes: 10 additions & 18 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,8 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
auto ExtName = Extension.first;
auto ExtInfo = Extension.second;

Builder.defineMacro(
Twine("__riscv_", ExtName),
Twine(getVersionValue(ExtInfo.MajorVersion, ExtInfo.MinorVersion)));
Builder.defineMacro(Twine("__riscv_", ExtName),
Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor)));
}

if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul"))
Expand Down Expand Up @@ -237,22 +236,15 @@ ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {

static std::vector<std::string>
collectNonISAExtFeature(ArrayRef<std::string> FeaturesNeedOverride, int XLen) {
auto ParseResult =
llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesNeedOverride);

if (!ParseResult) {
consumeError(ParseResult.takeError());
return std::vector<std::string>();
}

std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();

std::vector<std::string> NonISAExtFeatureVec;

auto IsNonISAExtFeature = [](const std::string &Feature) {
assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-'));
StringRef Ext = StringRef(Feature).drop_front(); // drop the +/-
return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext);
};
llvm::copy_if(FeaturesNeedOverride, std::back_inserter(NonISAExtFeatureVec),
[&](const std::string &Feat) {
return !llvm::is_contained(ImpliedFeatures, Feat);
});
IsNonISAExtFeature);

return NonISAExtFeatureVec;
}
Expand Down Expand Up @@ -303,7 +295,7 @@ bool RISCVTargetInfo::initFeatureMap(
}

// RISCVISAInfo makes implications for ISA features
std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector();
std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatures();

// parseFeatures normalizes the feature set by dropping any explicit
// negatives, and non-extension features. We need to preserve the later
Expand Down Expand Up @@ -420,7 +412,7 @@ static void handleFullArchString(StringRef FullArchStr,
// Forward the invalid FullArchStr.
Features.push_back("+" + FullArchStr.str());
} else {
std::vector<std::string> FeatStrings = (*RII)->toFeatureVector();
std::vector<std::string> FeatStrings = (*RII)->toFeatures();
Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());
}
}
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,13 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasAVX512BF16 = true;
} else if (Feature == "+avx512er") {
HasAVX512ER = true;
Diags.Report(diag::warn_knl_knm_isa_support_removed);
} else if (Feature == "+avx512fp16") {
HasAVX512FP16 = true;
HasLegalHalfType = true;
} else if (Feature == "+avx512pf") {
HasAVX512PF = true;
Diags.Report(diag::warn_knl_knm_isa_support_removed);
} else if (Feature == "+avx512dq") {
HasAVX512DQ = true;
} else if (Feature == "+avx512bitalg") {
Expand Down Expand Up @@ -358,6 +360,7 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasPREFETCHI = true;
} else if (Feature == "+prefetchwt1") {
HasPREFETCHWT1 = true;
Diags.Report(diag::warn_knl_knm_isa_support_removed);
} else if (Feature == "+clzero") {
HasCLZERO = true;
} else if (Feature == "+cldemote") {
Expand Down
244 changes: 242 additions & 2 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/OperationKinds.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
Expand Down Expand Up @@ -818,6 +819,238 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
}

const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
ASTContext &Ctx, const RecordDecl *RD, StringRef Name, uint64_t &Offset) {
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
getLangOpts().getStrictFlexArraysLevel();
unsigned FieldNo = 0;
bool IsUnion = RD->isUnion();

for (const Decl *D : RD->decls()) {
if (const auto *Field = dyn_cast<FieldDecl>(D);
Field && (Name.empty() || Field->getNameAsString() == Name) &&
Decl::isFlexibleArrayMemberLike(
Ctx, Field, Field->getType(), StrictFlexArraysLevel,
/*IgnoreTemplateOrMacroSubstitution=*/true)) {
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Offset += Layout.getFieldOffset(FieldNo);
return Field;
}

if (const auto *Record = dyn_cast<RecordDecl>(D))
if (const FieldDecl *Field =
FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Offset += Layout.getFieldOffset(FieldNo);
return Field;
}

if (!IsUnion && isa<FieldDecl>(D))
++FieldNo;
}

return nullptr;
}

static unsigned CountCountedByAttrs(const RecordDecl *RD) {
unsigned Num = 0;

for (const Decl *D : RD->decls()) {
if (const auto *FD = dyn_cast<FieldDecl>(D);
FD && FD->hasAttr<CountedByAttr>()) {
return ++Num;
}

if (const auto *Rec = dyn_cast<RecordDecl>(D))
Num += CountCountedByAttrs(Rec);
}

return Num;
}

llvm::Value *
CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
llvm::IntegerType *ResType) {
// The code generated here calculates the size of a struct with a flexible
// array member that uses the counted_by attribute. There are two instances
// we handle:
//
// struct s {
// unsigned long flags;
// int count;
// int array[] __attribute__((counted_by(count)));
// }
//
// 1) bdos of the flexible array itself:
//
// __builtin_dynamic_object_size(p->array, 1) ==
// p->count * sizeof(*p->array)
//
// 2) bdos of a pointer into the flexible array:
//
// __builtin_dynamic_object_size(&p->array[42], 1) ==
// (p->count - 42) * sizeof(*p->array)
//
// 2) bdos of the whole struct, including the flexible array:
//
// __builtin_dynamic_object_size(p, 1) ==
// max(sizeof(struct s),
// offsetof(struct s, array) + p->count * sizeof(*p->array))
//
ASTContext &Ctx = getContext();
const Expr *Base = E->IgnoreParenImpCasts();
const Expr *Idx = nullptr;

if (const auto *UO = dyn_cast<UnaryOperator>(Base);
UO && UO->getOpcode() == UO_AddrOf) {
Expr *SubExpr = UO->getSubExpr()->IgnoreParenImpCasts();
if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(SubExpr)) {
Base = ASE->getBase()->IgnoreParenImpCasts();
Idx = ASE->getIdx()->IgnoreParenImpCasts();

if (const auto *IL = dyn_cast<IntegerLiteral>(Idx)) {
int64_t Val = IL->getValue().getSExtValue();
if (Val < 0)
return getDefaultBuiltinObjectSizeResult(Type, ResType);

if (Val == 0)
// The index is 0, so we don't need to take it into account.
Idx = nullptr;
}
} else {
// Potential pointer to another element in the struct.
Base = SubExpr;
}
}

// Get the flexible array member Decl.
const RecordDecl *OuterRD = nullptr;
std::string FAMName;
if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
// Check if \p Base is referencing the FAM itself.
const ValueDecl *VD = ME->getMemberDecl();
OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext();
FAMName = VD->getNameAsString();
} else if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
// Check if we're pointing to the whole struct.
QualType Ty = DRE->getDecl()->getType();
if (Ty->isPointerType())
Ty = Ty->getPointeeType();
OuterRD = Ty->getAsRecordDecl();

// If we have a situation like this:
//
// struct union_of_fams {
// int flags;
// union {
// signed char normal_field;
// struct {
// int count1;
// int arr1[] __counted_by(count1);
// };
// struct {
// signed char count2;
// int arr2[] __counted_by(count2);
// };
// };
// };
//
// We don't konw which 'count' to use in this scenario:
//
// size_t get_size(struct union_of_fams *p) {
// return __builtin_dynamic_object_size(p, 1);
// }
//
// Instead of calculating a wrong number, we give up.
if (OuterRD && CountCountedByAttrs(OuterRD) > 1)
return nullptr;
}

if (!OuterRD)
return nullptr;

uint64_t Offset = 0;
const FieldDecl *FAMDecl =
FindFlexibleArrayMemberField(Ctx, OuterRD, FAMName, Offset);
Offset = Ctx.toCharUnitsFromBits(Offset).getQuantity();

if (!FAMDecl || !FAMDecl->hasAttr<CountedByAttr>())
// No flexible array member found or it doesn't have the "counted_by"
// attribute.
return nullptr;

const FieldDecl *CountedByFD = FindCountedByField(FAMDecl);
if (!CountedByFD)
// Can't find the field referenced by the "counted_by" attribute.
return nullptr;

// Build a load of the counted_by field.
bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
Value *CountedByInst = EmitCountedByFieldExpr(Base, FAMDecl, CountedByFD);
if (!CountedByInst)
return getDefaultBuiltinObjectSizeResult(Type, ResType);

CountedByInst = Builder.CreateIntCast(CountedByInst, ResType, IsSigned);

// Build a load of the index and subtract it from the count.
Value *IdxInst = nullptr;
if (Idx) {
if (Idx->HasSideEffects(getContext()))
// We can't have side-effects.
return getDefaultBuiltinObjectSizeResult(Type, ResType);

bool IdxSigned = Idx->getType()->isSignedIntegerType();
IdxInst = EmitAnyExprToTemp(Idx).getScalarVal();
IdxInst = Builder.CreateIntCast(IdxInst, ResType, IdxSigned);

// We go ahead with the calculation here. If the index turns out to be
// negative, we'll catch it at the end.
CountedByInst =
Builder.CreateSub(CountedByInst, IdxInst, "", !IsSigned, IsSigned);
}

// Calculate how large the flexible array member is in bytes.
const ArrayType *ArrayTy = Ctx.getAsArrayType(FAMDecl->getType());
CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
llvm::Constant *ElemSize =
llvm::ConstantInt::get(ResType, Size.getQuantity(), IsSigned);
Value *FAMSize =
Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned);
FAMSize = Builder.CreateIntCast(FAMSize, ResType, IsSigned);
Value *Res = FAMSize;

if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
// The whole struct is specificed in the __bdos.
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);

// Get the offset of the FAM.
llvm::Constant *FAMOffset = ConstantInt::get(ResType, Offset, IsSigned);
Value *OffsetAndFAMSize =
Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned);

// Get the full size of the struct.
llvm::Constant *SizeofStruct =
ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned);

// max(sizeof(struct s),
// offsetof(struct s, array) + p->count * sizeof(*p->array))
Res = IsSigned
? Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax,
OffsetAndFAMSize, SizeofStruct)
: Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax,
OffsetAndFAMSize, SizeofStruct);
}

// A negative \p IdxInst or \p CountedByInst means that the index lands
// outside of the flexible array member. If that's the case, we want to
// return 0.
Value *Cmp = Builder.CreateIsNotNeg(CountedByInst);
if (IdxInst)
Cmp = Builder.CreateAnd(Builder.CreateIsNotNeg(IdxInst), Cmp);

return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, IsSigned));
}

/// Returns a Value corresponding to the size of the given expression.
/// This Value may be either of the following:
/// - A llvm::Argument (if E is a param with the pass_object_size attribute on
Expand Down Expand Up @@ -850,6 +1083,13 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
}
}

if (IsDynamic) {
// Emit special code for a flexible array member with the "counted_by"
// attribute.
if (Value *V = emitFlexibleArrayMemberSize(E, Type, ResType))
return V;
}

// LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't
// evaluate E for side-effects. In either case, we shouldn't lower to
// @llvm.objectsize.
Expand Down Expand Up @@ -9681,8 +9921,8 @@ Value *CodeGenFunction::EmitSVEMaskedStore(const CallExpr *E,
bool IsQuadStore = false;

switch (IntrinsicID) {
case Intrinsic::aarch64_sve_st1uwq:
case Intrinsic::aarch64_sve_st1udq:
case Intrinsic::aarch64_sve_st1wq:
case Intrinsic::aarch64_sve_st1dq:
AddrMemoryTy = llvm::ScalableVectorType::get(MemEltTy, 1);
PredTy =
llvm::ScalableVectorType::get(IntegerType::get(getLLVMContext(), 1), 1);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2612,6 +2612,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
if (IRFunctionArgs.hasSRetArg()) {
llvm::AttrBuilder SRETAttrs(getLLVMContext());
SRETAttrs.addStructRetAttr(getTypes().ConvertTypeForMem(RetTy));
SRETAttrs.addAttribute(llvm::Attribute::Writable);
SRETAttrs.addAttribute(llvm::Attribute::DeadOnUnwind);
hasUsedSRet = true;
if (RetAI.getInReg())
SRETAttrs.addAttribute(llvm::Attribute::InReg);
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CodeGen/CGException.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
case ObjCRuntime::WatchOS:
return EHPersonality::NeXT_ObjC;
case ObjCRuntime::GNUstep:
if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
if (T.isOSCygMing())
return EHPersonality::GNU_CPlusPlus_SEH;
else if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
return EHPersonality::GNUstep_ObjC;
[[fallthrough]];
case ObjCRuntime::GCC:
Expand Down Expand Up @@ -210,7 +212,8 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
return getObjCPersonality(Target, L);

case ObjCRuntime::GNUstep:
return EHPersonality::GNU_ObjCXX;
return Target.getTriple().isOSCygMing() ? EHPersonality::GNU_CPlusPlus_SEH
: EHPersonality::GNU_ObjCXX;

// The GCC runtime's personality function inherently doesn't support
// mixed EH. Use the ObjC personality just to avoid returning null.
Expand Down
340 changes: 334 additions & 6 deletions clang/lib/CodeGen/CGExpr.cpp

Large diffs are not rendered by default.

37 changes: 25 additions & 12 deletions clang/lib/CodeGen/CGObjCGNU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ class CGObjCGNU : public CGObjCRuntime {
/// Does the current target use SEH-based exceptions? False implies
/// Itanium-style DWARF unwinding.
bool usesSEHExceptions;
/// Does the current target uses C++-based exceptions?
bool usesCxxExceptions;

/// Helper to check if we are targeting a specific runtime version or later.
bool isRuntime(ObjCRuntime::Kind kind, unsigned major, unsigned minor=0) {
Expand Down Expand Up @@ -819,12 +821,18 @@ class CGObjCGNUstep : public CGObjCGNU {
SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
PtrToObjCSuperTy, SelectorTy);
// If we're in ObjC++ mode, then we want to make
if (usesSEHExceptions) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void objc_exception_rethrow(void)
ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy);
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
if (usesCxxExceptions) {
// void *__cxa_begin_catch(void *e)
EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy);
// void __cxa_end_catch(void)
ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy);
// void objc_exception_rethrow(void*)
ExceptionReThrowFn.init(&CGM, "__cxa_rethrow", PtrTy);
} else if (usesSEHExceptions) {
// void objc_exception_rethrow(void)
ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy);
} else if (CGM.getLangOpts().CPlusPlus) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void *__cxa_begin_catch(void *e)
EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy);
// void __cxa_end_catch(void)
Expand All @@ -833,15 +841,13 @@ class CGObjCGNUstep : public CGObjCGNU {
ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy,
PtrTy);
} else if (R.getVersion() >= VersionTuple(1, 7)) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// id objc_begin_catch(void *e)
EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy);
// void objc_end_catch(void)
ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy);
// void _Unwind_Resume_or_Rethrow(void*)
ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, PtrTy);
}
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy,
SelectorTy, IdTy, PtrDiffTy);
SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy,
Expand Down Expand Up @@ -1851,6 +1857,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
llvm::GlobalValue::HiddenVisibility :
llvm::GlobalValue::DefaultVisibility;
OffsetVar->setVisibility(ivarVisibility);
if (ivarVisibility != llvm::GlobalValue::HiddenVisibility)
CGM.setGVProperties(OffsetVar, OID->getClassInterface());
ivarBuilder.add(OffsetVar);
// Ivar size
ivarBuilder.addInt(Int32Ty,
Expand Down Expand Up @@ -2124,6 +2132,9 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
usesSEHExceptions =
cgm.getContext().getTargetInfo().getTriple().isWindowsMSVCEnvironment();
usesCxxExceptions =
cgm.getContext().getTargetInfo().getTriple().isOSCygMing() &&
isRuntime(ObjCRuntime::GNUstep, 2);

CodeGenTypes &Types = CGM.getTypes();
IntTy = cast<llvm::IntegerType>(
Expand Down Expand Up @@ -2210,7 +2221,10 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,

// void objc_exception_throw(id);
ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
ExceptionReThrowFn.init(&CGM,
usesCxxExceptions ? "objc_exception_rethrow"
: "objc_exception_throw",
VoidTy, IdTy);
// int objc_sync_enter(id);
SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy);
// int objc_sync_exit(id);
Expand Down Expand Up @@ -2387,7 +2401,7 @@ llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
if (usesSEHExceptions)
return CGM.getCXXABI().getAddrOfRTTIDescriptor(T);

if (!CGM.getLangOpts().CPlusPlus)
if (!CGM.getLangOpts().CPlusPlus && !usesCxxExceptions)
return CGObjCGNU::GetEHType(T);

// For Objective-C++, we want to provide the ability to catch both C++ and
Expand Down Expand Up @@ -3993,7 +4007,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
ExceptionAsObject = CGF.ObjCEHValueStack.back();
isRethrow = true;
}
if (isRethrow && usesSEHExceptions) {
if (isRethrow && (usesSEHExceptions || usesCxxExceptions)) {
// For SEH, ExceptionAsObject may be undef, because the catch handler is
// not passed it for catchalls and so it is not visible to the catch
// funclet. The real thrown object will still be live on the stack at this
Expand All @@ -4003,8 +4017,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
// argument.
llvm::CallBase *Throw = CGF.EmitRuntimeCallOrInvoke(ExceptionReThrowFn);
Throw->setDoesNotReturn();
}
else {
} else {
ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
llvm::CallBase *Throw =
CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3073,6 +3073,25 @@ class CodeGenFunction : public CodeGenTypeCache {
/// this expression is used as an lvalue, for instance in "&Arr[Idx]".
void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index,
QualType IndexType, bool Accessed);
void EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
llvm::Value *Index, QualType IndexType,
QualType IndexedType, bool Accessed);

// Find a struct's flexible array member. It may be embedded inside multiple
// sub-structs, but must still be the last field.
const FieldDecl *FindFlexibleArrayMemberField(ASTContext &Ctx,
const RecordDecl *RD,
StringRef Name,
uint64_t &Offset);

/// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
/// \p nullptr if either the attribute or the field doesn't exist.
const FieldDecl *FindCountedByField(const FieldDecl *FD);

/// Build an expression accessing the "counted_by" field.
llvm::Value *EmitCountedByFieldExpr(const Expr *Base,
const FieldDecl *FAMDecl,
const FieldDecl *CountDecl);

llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
Expand Down Expand Up @@ -4873,6 +4892,9 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmittedE,
bool IsDynamic);

llvm::Value *emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
llvm::IntegerType *ResType);

void emitZeroOrPatternForAutoVarInit(QualType type, const VarDecl &D,
Address Loc);

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,8 @@ void CodeGenModule::Release() {
if (LangOpts.BranchProtectionPAuthLR)
getModule().addModuleFlag(llvm::Module::Min, "branch-protection-pauth-lr",
1);
if (LangOpts.GuardedControlStack)
getModule().addModuleFlag(llvm::Module::Min, "guarded-control-stack", 1);
if (LangOpts.hasSignReturnAddress())
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address", 1);
if (LangOpts.isSignReturnAddressScopeAll())
Expand Down
13 changes: 11 additions & 2 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1712,7 +1712,11 @@ struct CounterCoverageMappingBuilder
extendRegion(S->getCond());

Counter ParentCount = getRegion().getCounter();
Counter ThenCount = getRegionCounter(S);

// If this is "if !consteval" the then-branch will never be taken, we don't
// need to change counter
Counter ThenCount =
S->isNegatedConsteval() ? ParentCount : getRegionCounter(S);

if (!S->isConsteval()) {
// Emitting a counter for the condition makes it easier to interpret the
Expand All @@ -1729,7 +1733,12 @@ struct CounterCoverageMappingBuilder
extendRegion(S->getThen());
Counter OutCount = propagateCounts(ThenCount, S->getThen());

Counter ElseCount = subtractCounters(ParentCount, ThenCount);
// If this is "if consteval" the else-branch will never be taken, we don't
// need to change counter
Counter ElseCount = S->isNonNegatedConsteval()
? ParentCount
: subtractCounters(ParentCount, ThenCount);

if (const Stmt *Else = S->getElse()) {
bool ThenHasTerminateStmt = HasTerminateStmt;
HasTerminateStmt = false;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
BPI.BranchTargetEnforcement ? "true" : "false");
Fn->addFnAttr("branch-protection-pauth-lr",
BPI.BranchProtectionPAuthLR ? "true" : "false");
Fn->addFnAttr("guarded-control-stack",
BPI.GuardedControlStack ? "true" : "false");
}

bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,17 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
const ToolChain &TC = getToolChain(
*UArgs, computeTargetTriple(*this, TargetTriple, *UArgs));

if (TC.getTriple().isAndroid()) {
llvm::Triple Triple = TC.getTriple();
StringRef TripleVersionName = Triple.getEnvironmentVersionString();

if (Triple.getEnvironmentVersion().empty() && TripleVersionName != "") {
Diags.Report(diag::err_drv_triple_version_invalid)
<< TripleVersionName << TC.getTripleString();
ContainsError = true;
}
}

// Report warning when arm64EC option is overridden by specified target
if ((TC.getTriple().getArch() != llvm::Triple::aarch64 ||
TC.getTriple().getSubArch() != llvm::Triple::AArch64SubArch_arm64ec) &&
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Driver/ToolChains/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ static bool getArchFeatures(const Driver &D, StringRef Arch,
return false;
}

(*ISAInfo)->toFeatures(
Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); },
/*AddAllExtensions=*/true);
for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true,
/*IgnoreUnknown=*/false))
Features.push_back(Args.MakeArgString(Str));

if (EnableExperimentalExtensions)
Features.push_back(Args.MakeArgString("+experimental"));
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1508,7 +1508,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< Triple.getArchName();

StringRef Scope, Key;
bool IndirectBranches, BranchProtectionPAuthLR;
bool IndirectBranches, BranchProtectionPAuthLR, GuardedControlStack;

if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
Scope = A->getValue();
Expand All @@ -1518,6 +1518,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
Key = "a_key";
IndirectBranches = false;
BranchProtectionPAuthLR = false;
GuardedControlStack = false;
} else {
StringRef DiagMsg;
llvm::ARM::ParsedBranchProtection PBP;
Expand All @@ -1531,6 +1532,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
Key = PBP.Key;
BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
IndirectBranches = PBP.BranchTargetEnforcement;
GuardedControlStack = PBP.GuardedControlStack;
}

CmdArgs.push_back(
Expand All @@ -1543,6 +1545,8 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
Args.MakeArgString(Twine("-mbranch-protection-pauth-lr")));
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
if (GuardedControlStack)
CmdArgs.push_back("-mguarded-control-stack");
}

void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
const bool IsAMDGCN = ToolChain.getTriple().isAMDGCN();
const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath());
const Driver &D = ToolChain.getDriver();
const bool IsFatLTO = Args.hasArg(options::OPT_ffat_lto_objects);
const bool IsUnifiedLTO = Args.hasArg(options::OPT_funified_lto);
if (llvm::sys::path::filename(Linker) != "ld.lld" &&
llvm::sys::path::stem(Linker) != "ld.lld" &&
!ToolChain.getTriple().isOSOpenBSD()) {
Expand Down Expand Up @@ -765,7 +767,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
} else {
// Tell LLD to find and use .llvm.lto section in regular relocatable object
// files
if (Args.hasArg(options::OPT_ffat_lto_objects))
if (IsFatLTO)
CmdArgs.push_back("--fat-lto-objects");
}

Expand Down Expand Up @@ -825,7 +827,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
// Matrix intrinsic lowering happens at link time with ThinLTO. Enable
// LowerMatrixIntrinsicsPass, which is transitively called by
// buildThinLTODefaultPipeline under EnableMatrix.
if (IsThinLTO && Args.hasArg(options::OPT_fenable_matrix))
if ((IsThinLTO || IsFatLTO || IsUnifiedLTO) &&
Args.hasArg(options::OPT_fenable_matrix))
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-enable-matrix"));

Expand Down
57 changes: 54 additions & 3 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
//===----------------------------------------------------------------------===//

#include "Flang.h"
#include "Arch/RISCV.h"
#include "CommonArgs.h"

#include "clang/Basic/CodeGenOptions.h"
#include "clang/Driver/Options.h"
#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/TargetParser/RISCVTargetParser.h"

#include <cassert>

Expand Down Expand Up @@ -203,6 +206,51 @@ void Flang::AddAArch64TargetArgs(const ArgList &Args,
}
}

void Flang::AddRISCVTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const llvm::Triple &Triple = getToolChain().getTriple();
// Handle -mrvv-vector-bits=<bits>
if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) {
StringRef Val = A->getValue();
const Driver &D = getToolChain().getDriver();

// Get minimum VLen from march.
unsigned MinVLen = 0;
StringRef Arch = riscv::getRISCVArch(Args, Triple);
auto ISAInfo = llvm::RISCVISAInfo::parseArchString(
Arch, /*EnableExperimentalExtensions*/ true);
// Ignore parsing error.
if (!errorToBool(ISAInfo.takeError()))
MinVLen = (*ISAInfo)->getMinVLen();

// If the value is "zvl", use MinVLen from march. Otherwise, try to parse
// as integer as long as we have a MinVLen.
unsigned Bits = 0;
if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) {
Bits = MinVLen;
} else if (!Val.getAsInteger(10, Bits)) {
// Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that
// at least MinVLen.
if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock ||
Bits > 65536 || !llvm::isPowerOf2_32(Bits))
Bits = 0;
}

// If we got a valid value try to use it.
if (Bits != 0) {
unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock;
CmdArgs.push_back(
Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin)));
CmdArgs.push_back(
Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin)));
} else if (!Val.equals("scalable")) {
// Handle the unsupported values passed to mrvv-vector-bits.
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << Val;
}
}
}

static void addVSDefines(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {

Expand Down Expand Up @@ -321,6 +369,9 @@ void Flang::addTargetOptions(const ArgList &Args,
AddAMDGPUTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::riscv64:
getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
AddRISCVTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::x86_64:
getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
break;
Expand Down Expand Up @@ -352,12 +403,10 @@ void Flang::addTargetOptions(const ArgList &Args,
if (A->getValue() == StringRef{"Accelerate"}) {
CmdArgs.push_back("-framework");
CmdArgs.push_back("Accelerate");
A->render(Args, CmdArgs);
}
}
} else {
A->render(Args, CmdArgs);
}
A->render(Args, CmdArgs);
}

if (Triple.isKnownWindowsMSVCEnvironment()) {
Expand Down Expand Up @@ -428,6 +477,8 @@ void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
CmdArgs.push_back("-fopenmp-assume-no-thread-state");
if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism))
CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism");
if (Args.hasArg(options::OPT_nogpulib))
CmdArgs.push_back("-nogpulib");
}
}

Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ class LLVM_LIBRARY_VISIBILITY Flang : public Tool {
void AddAMDGPUTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;

/// Add specific options for RISC-V target.
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
void AddRISCVTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;

/// Extract offload options from the driver arguments and add them to
/// the command arguments.
/// \param [in] C The current compilation for the driver invocation
Expand Down
17 changes: 15 additions & 2 deletions clang/lib/Driver/ToolChains/Gnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2251,6 +2251,15 @@ void Generic_GCC::GCCInstallationDetector::init(
return;
}

// If --gcc-triple is specified use this instead of trying to
// auto-detect a triple.
if (const Arg *A =
Args.getLastArg(clang::driver::options::OPT_gcc_triple_EQ)) {
StringRef GCCTriple = A->getValue();
CandidateTripleAliases.clear();
CandidateTripleAliases.push_back(GCCTriple);
}

// Compute the set of prefixes for our search.
SmallVector<std::string, 8> Prefixes;
StringRef GCCToolchainDir = getGCCToolchainDir(Args, D.SysRoot);
Expand Down Expand Up @@ -2659,7 +2668,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
case llvm::Triple::arm:
case llvm::Triple::thumb:
LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs));
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF ||
TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF ||
TargetTriple.getEnvironment() == llvm::Triple::EABIHF) {
TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples));
} else {
TripleAliases.append(begin(ARMTriples), end(ARMTriples));
Expand All @@ -2668,7 +2679,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs));
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF ||
TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF ||
TargetTriple.getEnvironment() == llvm::Triple::EABIHF) {
TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples));
} else {
TripleAliases.append(begin(ARMebTriples), end(ARMebTriples));
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,16 @@ std::string Linux::getMultiarchTriple(const Driver &D,
case llvm::Triple::thumb:
if (IsAndroid)
return "arm-linux-androideabi";
if (TargetEnvironment == llvm::Triple::GNUEABIHF)
if (TargetEnvironment == llvm::Triple::GNUEABIHF ||
TargetEnvironment == llvm::Triple::MuslEABIHF ||
TargetEnvironment == llvm::Triple::EABIHF)
return "arm-linux-gnueabihf";
return "arm-linux-gnueabi";
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
if (TargetEnvironment == llvm::Triple::GNUEABIHF)
if (TargetEnvironment == llvm::Triple::GNUEABIHF ||
TargetEnvironment == llvm::Triple::MuslEABIHF ||
TargetEnvironment == llvm::Triple::EABIHF)
return "armeb-linux-gnueabihf";
return "armeb-linux-gnueabi";
case llvm::Triple::x86:
Expand Down
25 changes: 23 additions & 2 deletions clang/lib/Driver/ToolChains/MinGW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,12 +471,23 @@ findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple,
return make_error_code(std::errc::no_such_file_or_directory);
}

static bool looksLikeMinGWSysroot(const std::string &Directory) {
StringRef Sep = llvm::sys::path::get_separator();
if (!llvm::sys::fs::exists(Directory + Sep + "include" + Sep + "_mingw.h"))
return false;
if (!llvm::sys::fs::exists(Directory + Sep + "lib" + Sep + "libkernel32.a"))
return false;
return true;
}

toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
RocmInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());

std::string InstallBase =
std::string(llvm::sys::path::parent_path(getDriver().getInstalledDir()));
// The sequence for detecting a sysroot here should be kept in sync with
// the testTriple function below.
llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple());
Expand All @@ -487,13 +498,17 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot(
getDriver(), LiteralTriple, getTriple(), SubdirName))
Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get()));
// If the install base of Clang seems to have mingw sysroot files directly
// in the toplevel include and lib directories, use this as base instead of
// looking for a triple prefixed GCC in the path.
else if (looksLikeMinGWSysroot(InstallBase))
Base = InstallBase;
else if (llvm::ErrorOr<std::string> GPPName =
findGcc(LiteralTriple, getTriple()))
Base = std::string(llvm::sys::path::parent_path(
llvm::sys::path::parent_path(GPPName.get())));
else
Base = std::string(
llvm::sys::path::parent_path(getDriver().getInstalledDir()));
Base = InstallBase;

Base += llvm::sys::path::get_separator();
findGccLibDir(LiteralTriple);
Expand Down Expand Up @@ -778,9 +793,15 @@ static bool testTriple(const Driver &D, const llvm::Triple &Triple,
if (D.SysRoot.size())
return true;
llvm::Triple LiteralTriple = getLiteralTriple(D, Triple);
std::string InstallBase =
std::string(llvm::sys::path::parent_path(D.getInstalledDir()));
if (llvm::ErrorOr<std::string> TargetSubdir =
findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName))
return true;
// If the install base itself looks like a mingw sysroot, we'll use that
// - don't use any potentially unrelated gcc to influence what triple to use.
if (looksLikeMinGWSysroot(InstallBase))
return false;
if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, Triple))
return true;
// If we neither found a colocated sysroot or a matching gcc executable,
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Format/.clang-format
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
BasedOnStyle: clang-format
BasedOnStyle: LLVM
InsertBraces: true
InsertNewlineAtEOF: true
LineEnding: LF
RemoveBracesLLVM: true
RemoveParentheses: ReturnStatement
30 changes: 15 additions & 15 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,48 +76,47 @@ template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> {
FormatStyle::AlignConsecutiveStyle(
{/*Enabled=*/false, /*AcrossEmptyLines=*/false,
/*AcrossComments=*/false, /*AlignCompound=*/false,
/*PadOperators=*/true}));
/*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
IO.enumCase(Value, "Consecutive",
FormatStyle::AlignConsecutiveStyle(
{/*Enabled=*/true, /*AcrossEmptyLines=*/false,
/*AcrossComments=*/false, /*AlignCompound=*/false,
/*PadOperators=*/true}));
/*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
IO.enumCase(Value, "AcrossEmptyLines",
FormatStyle::AlignConsecutiveStyle(
{/*Enabled=*/true, /*AcrossEmptyLines=*/true,
/*AcrossComments=*/false, /*AlignCompound=*/false,
/*PadOperators=*/true}));
/*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
IO.enumCase(Value, "AcrossComments",
FormatStyle::AlignConsecutiveStyle({/*Enabled=*/true,
/*AcrossEmptyLines=*/false,
/*AcrossComments=*/true,
/*AlignCompound=*/false,
/*PadOperators=*/true}));
FormatStyle::AlignConsecutiveStyle(
{/*Enabled=*/true, /*AcrossEmptyLines=*/false,
/*AcrossComments=*/true, /*AlignCompound=*/false,
/*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
IO.enumCase(Value, "AcrossEmptyLinesAndComments",
FormatStyle::AlignConsecutiveStyle({/*Enabled=*/true,
/*AcrossEmptyLines=*/true,
/*AcrossComments=*/true,
/*AlignCompound=*/false,
/*PadOperators=*/true}));
FormatStyle::AlignConsecutiveStyle(
{/*Enabled=*/true, /*AcrossEmptyLines=*/true,
/*AcrossComments=*/true, /*AlignCompound=*/false,
/*AlignFunctionPointers=*/false, /*PadOperators=*/true}));

// For backward compatibility.
IO.enumCase(Value, "true",
FormatStyle::AlignConsecutiveStyle(
{/*Enabled=*/true, /*AcrossEmptyLines=*/false,
/*AcrossComments=*/false, /*AlignCompound=*/false,
/*PadOperators=*/true}));
/*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
IO.enumCase(Value, "false",
FormatStyle::AlignConsecutiveStyle(
{/*Enabled=*/false, /*AcrossEmptyLines=*/false,
/*AcrossComments=*/false, /*AlignCompound=*/false,
/*PadOperators=*/true}));
/*AlignFunctionPointers=*/false, /*PadOperators=*/true}));
}

static void mapping(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) {
IO.mapOptional("Enabled", Value.Enabled);
IO.mapOptional("AcrossEmptyLines", Value.AcrossEmptyLines);
IO.mapOptional("AcrossComments", Value.AcrossComments);
IO.mapOptional("AlignCompound", Value.AlignCompound);
IO.mapOptional("AlignFunctionPointers", Value.AlignFunctionPointers);
IO.mapOptional("PadOperators", Value.PadOperators);
}
};
Expand Down Expand Up @@ -1432,6 +1431,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlignConsecutiveAssignments.AcrossEmptyLines = false;
LLVMStyle.AlignConsecutiveAssignments.AcrossComments = false;
LLVMStyle.AlignConsecutiveAssignments.AlignCompound = false;
LLVMStyle.AlignConsecutiveAssignments.AlignFunctionPointers = false;
LLVMStyle.AlignConsecutiveAssignments.PadOperators = true;
LLVMStyle.AlignConsecutiveBitFields = {};
LLVMStyle.AlignConsecutiveDeclarations = {};
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Format/FormatToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ unsigned CommaSeparatedList::formatAfterToken(LineState &State,
if (!State.NextToken || !State.NextToken->Previous)
return 0;

if (Formats.size() == 1)
return 0; // Handled by formatFromToken
if (Formats.size() <= 1)
return 0; // Handled by formatFromToken (1) or avoid severe penalty (0).

// Ensure that we start on the opening brace.
const FormatToken *LBrace =
Expand Down
100 changes: 92 additions & 8 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,14 +275,15 @@ class AnnotatedLine;
struct FormatToken {
FormatToken()
: HasUnescapedNewline(false), IsMultiline(false), IsFirst(false),
MustBreakBefore(false), IsUnterminatedLiteral(false),
CanBreakBefore(false), ClosesTemplateDeclaration(false),
StartsBinaryExpression(false), EndsBinaryExpression(false),
PartOfMultiVariableDeclStmt(false), ContinuesLineCommentSection(false),
Finalized(false), ClosesRequiresClause(false),
EndsCppAttributeGroup(false), BlockKind(BK_Unknown),
Decision(FD_Unformatted), PackingKind(PPK_Inconclusive),
TypeIsFinalized(false), Type(TT_Unknown) {}
MustBreakBefore(false), MustBreakBeforeFinalized(false),
IsUnterminatedLiteral(false), CanBreakBefore(false),
ClosesTemplateDeclaration(false), StartsBinaryExpression(false),
EndsBinaryExpression(false), PartOfMultiVariableDeclStmt(false),
ContinuesLineCommentSection(false), Finalized(false),
ClosesRequiresClause(false), EndsCppAttributeGroup(false),
BlockKind(BK_Unknown), Decision(FD_Unformatted),
PackingKind(PPK_Inconclusive), TypeIsFinalized(false),
Type(TT_Unknown) {}

/// The \c Token.
Token Tok;
Expand Down Expand Up @@ -318,6 +319,10 @@ struct FormatToken {
/// before the token.
unsigned MustBreakBefore : 1;

/// Whether MustBreakBefore is finalized during parsing and must not
/// be reset between runs.
unsigned MustBreakBeforeFinalized : 1;

/// Set to \c true if this token is an unterminated literal.
unsigned IsUnterminatedLiteral : 1;

Expand Down Expand Up @@ -416,10 +421,14 @@ struct FormatToken {
/// to another one please use overwriteFixedType, or even better remove the
/// need to reassign the type.
void setFinalizedType(TokenType T) {
if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg)
return;
Type = T;
TypeIsFinalized = true;
}
void overwriteFixedType(TokenType T) {
if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg)
return;
TypeIsFinalized = false;
setType(T);
}
Expand Down Expand Up @@ -1202,6 +1211,21 @@ struct AdditionalKeywords {
kw_verilogHashHash = &IdentTable.get("##");
kw_apostrophe = &IdentTable.get("\'");

// TableGen keywords
kw_bit = &IdentTable.get("bit");
kw_bits = &IdentTable.get("bits");
kw_code = &IdentTable.get("code");
kw_dag = &IdentTable.get("dag");
kw_def = &IdentTable.get("def");
kw_defm = &IdentTable.get("defm");
kw_defset = &IdentTable.get("defset");
kw_defvar = &IdentTable.get("defvar");
kw_dump = &IdentTable.get("dump");
kw_include = &IdentTable.get("include");
kw_list = &IdentTable.get("list");
kw_multiclass = &IdentTable.get("multiclass");
kw_then = &IdentTable.get("then");

// Keep this at the end of the constructor to make sure everything here
// is
// already initialized.
Expand Down Expand Up @@ -1294,6 +1318,27 @@ struct AdditionalKeywords {
kw_wildcard, kw_wire,
kw_with, kw_wor,
kw_verilogHash, kw_verilogHashHash});

TableGenExtraKeywords = std::unordered_set<IdentifierInfo *>({
kw_assert,
kw_bit,
kw_bits,
kw_code,
kw_dag,
kw_def,
kw_defm,
kw_defset,
kw_defvar,
kw_dump,
kw_foreach,
kw_in,
kw_include,
kw_let,
kw_list,
kw_multiclass,
kw_string,
kw_then,
});
}

// Context sensitive keywords.
Expand Down Expand Up @@ -1539,6 +1584,21 @@ struct AdditionalKeywords {
// Symbols in Verilog that don't exist in C++.
IdentifierInfo *kw_apostrophe;

// TableGen keywords
IdentifierInfo *kw_bit;
IdentifierInfo *kw_bits;
IdentifierInfo *kw_code;
IdentifierInfo *kw_dag;
IdentifierInfo *kw_def;
IdentifierInfo *kw_defm;
IdentifierInfo *kw_defset;
IdentifierInfo *kw_defvar;
IdentifierInfo *kw_dump;
IdentifierInfo *kw_include;
IdentifierInfo *kw_list;
IdentifierInfo *kw_multiclass;
IdentifierInfo *kw_then;

/// Returns \c true if \p Tok is a keyword or an identifier.
bool isWordLike(const FormatToken &Tok) const {
// getIdentifierinfo returns non-null for keywords as well as identifiers.
Expand Down Expand Up @@ -1811,6 +1871,27 @@ struct AdditionalKeywords {
}
}

bool isTableGenDefinition(const FormatToken &Tok) const {
return Tok.isOneOf(kw_def, kw_defm, kw_defset, kw_defvar, kw_multiclass,
kw_let, tok::kw_class);
}

bool isTableGenKeyword(const FormatToken &Tok) const {
switch (Tok.Tok.getKind()) {
case tok::kw_class:
case tok::kw_else:
case tok::kw_false:
case tok::kw_if:
case tok::kw_int:
case tok::kw_true:
return true;
default:
return Tok.is(tok::identifier) &&
TableGenExtraKeywords.find(Tok.Tok.getIdentifierInfo()) !=
TableGenExtraKeywords.end();
}
}

private:
/// The JavaScript keywords beyond the C++ keyword set.
std::unordered_set<IdentifierInfo *> JsExtraKeywords;
Expand All @@ -1820,6 +1901,9 @@ struct AdditionalKeywords {

/// The Verilog keywords beyond the C++ keyword set.
std::unordered_set<IdentifierInfo *> VerilogExtraKeywords;

/// The TableGen keywords beyond the C++ keyword set.
std::unordered_set<IdentifierInfo *> TableGenExtraKeywords;
};

inline bool isLineComment(const FormatToken &FormatTok) {
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,9 @@ FormatToken *FormatTokenLexer::getNextToken() {
tok::kw_operator)) {
FormatTok->Tok.setKind(tok::identifier);
FormatTok->Tok.setIdentifierInfo(nullptr);
} else if (Style.isTableGen() && !Keywords.isTableGenKeyword(*FormatTok)) {
FormatTok->Tok.setKind(tok::identifier);
FormatTok->Tok.setIdentifierInfo(nullptr);
}
} else if (FormatTok->is(tok::greatergreater)) {
FormatTok->Tok.setKind(tok::greater);
Expand Down
30 changes: 22 additions & 8 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2234,6 +2234,12 @@ class AnnotatingParser {
if (PreviousNotConst->ClosesRequiresClause)
return false;

if (Style.isTableGen()) {
// keywords such as let and def* defines names.
if (Keywords.isTableGenDefinition(*PreviousNotConst))
return true;
}

bool IsPPKeyword = PreviousNotConst->is(tok::identifier) &&
PreviousNotConst->Previous &&
PreviousNotConst->Previous->is(tok::hash);
Expand Down Expand Up @@ -2369,7 +2375,7 @@ class AnnotatingParser {
}
}

if (Tok.Next->is(tok::question))
if (Tok.Next->isOneOf(tok::question, tok::ampamp))
return false;

// `foreach((A a, B b) in someList)` should not be seen as a cast.
Expand Down Expand Up @@ -2769,13 +2775,6 @@ class ExpressionParser {
// Consume operators with higher precedence.
parse(Precedence + 1);

// Do not assign fake parenthesis to tokens that are part of an
// unexpanded macro call. The line within the macro call contains
// the parenthesis and commas, and we will not find operators within
// that structure.
if (Current && Current->MacroParent)
break;

int CurrentPrecedence = getCurrentPrecedence();

if (Precedence == CurrentPrecedence && Current &&
Expand Down Expand Up @@ -2919,6 +2918,13 @@ class ExpressionParser {

void addFakeParenthesis(FormatToken *Start, prec::Level Precedence,
FormatToken *End = nullptr) {
// Do not assign fake parenthesis to tokens that are part of an
// unexpanded macro call. The line within the macro call contains
// the parenthesis and commas, and we will not find operators within
// that structure.
if (Start->MacroParent)
return;

Start->FakeLParens.push_back(Precedence);
if (Precedence > prec::Unknown)
Start->StartsBinaryExpression = true;
Expand Down Expand Up @@ -5151,6 +5157,14 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
if (Left.IsUnterminatedLiteral)
return true;
// FIXME: Breaking after newlines seems useful in general. Turn this into an
// option and recognize more cases like endl etc, and break independent of
// what comes after operator lessless.
if (Right.is(tok::lessless) && Right.Next &&
Right.Next->is(tok::string_literal) && Left.is(tok::string_literal) &&
Left.TokenText.ends_with("\\n\"")) {
return true;
}
if (Right.is(TT_RequiresClause)) {
switch (Style.RequiresClausePosition) {
case FormatStyle::RCPS_OwnLine:
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Format/UnwrappedLineFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,13 +954,15 @@ static void markFinalized(FormatToken *Tok) {
// will be modified as unexpanded arguments (as part of the macro call
// formatting) in the next pass.
Tok->MacroCtx->Role = MR_UnexpandedArg;
// Reset whether spaces are required before this token, as that is context
// dependent, and that context may change when formatting the macro call.
// For example, given M(x) -> 2 * x, and the macro call M(var),
// the token 'var' will have SpacesRequiredBefore = 1 after being
// Reset whether spaces or a line break are required before this token, as
// that is context dependent, and that context may change when formatting
// the macro call. For example, given M(x) -> 2 * x, and the macro call
// M(var), the token 'var' will have SpacesRequiredBefore = 1 after being
// formatted as part of the expanded macro, but SpacesRequiredBefore = 0
// for its position within the macro call.
Tok->SpacesRequiredBefore = 0;
if (!Tok->MustBreakBeforeFinalized)
Tok->MustBreakBefore = 0;
} else {
Tok->Finalized = true;
}
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2308,7 +2308,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
LeftSquare->isCppStructuredBinding(Style)) {
return false;
}
if (FormatTok->is(tok::l_square))
if (FormatTok->is(tok::l_square) || tok::isLiteral(FormatTok->Tok.getKind()))
return false;
if (FormatTok->is(tok::r_square)) {
const FormatToken *Next = Tokens->peekNextToken(/*SkipComment=*/true);
Expand Down Expand Up @@ -4675,6 +4675,7 @@ void UnwrappedLineParser::readToken(int LevelDifference) {
conditionalCompilationEnd();
FormatTok = Tokens->getNextToken();
FormatTok->MustBreakBefore = true;
FormatTok->MustBreakBeforeFinalized = true;
}

auto IsFirstNonCommentOnLine = [](bool FirstNonCommentOnLine,
Expand Down Expand Up @@ -4891,6 +4892,7 @@ void UnwrappedLineParser::pushToken(FormatToken *Tok) {
Line->Tokens.push_back(UnwrappedLineNode(Tok));
if (MustBreakBeforeNextToken) {
Line->Tokens.back().Tok->MustBreakBefore = true;
Line->Tokens.back().Tok->MustBreakBeforeFinalized = true;
MustBreakBeforeNextToken = false;
}
}
Expand Down
9 changes: 8 additions & 1 deletion clang/lib/Format/WhitespaceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,14 @@ void WhitespaceManager::alignConsecutiveDeclarations() {

AlignTokens(
Style,
[](Change const &C) {
[&](Change const &C) {
if (Style.AlignConsecutiveDeclarations.AlignFunctionPointers) {
for (const auto *Prev = C.Tok->Previous; Prev; Prev = Prev->Previous)
if (Prev->is(tok::equal))
return false;
if (C.Tok->is(TT_FunctionTypeLParen))
return true;
}
if (C.Tok->is(TT_FunctionDeclarationName))
return true;
if (C.Tok->isNot(TT_StartOfName))
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/WhitespaceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ class WhitespaceManager {
for (auto PrevIter = Start; PrevIter != End; ++PrevIter) {
// If we broke the line the initial spaces are already
// accounted for.
assert(PrevIter->Index < Changes.size());
if (Changes[PrevIter->Index].NewlinesBefore > 0)
NetWidth = 0;
NetWidth +=
Expand Down
15 changes: 11 additions & 4 deletions clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,12 +611,19 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
diag::err_verify_missing_start) << KindStr;
continue;
}
llvm::SmallString<8> CloseBrace("}}");
const char *const DelimBegin = PH.C;
PH.Advance();
// Count the number of opening braces for `string` kinds
for (; !D.RegexKind && PH.Next("{"); PH.Advance())
CloseBrace += '}';
const char* const ContentBegin = PH.C; // mark content begin
// Search for token: }}
if (!PH.SearchClosingBrace("{{", "}}")) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_end) << KindStr;
// Search for closing brace
StringRef OpenBrace(DelimBegin, ContentBegin - DelimBegin);
if (!PH.SearchClosingBrace(OpenBrace, CloseBrace)) {
Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
diag::err_verify_missing_end)
<< KindStr << CloseBrace;
continue;
}
const char* const ContentEnd = PH.P; // mark content end
Expand Down
59 changes: 59 additions & 0 deletions clang/lib/Headers/arm_acle.h
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,65 @@ __arm_st64bv0(void *__addr, data512_t __value) {
__builtin_arm_mops_memset_tag(__tagged_address, __value, __size)
#endif

/* Coprocessor Intrinsics */
#if defined(__ARM_FEATURE_COPROC)

#if (__ARM_FEATURE_COPROC & 0x1)

#if (__ARM_ARCH < 8)
#define __arm_cdp(coproc, opc1, CRd, CRn, CRm, opc2) \
__builtin_arm_cdp(coproc, opc1, CRd, CRn, CRm, opc2)
#endif /* __ARM_ARCH < 8 */

#define __arm_ldc(coproc, CRd, p) __builtin_arm_ldc(coproc, CRd, p)
#define __arm_stc(coproc, CRd, p) __builtin_arm_stc(coproc, CRd, p)

#define __arm_mcr(coproc, opc1, value, CRn, CRm, opc2) \
__builtin_arm_mcr(coproc, opc1, value, CRn, CRm, opc2)
#define __arm_mrc(coproc, opc1, CRn, CRm, opc2) \
__builtin_arm_mrc(coproc, opc1, CRn, CRm, opc2)

#if (__ARM_ARCH != 4) && (__ARM_ARCH < 8)
#define __arm_ldcl(coproc, CRd, p) __builtin_arm_ldcl(coproc, CRd, p)
#define __arm_stcl(coproc, CRd, p) __builtin_arm_stcl(coproc, CRd, p)
#endif /* (__ARM_ARCH != 4) && (__ARM_ARCH != 8) */

#if (__ARM_ARCH_8M_MAIN__) || (__ARM_ARCH_8_1M_MAIN__)
#define __arm_cdp(coproc, opc1, CRd, CRn, CRm, opc2) \
__builtin_arm_cdp(coproc, opc1, CRd, CRn, CRm, opc2)
#define __arm_ldcl(coproc, CRd, p) __builtin_arm_ldcl(coproc, CRd, p)
#define __arm_stcl(coproc, CRd, p) __builtin_arm_stcl(coproc, CRd, p)
#endif /* ___ARM_ARCH_8M_MAIN__ */

#endif /* __ARM_FEATURE_COPROC & 0x1 */

#if (__ARM_FEATURE_COPROC & 0x2)
#define __arm_cdp2(coproc, opc1, CRd, CRn, CRm, opc2) \
__builtin_arm_cdp2(coproc, opc1, CRd, CRn, CRm, opc2)
#define __arm_ldc2(coproc, CRd, p) __builtin_arm_ldc2(coproc, CRd, p)
#define __arm_stc2(coproc, CRd, p) __builtin_arm_stc2(coproc, CRd, p)
#define __arm_ldc2l(coproc, CRd, p) __builtin_arm_ldc2l(coproc, CRd, p)
#define __arm_stc2l(coproc, CRd, p) __builtin_arm_stc2l(coproc, CRd, p)
#define __arm_mcr2(coproc, opc1, value, CRn, CRm, opc2) \
__builtin_arm_mcr2(coproc, opc1, value, CRn, CRm, opc2)
#define __arm_mrc2(coproc, opc1, CRn, CRm, opc2) \
__builtin_arm_mrc2(coproc, opc1, CRn, CRm, opc2)
#endif

#if (__ARM_FEATURE_COPROC & 0x4)
#define __arm_mcrr(coproc, opc1, value, CRm) \
__builtin_arm_mcrr(coproc, opc1, value, CRm)
#define __arm_mrrc(coproc, opc1, CRm) __builtin_arm_mrrc(coproc, opc1, CRm)
#endif

#if (__ARM_FEATURE_COPROC & 0x8)
#define __arm_mcrr2(coproc, opc1, value, CRm) \
__builtin_arm_mcrr2(coproc, opc1, value, CRm)
#define __arm_mrrc2(coproc, opc1, CRm) __builtin_arm_mrrc2(coproc, opc1, CRm)
#endif

#endif // __ARM_FEATURE_COPROC

/* Transactional Memory Extension (TME) Intrinsics */
#if defined(__ARM_FEATURE_TME) && __ARM_FEATURE_TME

Expand Down
376 changes: 182 additions & 194 deletions clang/lib/Headers/ia32intrin.h

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions clang/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) {
// We do C++ by default; append right after argv[0] if no "-x" given
ClangArgv.insert(ClangArgv.end(), "-Xclang");
ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions");
ClangArgv.insert(ClangArgv.end(), "-mcpu=native");
ClangArgv.insert(ClangArgv.end(), "-c");

// Put a dummy C++ file on to ensure there's at least one compile job for the
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Lex/ModuleMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,9 @@ static void inferFrameworkLink(Module *Mod) {
assert(!Mod->isSubFramework() &&
"Can only infer linking for top-level frameworks");

Mod->LinkLibraries.push_back(Module::LinkLibrary(Mod->Name,
StringRef FrameworkName(Mod->Name);
FrameworkName.consume_back("_Private");
Mod->LinkLibraries.push_back(Module::LinkLibrary(FrameworkName.str(),
/*IsFramework=*/true));
}

Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2661,7 +2661,12 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
// ProduceConstructorSignatureHelp only on VarDecls.
ExpressionStarts = SetPreferredType;
}
if (ParseExpressionList(Exprs, ExpressionStarts)) {

bool SawError = ParseExpressionList(Exprs, ExpressionStarts);

InitScope.pop();

if (SawError) {
if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) {
Actions.ProduceConstructorSignatureHelp(
ThisVarDecl->getType()->getCanonicalTypeInternal(),
Expand All @@ -2674,7 +2679,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
} else {
// Match the ')'.
T.consumeClose();
InitScope.pop();

ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
T.getCloseLocation(),
Expand Down
26 changes: 22 additions & 4 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1974,10 +1974,11 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get());

// We try to parse a list of indexes in all language mode first
// and, in we find 0 or one index, we try to parse an OpenMP array
// and, in we find 0 or one index, we try to parse an OpenMP/OpenACC array
// section. This allow us to support C++23 multi dimensional subscript and
// OpenMp sections in the same language mode.
if (!getLangOpts().OpenMP || Tok.isNot(tok::colon)) {
// OpenMP/OpenACC sections in the same language mode.
if ((!getLangOpts().OpenMP && !AllowOpenACCArraySections) ||
Tok.isNot(tok::colon)) {
if (!getLangOpts().CPlusPlus23) {
ExprResult Idx;
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Expand All @@ -2001,7 +2002,18 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
}
}

if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) {
// Handle OpenACC first, since 'AllowOpenACCArraySections' is only enabled
// when actively parsing a 'var' in a 'var-list' during clause/'cache'
// parsing, so it is the most specific, and best allows us to handle
// OpenACC and OpenMP at the same time.
if (ArgExprs.size() <= 1 && AllowOpenACCArraySections) {
ColonProtectionRAIIObject RAII(*this);
if (Tok.is(tok::colon)) {
// Consume ':'
ColonLocFirst = ConsumeToken();
Length = Actions.CorrectDelayedTyposInExpr(ParseExpression());
}
} else if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) {
ColonProtectionRAIIObject RAII(*this);
if (Tok.is(tok::colon)) {
// Consume ':'
Expand Down Expand Up @@ -2031,6 +2043,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (!LHS.isInvalid() && !HasError && !Length.isInvalid() &&
!Stride.isInvalid() && Tok.is(tok::r_square)) {
if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) {
// FIXME: OpenACC hasn't implemented Sema/Array section handling at a
// semantic level yet. For now, just reuse the OpenMP implementation
// as it gets the parsing/type management mostly right, and we can
// replace this call to ActOnOpenACCArraySectionExpr in the future.
// Eventually we'll genericize the OPenMPArraySectionExpr type as
// well.
LHS = Actions.ActOnOMPArraySectionExpr(
LHS.get(), Loc, ArgExprs.empty() ? nullptr : ArgExprs[0],
ColonLocFirst, ColonLocSecond, Length.get(), Stride.get(), RLoc);
Expand Down
268 changes: 159 additions & 109 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,26 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) {
if (Tok.is(tok::kw_default))
return OpenACCClauseKind::Default;

// if is also a keyword, make sure we parse it correctly.
if (Tok.is(tok::kw_if))
return OpenACCClauseKind::If;

if (!Tok.is(tok::identifier))
return OpenACCClauseKind::Invalid;

return llvm::StringSwitch<OpenACCClauseKind>(
Tok.getIdentifierInfo()->getName())
.Case("auto", OpenACCClauseKind::Auto)
.Case("copy", OpenACCClauseKind::Copy)
.Case("default", OpenACCClauseKind::Default)
.Case("finalize", OpenACCClauseKind::Finalize)
.Case("if", OpenACCClauseKind::If)
.Case("if_present", OpenACCClauseKind::IfPresent)
.Case("independent", OpenACCClauseKind::Independent)
.Case("nohost", OpenACCClauseKind::NoHost)
.Case("self", OpenACCClauseKind::Self)
.Case("seq", OpenACCClauseKind::Seq)
.Case("use_device", OpenACCClauseKind::UseDevice)
.Case("vector", OpenACCClauseKind::Vector)
.Case("worker", OpenACCClauseKind::Worker)
.Default(OpenACCClauseKind::Invalid);
Expand Down Expand Up @@ -323,103 +331,168 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
return DirKind;
}

bool ClauseHasOptionalParens(OpenACCClauseKind Kind) {
return Kind == OpenACCClauseKind::Self;
}

bool ClauseHasRequiredParens(OpenACCClauseKind Kind) {
return Kind == OpenACCClauseKind::Default;
return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If ||
Kind == OpenACCClauseKind::Copy ||
Kind == OpenACCClauseKind::UseDevice;
}

ExprResult ParseOpenACCConditionalExpr(Parser &P) {
// FIXME: It isn't clear if the spec saying 'condition' means the same as
// it does in an if/while/etc (See ParseCXXCondition), however as it was
// written with Fortran/C in mind, we're going to assume it just means an
// 'expression evaluating to boolean'.
return P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression());
}

// Skip until we see the end of pragma token, but don't consume it. This is us
// just giving up on the rest of the pragma so we can continue executing. We
// have to do this because 'SkipUntil' considers paren balancing, which isn't
// what we want.
void SkipUntilEndOfDirective(Parser &P) {
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
P.ConsumeAnyToken();
}

bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) {
BalancedDelimiterTracker Parens(P, tok::l_paren,
} // namespace

// OpenACC 3.3, section 1.7:
// To simplify the specification and convey appropriate constraint information,
// a pqr-list is a comma-separated list of pdr items. The one exception is a
// clause-list, which is a list of one or more clauses optionally separated by
// commas.
void Parser::ParseOpenACCClauseList() {
bool FirstClause = true;
while (getCurToken().isNot(tok::annot_pragma_openacc_end)) {
// Comma is optional in a clause-list.
if (!FirstClause && getCurToken().is(tok::comma))
ConsumeToken();
FirstClause = false;

// Recovering from a bad clause is really difficult, so we just give up on
// error.
if (ParseOpenACCClause()) {
SkipUntilEndOfDirective(*this);
return;
}
}
}

bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) {
// FIXME: Future clauses will require 'special word' parsing, check for one,
// then parse it based on whether it is a clause that requires a 'special
// word'.
(void)Kind;

// If the var parsing fails, skip until the end of the directive as this is
// an expression and gets messy if we try to continue otherwise.
if (ParseOpenACCVar())
return true;

while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
ExpectAndConsume(tok::comma);

// If the var parsing fails, skip until the end of the directive as this is
// an expression and gets messy if we try to continue otherwise.
if (ParseOpenACCVar())
return true;
}
return false;
}
// The OpenACC Clause List is a comma or space-delimited list of clauses (see
// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
// really have its owner grammar and each individual one has its own definition.
// However, they all are named with a single-identifier (or auto/default!)
// token, followed in some cases by either braces or parens.
bool Parser::ParseOpenACCClause() {
// A number of clause names are actually keywords, so accept a keyword that
// can be converted to a name.
if (expectIdentifierOrKeyword(*this))
return true;

OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken());

if (Kind == OpenACCClauseKind::Invalid)
return Diag(getCurToken(), diag::err_acc_invalid_clause)
<< getCurToken().getIdentifierInfo();

// Consume the clause name.
ConsumeToken();

return ParseOpenACCClauseParams(Kind);
}

bool Parser::ParseOpenACCClauseParams(OpenACCClauseKind Kind) {
BalancedDelimiterTracker Parens(*this, tok::l_paren,
tok::annot_pragma_openacc_end);

if (ClauseHasRequiredParens(Kind)) {
if (Parens.expectAndConsume()) {
// We are missing a paren, so assume that the person just forgot the
// parameter. Return 'false' so we try to continue on and parse the next
// clause.
P.SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return false;
}

switch (Kind) {
case OpenACCClauseKind::Default: {
Token DefKindTok = P.getCurToken();
Token DefKindTok = getCurToken();

if (expectIdentifierOrKeyword(P))
if (expectIdentifierOrKeyword(*this))
break;

P.ConsumeToken();
ConsumeToken();

if (getOpenACCDefaultClauseKind(DefKindTok) ==
OpenACCDefaultClauseKind::Invalid)
P.Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);

break;
}
case OpenACCClauseKind::If: {
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
// An invalid expression can be just about anything, so just give up on
// this clause list.
if (CondExpr.isInvalid())
return true;
break;
}
case OpenACCClauseKind::UseDevice:
case OpenACCClauseKind::Copy:
if (ParseOpenACCClauseVarList(Kind))
return true;
break;
default:
llvm_unreachable("Not a required parens type?");
}

return Parens.consumeClose();
}
// FIXME: Handle optional parens
return false;
}

// The OpenACC Clause List is a comma or space-delimited list of clauses (see
// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
// really have its owner grammar and each individual one has its own definition.
// However, they all are named with a single-identifier (or auto/default!)
// token, followed in some cases by either braces or parens.
bool ParseOpenACCClause(Parser &P) {
if (!P.getCurToken().isOneOf(tok::identifier, tok::kw_auto, tok::kw_default))
return P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;

OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken());

if (Kind == OpenACCClauseKind::Invalid)
return P.Diag(P.getCurToken(), diag::err_acc_invalid_clause)
<< P.getCurToken().getIdentifierInfo();

// Consume the clause name.
P.ConsumeToken();

return ParseOpenACCClauseParams(P, Kind);
}

// Skip until we see the end of pragma token, but don't consume it. This is us
// just giving up on the rest of the pragma so we can continue executing. We
// have to do this because 'SkipUntil' considers paren balancing, which isn't
// what we want.
void SkipUntilEndOfDirective(Parser &P) {
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
P.ConsumeAnyToken();
}

// OpenACC 3.3, section 1.7:
// To simplify the specification and convey appropriate constraint information,
// a pqr-list is a comma-separated list of pdr items. The one exception is a
// clause-list, which is a list of one or more clauses optionally separated by
// commas.
void ParseOpenACCClauseList(Parser &P) {
bool FirstClause = true;
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) {
// Comma is optional in a clause-list.
if (!FirstClause && P.getCurToken().is(tok::comma))
P.ConsumeToken();
FirstClause = false;

// Recovering from a bad clause is really difficult, so we just give up on
// error.
if (ParseOpenACCClause(P)) {
SkipUntilEndOfDirective(P);
return;
} else if (ClauseHasOptionalParens(Kind)) {
if (!Parens.consumeOpen()) {
switch (Kind) {
case OpenACCClauseKind::Self: {
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
// An invalid expression can be just about anything, so just give up on
// this clause list.
if (CondExpr.isInvalid())
return true;
break;
}
default:
llvm_unreachable("Not an optional parens type?");
}
Parens.consumeClose();
}
}
return false;
}

} // namespace

/// OpenACC 3.3, section 2.16:
/// In this section and throughout the specification, the term wait-argument
/// means:
Expand Down Expand Up @@ -511,49 +584,17 @@ ExprResult Parser::ParseOpenACCIDExpression() {
return getActions().CorrectDelayedTyposInExpr(Res);
}

/// OpenACC 3.3, section 2.10:
/// A 'var' in a cache directive must be a single array element or a simple
/// subarray. In C and C++, a simple subarray is an array name followed by an
/// extended array range specification in brackets, with a start and length such
/// as:
///
/// arr[lower:length]
///
bool Parser::ParseOpenACCCacheVar() {
ExprResult ArrayName = ParseOpenACCIDExpression();
if (ArrayName.isInvalid())
return true;

// If the expression is invalid, just continue parsing the brackets, there
// is likely other useful diagnostics we can emit inside of those.

BalancedDelimiterTracker SquareBrackets(*this, tok::l_square,
tok::annot_pragma_openacc_end);

// Square brackets are required, so error here, and try to recover by moving
// until the next comma, or the close paren/end of pragma.
if (SquareBrackets.expectAndConsume()) {
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,
Parser::StopBeforeMatch);
return true;
}

ExprResult Lower = getActions().CorrectDelayedTyposInExpr(ParseExpression());
if (Lower.isInvalid())
return true;

// The 'length' expression is optional, as this could be a single array
// element. If there is no colon, we can treat it as that.
if (getCurToken().is(tok::colon)) {
ConsumeToken();
ExprResult Length =
getActions().CorrectDelayedTyposInExpr(ParseExpression());
if (Length.isInvalid())
return true;
}

// Diagnose the square bracket being in the wrong place and continue.
return SquareBrackets.consumeClose();
/// OpenACC 3.3, section 1.6:
/// In this spec, a 'var' (in italics) is one of the following:
/// - a variable name (a scalar, array, or compisite variable name)
/// - a subarray specification with subscript ranges
/// - an array element
/// - a member of a composite variable
/// - a common block name between slashes (fortran only)
bool Parser::ParseOpenACCVar() {
OpenACCArraySectionRAII ArraySections(*this);
ExprResult Res = ParseAssignmentExpression();
return Res.isInvalid();
}

/// OpenACC 3.3, section 2.10:
Expand Down Expand Up @@ -584,7 +625,16 @@ void Parser::ParseOpenACCCacheVarList() {
if (!FirstArray)
ExpectAndConsume(tok::comma);
FirstArray = false;
if (ParseOpenACCCacheVar())

// OpenACC 3.3, section 2.10:
// A 'var' in a cache directive must be a single array element or a simple
// subarray. In C and C++, a simple subarray is an array name followed by
// an extended array range specification in brackets, with a start and
// length such as:
//
// arr[lower:length]
//
if (ParseOpenACCVar())
SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma,
StopBeforeMatch);
}
Expand Down Expand Up @@ -644,7 +694,7 @@ void Parser::ParseOpenACCDirective() {
}

// Parses the list of clauses, if present.
ParseOpenACCClauseList(*this);
ParseOpenACCClauseList();

Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
assert(Tok.is(tok::annot_pragma_openacc_end) &&
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18376,7 +18376,7 @@ static bool isSetterLikeSelector(Selector sel) {
if (sel.isUnarySelector()) return false;

StringRef str = sel.getNameForSlot(0);
while (!str.empty() && str.front() == '_') str = str.substr(1);
str = str.ltrim('_');
if (str.starts_with("set"))
str = str.substr(3);
else if (str.starts_with("add")) {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2315,6 +2315,12 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
}
ShadowingDecls.erase(ShadowI);
}

if (!getLangOpts().CPlusPlus && S->isClassScope()) {
if (auto *FD = dyn_cast<FieldDecl>(TmpD);
FD && FD->hasAttr<CountedByAttr>())
CheckCountedByAttr(S, FD);
}
}

llvm::sort(DeclDiags,
Expand Down
133 changes: 133 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8460,6 +8460,135 @@ static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(ZeroCallUsedRegsAttr::Create(S.Context, Kind, AL));
}

static void handleCountedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.isArgIdent(0)) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIdentifier;
return;
}

IdentifierLoc *IL = AL.getArgAsIdent(0);
CountedByAttr *CBA =
::new (S.Context) CountedByAttr(S.Context, AL, IL->Ident);
CBA->setCountedByFieldLoc(IL->Loc);
D->addAttr(CBA);
}

static const FieldDecl *
FindFieldInTopLevelOrAnonymousStruct(const RecordDecl *RD,
const IdentifierInfo *FieldName) {
for (const Decl *D : RD->decls()) {
if (const auto *FD = dyn_cast<FieldDecl>(D))
if (FD->getName() == FieldName->getName())
return FD;

if (const auto *R = dyn_cast<RecordDecl>(D))
if (const FieldDecl *FD =
FindFieldInTopLevelOrAnonymousStruct(R, FieldName))
return FD;
}

return nullptr;
}

bool Sema::CheckCountedByAttr(Scope *S, const FieldDecl *FD) {
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
LangOptions::StrictFlexArraysLevelKind::IncompleteOnly;
if (!Decl::isFlexibleArrayMemberLike(Context, FD, FD->getType(),
StrictFlexArraysLevel, true)) {
// The "counted_by" attribute must be on a flexible array member.
SourceRange SR = FD->getLocation();
Diag(SR.getBegin(), diag::err_counted_by_attr_not_on_flexible_array_member)
<< SR;
return true;
}

const auto *CBA = FD->getAttr<CountedByAttr>();
const IdentifierInfo *FieldName = CBA->getCountedByField();

auto GetNonAnonStructOrUnion = [](const RecordDecl *RD) {
while (RD && !RD->getDeclName())
if (const auto *R = dyn_cast<RecordDecl>(RD->getDeclContext()))
RD = R;
else
break;

return RD;
};

const RecordDecl *EnclosingRD = GetNonAnonStructOrUnion(FD->getParent());
const FieldDecl *CountFD =
FindFieldInTopLevelOrAnonymousStruct(EnclosingRD, FieldName);

if (!CountFD) {
DeclarationNameInfo NameInfo(FieldName,
CBA->getCountedByFieldLoc().getBegin());
LookupResult MemResult(*this, NameInfo, Sema::LookupMemberName);
LookupName(MemResult, S);

if (!MemResult.empty()) {
SourceRange SR = CBA->getCountedByFieldLoc();
Diag(SR.getBegin(), diag::err_flexible_array_count_not_in_same_struct)
<< CBA->getCountedByField() << SR;

if (auto *ND = MemResult.getAsSingle<NamedDecl>()) {
SR = ND->getLocation();
Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field)
<< ND << SR;
}

return true;
} else {
// The "counted_by" field needs to exist in the struct.
LookupResult OrdResult(*this, NameInfo, Sema::LookupOrdinaryName);
LookupName(OrdResult, S);

if (!OrdResult.empty()) {
SourceRange SR = FD->getLocation();
Diag(SR.getBegin(), diag::err_counted_by_must_be_in_structure)
<< FieldName << SR;

if (auto *ND = OrdResult.getAsSingle<NamedDecl>()) {
SR = ND->getLocation();
Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field)
<< ND << SR;
}

return true;
}
}

CXXScopeSpec SS;
DeclFilterCCC<FieldDecl> Filter(FieldName);
return DiagnoseEmptyLookup(S, SS, MemResult, Filter, nullptr, std::nullopt,
const_cast<DeclContext *>(FD->getDeclContext()));
}

if (CountFD->hasAttr<CountedByAttr>()) {
// The "counted_by" field can't point to the flexible array member.
SourceRange SR = CBA->getCountedByFieldLoc();
Diag(SR.getBegin(), diag::err_counted_by_attr_refers_to_flexible_array)
<< CBA->getCountedByField() << SR;
return true;
}

if (!CountFD->getType()->isIntegerType() ||
CountFD->getType()->isBooleanType()) {
// The "counted_by" field must have an integer type.
SourceRange SR = CBA->getCountedByFieldLoc();
Diag(SR.getBegin(),
diag::err_flexible_array_counted_by_attr_field_not_integer)
<< CBA->getCountedByField() << SR;

SR = CountFD->getLocation();
Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field)
<< CountFD << SR;
return true;
}

return false;
}

static void handleFunctionReturnThunksAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
StringRef KindStr;
Expand Down Expand Up @@ -9420,6 +9549,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleAvailableOnlyInDefaultEvalMethod(S, D, AL);
break;

case ParsedAttr::AT_CountedBy:
handleCountedByAttr(S, D, AL);
break;

// Microsoft attributes:
case ParsedAttr::AT_LayoutVersion:
handleLayoutVersion(S, D, AL);
Expand Down
60 changes: 30 additions & 30 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2469,7 +2469,8 @@ bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) {
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CorrectionCandidateCallback &CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs,
ArrayRef<Expr *> Args, TypoExpr **Out) {
ArrayRef<Expr *> Args, DeclContext *LookupCtx,
TypoExpr **Out) {
DeclarationName Name = R.getLookupName();

unsigned diagnostic = diag::err_undeclared_var_use;
Expand All @@ -2485,7 +2486,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// unqualified lookup. This is useful when (for example) the
// original lookup would not have found something because it was a
// dependent name.
DeclContext *DC = SS.isEmpty() ? CurContext : nullptr;
DeclContext *DC =
LookupCtx ? LookupCtx : (SS.isEmpty() ? CurContext : nullptr);
while (DC) {
if (isa<CXXRecordDecl>(DC)) {
LookupQualifiedName(R, DC);
Expand Down Expand Up @@ -2528,12 +2530,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args,
diagnostic, diagnostic_suggest);
},
nullptr, CTK_ErrorRecovery);
nullptr, CTK_ErrorRecovery, LookupCtx);
if (*Out)
return true;
} else if (S &&
(Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
S, &SS, CCC, CTK_ErrorRecovery))) {
} else if (S && (Corrected =
CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S,
&SS, CCC, CTK_ErrorRecovery, LookupCtx))) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
Expand Down Expand Up @@ -2823,7 +2825,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// a template name, but we happen to have always already looked up the name
// before we get here if it must be a template name.
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr,
std::nullopt, &TE)) {
std::nullopt, nullptr, &TE)) {
if (TE && KeywordReplacement) {
auto &State = getTypoExprState(TE);
auto BestTC = State.Consumer->getNextCorrection();
Expand Down Expand Up @@ -8691,10 +8693,10 @@ ExprResult Sema::ActOnParenListExpr(SourceLocation L,
/// Emit a specialized diagnostic when one expression is a null pointer
/// constant and the other is not a pointer. Returns true if a diagnostic is
/// emitted.
bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
bool Sema::DiagnoseConditionalForNull(const Expr *LHSExpr, const Expr *RHSExpr,
SourceLocation QuestionLoc) {
Expr *NullExpr = LHSExpr;
Expr *NonPointerExpr = RHSExpr;
const Expr *NullExpr = LHSExpr;
const Expr *NonPointerExpr = RHSExpr;
Expr::NullPointerConstantKind NullKind =
NullExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNotNull);
Expand Down Expand Up @@ -8730,7 +8732,8 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
}

/// Return false if the condition expression is valid, true otherwise.
static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) {
static bool checkCondition(Sema &S, const Expr *Cond,
SourceLocation QuestionLoc) {
QualType CondTy = Cond->getType();

// OpenCL v1.1 s6.3.i says the condition cannot be a floating point type.
Expand Down Expand Up @@ -9542,28 +9545,27 @@ static bool IsArithmeticOp(BinaryOperatorKind Opc) {
/// expression, either using a built-in or overloaded operator,
/// and sets *OpCode to the opcode and *RHSExprs to the right-hand side
/// expression.
static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
Expr **RHSExprs) {
static bool IsArithmeticBinaryExpr(const Expr *E, BinaryOperatorKind *Opcode,
const Expr **RHSExprs) {
// Don't strip parenthesis: we should not warn if E is in parenthesis.
E = E->IgnoreImpCasts();
E = E->IgnoreConversionOperatorSingleStep();
E = E->IgnoreImpCasts();
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
E = MTE->getSubExpr();
E = E->IgnoreImpCasts();
}

// Built-in binary operator.
if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) {
if (IsArithmeticOp(OP->getOpcode())) {
*Opcode = OP->getOpcode();
*RHSExprs = OP->getRHS();
return true;
}
if (const auto *OP = dyn_cast<BinaryOperator>(E);
OP && IsArithmeticOp(OP->getOpcode())) {
*Opcode = OP->getOpcode();
*RHSExprs = OP->getRHS();
return true;
}

// Overloaded operator.
if (CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(E)) {
if (const auto *Call = dyn_cast<CXXOperatorCallExpr>(E)) {
if (Call->getNumArgs() != 2)
return false;

Expand All @@ -9588,14 +9590,14 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
/// ExprLooksBoolean - Returns true if E looks boolean, i.e. it has boolean type
/// or is a logical expression such as (x==y) which has int type, but is
/// commonly interpreted as boolean.
static bool ExprLooksBoolean(Expr *E) {
static bool ExprLooksBoolean(const Expr *E) {
E = E->IgnoreParenImpCasts();

if (E->getType()->isBooleanType())
return true;
if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E))
if (const auto *OP = dyn_cast<BinaryOperator>(E))
return OP->isComparisonOp() || OP->isLogicalOp();
if (UnaryOperator *OP = dyn_cast<UnaryOperator>(E))
if (const auto *OP = dyn_cast<UnaryOperator>(E))
return OP->getOpcode() == UO_LNot;
if (E->getType()->isPointerType())
return true;
Expand All @@ -9609,13 +9611,11 @@ static bool ExprLooksBoolean(Expr *E) {
/// and binary operator are mixed in a way that suggests the programmer assumed
/// the conditional operator has higher precedence, for example:
/// "int x = a + someBinaryCondition ? 1 : 2".
static void DiagnoseConditionalPrecedence(Sema &Self,
SourceLocation OpLoc,
Expr *Condition,
Expr *LHSExpr,
Expr *RHSExpr) {
static void DiagnoseConditionalPrecedence(Sema &Self, SourceLocation OpLoc,
Expr *Condition, const Expr *LHSExpr,
const Expr *RHSExpr) {
BinaryOperatorKind CondOpcode;
Expr *CondRHS;
const Expr *CondRHS;

if (!IsArithmeticBinaryExpr(Condition, &CondOpcode, &CondRHS))
return;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,8 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
const Scope *S,
ActOnMemberAccessExtraArgs *ExtraArgs) {
if (BaseType->isDependentType() ||
(SS.isSet() && isDependentScopeSpecifier(SS)))
(SS.isSet() && isDependentScopeSpecifier(SS)) ||
NameInfo.getName().isDependentName())
return ActOnDependentMemberExpr(Base, BaseType,
IsArrow, OpLoc,
SS, TemplateKWLoc, FirstQualifierInScope,
Expand Down
52 changes: 24 additions & 28 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10377,11 +10377,6 @@ void InitializationSequence::dump() const {
dump(llvm::errs());
}

static bool NarrowingErrs(const LangOptions &L) {
return L.CPlusPlus11 &&
(!L.MicrosoftExt || L.isCompatibleWithMSVC(LangOptions::MSVC2015));
}

static void DiagnoseNarrowingInInitList(Sema &S,
const ImplicitConversionSequence &ICS,
QualType PreNarrowingType,
Expand All @@ -10402,6 +10397,19 @@ static void DiagnoseNarrowingInInitList(Sema &S,
return;
}

auto MakeDiag = [&](bool IsConstRef, unsigned DefaultDiagID,
unsigned ConstRefDiagID, unsigned WarnDiagID) {
unsigned DiagID;
auto &L = S.getLangOpts();
if (L.CPlusPlus11 &&
(!L.MicrosoftExt || L.isCompatibleWithMSVC(LangOptions::MSVC2015)))
DiagID = IsConstRef ? ConstRefDiagID : DefaultDiagID;
else
DiagID = WarnDiagID;
return S.Diag(PostInit->getBeginLoc(), DiagID)
<< PostInit->getSourceRange();
};

// C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion.
APValue ConstantValue;
QualType ConstantType;
Expand All @@ -10417,43 +10425,31 @@ static void DiagnoseNarrowingInInitList(Sema &S,
// narrowing conversion even if the value is a constant and can be
// represented exactly as an integer.
QualType T = EntityType.getNonReferenceType();
S.Diag(PostInit->getBeginLoc(),
NarrowingErrs(S.getLangOpts())
? (T == EntityType
? diag::ext_init_list_type_narrowing
: diag::ext_init_list_type_narrowing_const_reference)
: diag::warn_init_list_type_narrowing)
<< PostInit->getSourceRange()
MakeDiag(T != EntityType, diag::ext_init_list_type_narrowing,
diag::ext_init_list_type_narrowing_const_reference,
diag::warn_init_list_type_narrowing)
<< PreNarrowingType.getLocalUnqualifiedType()
<< T.getLocalUnqualifiedType();
break;
}

case NK_Constant_Narrowing: {
// A constant value was narrowed.
QualType T = EntityType.getNonReferenceType();
S.Diag(PostInit->getBeginLoc(),
NarrowingErrs(S.getLangOpts())
? (T == EntityType
? diag::ext_init_list_constant_narrowing
: diag::ext_init_list_constant_narrowing_const_reference)
: diag::warn_init_list_constant_narrowing)
<< PostInit->getSourceRange()
MakeDiag(EntityType.getNonReferenceType() != EntityType,
diag::ext_init_list_constant_narrowing,
diag::ext_init_list_constant_narrowing_const_reference,
diag::warn_init_list_constant_narrowing)
<< ConstantValue.getAsString(S.getASTContext(), ConstantType)
<< EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;
}

case NK_Variable_Narrowing: {
// A variable's value may have been narrowed.
QualType T = EntityType.getNonReferenceType();
S.Diag(PostInit->getBeginLoc(),
NarrowingErrs(S.getLangOpts())
? (T == EntityType
? diag::ext_init_list_variable_narrowing
: diag::ext_init_list_variable_narrowing_const_reference)
: diag::warn_init_list_variable_narrowing)
<< PostInit->getSourceRange()
MakeDiag(EntityType.getNonReferenceType() != EntityType,
diag::ext_init_list_variable_narrowing,
diag::ext_init_list_variable_narrowing_const_reference,
diag::warn_init_list_variable_narrowing)
<< PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;
Expand Down
Loading