74 changes: 73 additions & 1 deletion clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include "clang/AST/Type.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/PartialDiagnostic.h"
Expand Down Expand Up @@ -411,6 +410,79 @@ bool Decl::isFileContextDecl() const {
return DC && DC->isFileContext();
}

bool Decl::isFlexibleArrayMemberLike(
ASTContext &Ctx, const Decl *D, QualType Ty,
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
bool IgnoreTemplateOrMacroSubstitution) {
// For compatibility with existing code, we treat arrays of length 0 or
// 1 as flexible array members.
const auto *CAT = Ctx.getAsConstantArrayType(Ty);
if (CAT) {
using FAMKind = LangOptions::StrictFlexArraysLevelKind;

llvm::APInt Size = CAT->getSize();
if (StrictFlexArraysLevel == FAMKind::IncompleteOnly)
return false;

// GCC extension, only allowed to represent a FAM.
if (Size.isZero())
return true;

if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1))
return false;

if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2))
return false;
} else if (!Ctx.getAsIncompleteArrayType(Ty)) {
return false;
}

if (const auto *OID = dyn_cast_if_present<ObjCIvarDecl>(D))
return OID->getNextIvar() == nullptr;

const auto *FD = dyn_cast_if_present<FieldDecl>(D);
if (!FD)
return false;

if (CAT) {
// GCC treats an array memeber of a union as an FAM if the size is one or
// zero.
llvm::APInt Size = CAT->getSize();
if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne()))
return true;
}

// Don't consider sizes resulting from macro expansions or template argument
// substitution to form C89 tail-padded arrays.
if (IgnoreTemplateOrMacroSubstitution) {
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
while (TInfo) {
TypeLoc TL = TInfo->getTypeLoc();

// Look through typedefs.
if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
TInfo = TDL->getTypeSourceInfo();
continue;
}

if (auto CTL = TL.getAs<ConstantArrayTypeLoc>()) {
if (const Expr *SizeExpr =
dyn_cast_if_present<IntegerLiteral>(CTL.getSizeExpr());
!SizeExpr || SizeExpr->getExprLoc().isMacroID())
return false;
}

break;
}
}

// Test that the field is the last in the structure.
RecordDecl::field_iterator FI(
DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
return ++FI == FD->getParent()->field_end();
}

TranslationUnitDecl *Decl::getTranslationUnitDecl() {
if (auto *TUD = dyn_cast<TranslationUnitDecl>(this))
return TUD;
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,19 @@ bool CXXRecordDecl::isTriviallyCopyable() const {
return true;
}

bool CXXRecordDecl::isTriviallyCopyConstructible() const {

// A trivially copy constructible class is a class that:
// -- has no non-trivial copy constructors,
if (hasNonTrivialCopyConstructor())
return false;
// -- has a trivial destructor.
if (!hasTrivialDestructor())
return false;

return true;
}

void CXXRecordDecl::markedVirtualFunctionPure() {
// C++ [class.abstract]p2:
// A class is abstract if it has at least one pure virtual function.
Expand Down
83 changes: 10 additions & 73 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,85 +205,22 @@ bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
}

bool Expr::isFlexibleArrayMemberLike(
ASTContext &Context,
ASTContext &Ctx,
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
bool IgnoreTemplateOrMacroSubstitution) const {

// For compatibility with existing code, we treat arrays of length 0 or
// 1 as flexible array members.
const auto *CAT = Context.getAsConstantArrayType(getType());
if (CAT) {
llvm::APInt Size = CAT->getSize();

using FAMKind = LangOptions::StrictFlexArraysLevelKind;

if (StrictFlexArraysLevel == FAMKind::IncompleteOnly)
return false;

// GCC extension, only allowed to represent a FAM.
if (Size == 0)
return true;

if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1))
return false;

if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2))
return false;
} else if (!Context.getAsIncompleteArrayType(getType()))
return false;

const Expr *E = IgnoreParens();
const Decl *D = nullptr;

const NamedDecl *ND = nullptr;
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
ND = DRE->getDecl();
else if (const auto *ME = dyn_cast<MemberExpr>(E))
ND = ME->getMemberDecl();
if (const auto *ME = dyn_cast<MemberExpr>(E))
D = ME->getMemberDecl();
else if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
D = DRE->getDecl();
else if (const auto *IRE = dyn_cast<ObjCIvarRefExpr>(E))
return IRE->getDecl()->getNextIvar() == nullptr;

if (!ND)
return false;
D = IRE->getDecl();

// A flexible array member must be the last member in the class.
// FIXME: If the base type of the member expr is not FD->getParent(),
// this should not be treated as a flexible array member access.
if (const auto *FD = dyn_cast<FieldDecl>(ND)) {
// GCC treats an array memeber of a union as an FAM if the size is one or
// zero.
if (CAT) {
llvm::APInt Size = CAT->getSize();
if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne()))
return true;
}

// Don't consider sizes resulting from macro expansions or template argument
// substitution to form C89 tail-padded arrays.
if (IgnoreTemplateOrMacroSubstitution) {
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
while (TInfo) {
TypeLoc TL = TInfo->getTypeLoc();
// Look through typedefs.
if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
TInfo = TDL->getTypeSourceInfo();
continue;
}
if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
return false;
}
break;
}
}

RecordDecl::field_iterator FI(
DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
return ++FI == FD->getParent()->field_end();
}

return false;
return Decl::isFlexibleArrayMemberLike(Ctx, D, E->getType(),
StrictFlexArraysLevel,
IgnoreTemplateOrMacroSubstitution);
}

const ValueDecl *
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/FormatString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,6 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
return NoMatchPromotionTypeConfusion;
break;
case BuiltinType::Half:
case BuiltinType::Float16:
case BuiltinType::Float:
if (T == C.DoubleTy)
return MatchPromotion;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,17 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
}

case CK_FloatingCast: {
if (DiscardResult)
return this->discard(SubExpr);
if (!this->visit(SubExpr))
return false;
const auto *TargetSemantics = &Ctx.getFloatSemantics(CE->getType());
return this->emitCastFP(TargetSemantics, getRoundingMode(CE), CE);
}

case CK_IntegralToFloating: {
if (DiscardResult)
return this->discard(SubExpr);
std::optional<PrimType> FromT = classify(SubExpr->getType());
if (!FromT)
return false;
Expand All @@ -135,6 +139,9 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {

case CK_FloatingToBoolean:
case CK_FloatingToIntegral: {
if (DiscardResult)
return this->discard(SubExpr);

std::optional<PrimType> ToT = classify(CE->getType());

if (!ToT)
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/AST/Interp/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
}

/// Unknown-size arrays of composite elements.
Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary,
UnknownSize)
Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem,
bool IsTemporary, UnknownSize)
: Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
Size(UnknownSizeMark), MDSize(0),
AllocSize(alignof(void *) + sizeof(InitMapPtr)), ElemDesc(Elem),
Expand All @@ -286,7 +286,7 @@ Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary,
}

/// Composite records.
Descriptor::Descriptor(const DeclTy &D, Record *R, MetadataSize MD,
Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
bool IsConst, bool IsTemporary, bool IsMutable)
: Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ struct Descriptor final {
static constexpr MetadataSize InlineDescMD = sizeof(InlineDescriptor);

/// Pointer to the record, if block contains records.
Record *const ElemRecord = nullptr;
const Record *const ElemRecord = nullptr;
/// Descriptor of the array element.
const Descriptor *const ElemDesc = nullptr;
/// Flag indicating if the block is mutable.
Expand Down Expand Up @@ -135,10 +135,11 @@ struct Descriptor final {
unsigned NumElems, bool IsConst, bool IsTemporary, bool IsMutable);

/// Allocates a descriptor for an array of composites of unknown size.
Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, UnknownSize);
Descriptor(const DeclTy &D, const Descriptor *Elem, bool IsTemporary,
UnknownSize);

/// Allocates a descriptor for a record.
Descriptor(const DeclTy &D, Record *R, MetadataSize MD, bool IsConst,
Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst,
bool IsTemporary, bool IsMutable);

Descriptor(const DeclTy &D, MetadataSize MD);
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,18 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
if (CurFunc->isUnevaluatedBuiltin())
return;

// Some builtin functions require us to only look at the call site, since
// the classified parameter types do not match.
if (CurFunc->isBuiltin()) {
const auto *CE =
cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
const Expr *A = CE->getArg(I);
popArg(S, A);
}
return;
}

if (S.Current->Caller && CurFunc->isVariadic()) {
// CallExpr we're look for is at the return PC of the current function, i.e.
// in the caller.
Expand Down Expand Up @@ -290,10 +302,10 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
}

bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckLive(S, OpPC, Ptr, AK_Read))
return false;
if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckExtern(S, OpPC, Ptr))
return false;
if (!CheckRange(S, OpPC, Ptr, AK_Read))
Expand Down
6 changes: 0 additions & 6 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1813,9 +1813,6 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>();

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

if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
return false;

Expand Down Expand Up @@ -1843,9 +1840,6 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();

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

if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
return false;

Expand Down
33 changes: 30 additions & 3 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
case X: \
return Ret<X>(S, OpPC, Result);
switch (*T) {
RET_CASE(PT_Ptr);
RET_CASE(PT_FnPtr);
RET_CASE(PT_Float);
RET_CASE(PT_Bool);
RET_CASE(PT_Sint8);
Expand Down Expand Up @@ -613,15 +615,34 @@ static bool interp__builtin_ffs(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
PrimType PtrT =
S.getContext().classify(Call->getArg(0)->getType()).value_or(PT_Ptr);

if (PtrT == PT_FnPtr) {
const FunctionPointer &Arg = S.Stk.peek<FunctionPointer>();
S.Stk.push<FunctionPointer>(Arg);
} else if (PtrT == PT_Ptr) {
const Pointer &Arg = S.Stk.peek<Pointer>();
S.Stk.push<Pointer>(Arg);
} else {
assert(false && "Unsupported pointer type passed to __builtin_addressof()");
}
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
InterpFrame *Frame = S.Current;
APValue Dummy;

QualType ReturnType = Call->getCallReturnType(S.getCtx());
std::optional<PrimType> ReturnT = S.getContext().classify(ReturnType);
std::optional<PrimType> ReturnT = S.getContext().classify(Call->getType());

// If classify failed, we assume void.
assert(ReturnT || ReturnType->isVoidType());
assert(ReturnT || Call->getType()->isVoidType());

switch (F->getBuiltinID()) {
case Builtin::BI__builtin_is_constant_evaluated:
Expand Down Expand Up @@ -820,6 +841,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
if (!interp__builtin_ffs(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BIaddressof:
case Builtin::BI__addressof:
case Builtin::BI__builtin_addressof:
if (!interp__builtin_addressof(S, OpPC, Frame, F, Call))
return false;
break;

default:
return false;
Expand Down
16 changes: 8 additions & 8 deletions clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,14 +315,14 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
bool IsConst, bool IsTemporary,
bool IsMutable, const Expr *Init) {
// Classes and structures.
if (auto *RT = Ty->getAs<RecordType>()) {
if (auto *Record = getOrCreateRecord(RT->getDecl()))
if (const auto *RT = Ty->getAs<RecordType>()) {
if (const auto *Record = getOrCreateRecord(RT->getDecl()))
return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
IsMutable);
}

// Arrays.
if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
QualType ElemTy = ArrayType->getElementType();
// Array of well-known bounds.
if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
Expand All @@ -338,7 +338,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
} else {
// Arrays of composites. In this case, the array is a list of pointers,
// followed by the actual elements.
Descriptor *ElemDesc = createDescriptor(
const Descriptor *ElemDesc = createDescriptor(
D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
if (!ElemDesc)
return nullptr;
Expand All @@ -358,8 +358,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
return allocateDescriptor(D, *T, IsTemporary,
Descriptor::UnknownSize{});
} else {
Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), MDSize,
IsConst, IsTemporary);
const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(),
MDSize, IsConst, IsTemporary);
if (!Desc)
return nullptr;
return allocateDescriptor(D, Desc, IsTemporary,
Expand All @@ -369,14 +369,14 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
}

// Atomic types.
if (auto *AT = Ty->getAs<AtomicType>()) {
if (const auto *AT = Ty->getAs<AtomicType>()) {
const Type *InnerTy = AT->getValueType().getTypePtr();
return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary,
IsMutable);
}

// Complex types - represented as arrays of elements.
if (auto *CT = Ty->getAs<ComplexType>()) {
if (const auto *CT = Ty->getAs<ComplexType>()) {
PrimType ElemTy = *Ctx.classify(CT->getElementType());
return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary,
IsMutable);
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,16 @@ void clang::TextNodeDumper::VisitReturnStmt(const ReturnStmt *Node) {
}
}

void clang::TextNodeDumper::VisitCoawaitExpr(const CoawaitExpr *Node) {
if (Node->isImplicit())
OS << " implicit";
}

void clang::TextNodeDumper::VisitCoreturnStmt(const CoreturnStmt *Node) {
if (Node->isImplicit())
OS << " implicit";
}

void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) {
if (Node->hasAPValueResult())
AddChild("value",
Expand Down
34 changes: 25 additions & 9 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2604,19 +2604,22 @@ bool QualType::isTrivialType(const ASTContext &Context) const {
return false;
}

bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
if ((*this)->isArrayType())
return Context.getBaseElementType(*this).isTriviallyCopyableType(Context);
static bool isTriviallyCopyableTypeImpl(const QualType &type,
const ASTContext &Context,
bool IsCopyConstructible) {
if (type->isArrayType())
return isTriviallyCopyableTypeImpl(Context.getBaseElementType(type),
Context, IsCopyConstructible);

if (hasNonTrivialObjCLifetime())
if (type.hasNonTrivialObjCLifetime())
return false;

// C++11 [basic.types]p9 - See Core 2094
// Scalar types, trivially copyable class types, arrays of such types, and
// cv-qualified versions of these types are collectively
// called trivially copyable types.
// called trivially copy constructible types.

QualType CanonicalType = getCanonicalType();
QualType CanonicalType = type.getCanonicalType();
if (CanonicalType->isDependentType())
return false;

Expand All @@ -2634,16 +2637,29 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {

if (const auto *RT = CanonicalType->getAs<RecordType>()) {
if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->isTriviallyCopyable()) return false;
if (IsCopyConstructible) {
return ClassDecl->isTriviallyCopyConstructible();
} else {
return ClassDecl->isTriviallyCopyable();
}
}

return true;
}

// No other types can match.
return false;
}

bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
return isTriviallyCopyableTypeImpl(*this, Context,
/*IsCopyConstructible=*/false);
}

bool QualType::isTriviallyCopyConstructibleType(
const ASTContext &Context) const {
return isTriviallyCopyableTypeImpl(*this, Context,
/*IsCopyConstructible=*/true);
}

bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const {
QualType BaseElementType = Context.getBaseElementType(*this);

Expand Down
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.

67 changes: 42 additions & 25 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 @@ -1425,12 +1431,24 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
const std::string &TypeEncoding) override {
return GetConstantSelector(Sel, TypeEncoding);
}
std::string GetSymbolNameForTypeEncoding(const std::string &TypeEncoding) {
std::string MangledTypes = std::string(TypeEncoding);
// @ is used as a special character in ELF symbol names (used for symbol
// versioning), so mangle the name to not include it. Replace it with a
// character that is not a valid type encoding character (and, being
// non-printable, never will be!)
if (CGM.getTriple().isOSBinFormatELF())
std::replace(MangledTypes.begin(), MangledTypes.end(), '@', '\1');
// = in dll exported names causes lld to fail when linking on Windows.
if (CGM.getTriple().isOSWindows())
std::replace(MangledTypes.begin(), MangledTypes.end(), '=', '\2');
return MangledTypes;
}
llvm::Constant *GetTypeString(llvm::StringRef TypeEncoding) {
if (TypeEncoding.empty())
return NULLPtr;
std::string MangledTypes = std::string(TypeEncoding);
std::replace(MangledTypes.begin(), MangledTypes.end(),
'@', '\1');
std::string MangledTypes =
GetSymbolNameForTypeEncoding(std::string(TypeEncoding));
std::string TypesVarName = ".objc_sel_types_" + MangledTypes;
auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName);
if (!TypesGlobal) {
Expand All @@ -1447,13 +1465,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
}
llvm::Constant *GetConstantSelector(Selector Sel,
const std::string &TypeEncoding) override {
// @ is used as a special character in symbol names (used for symbol
// versioning), so mangle the name to not include it. Replace it with a
// character that is not a valid type encoding character (and, being
// non-printable, never will be!)
std::string MangledTypes = TypeEncoding;
std::replace(MangledTypes.begin(), MangledTypes.end(),
'@', '\1');
std::string MangledTypes = GetSymbolNameForTypeEncoding(TypeEncoding);
auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" +
MangledTypes).str();
if (auto *GV = TheModule.getNamedGlobal(SelVarName))
Expand Down Expand Up @@ -1665,9 +1677,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
const ObjCIvarDecl *Ivar) override {
std::string TypeEncoding;
CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding);
// Prevent the @ from being interpreted as a symbol version.
std::replace(TypeEncoding.begin(), TypeEncoding.end(),
'@', '\1');
TypeEncoding = GetSymbolNameForTypeEncoding(TypeEncoding);
const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
+ '.' + Ivar->getNameAsString() + '.' + TypeEncoding;
return Name;
Expand Down Expand Up @@ -1851,6 +1861,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 +2136,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 +2225,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 +2405,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 +4011,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 +4021,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
4 changes: 3 additions & 1 deletion 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 Expand Up @@ -1199,7 +1201,7 @@ void CodeGenModule::Release() {
llvm::CodeModel::Model codeModel = static_cast<llvm::CodeModel::Model>(CM);
getModule().setCodeModel(codeModel);

if (CM == llvm::CodeModel::Medium &&
if ((CM == llvm::CodeModel::Medium || CM == llvm::CodeModel::Large) &&
Context.getTargetInfo().getTriple().getArch() ==
llvm::Triple::x86_64) {
getModule().setLargeDataThreshold(getCodeGenOpts().LargeDataThreshold);
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
8 changes: 1 addition & 7 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr;
static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr;
static const SanitizerMask NotAllowedWithExecuteOnly =
SanitizerKind::Function | SanitizerKind::KCFI;
static const SanitizerMask RequiresPIE =
SanitizerKind::DataFlow | SanitizerKind::Scudo;
static const SanitizerMask NeedsUnwindTables =
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
SanitizerKind::Memory | SanitizerKind::DataFlow;
Expand Down Expand Up @@ -303,9 +301,7 @@ bool SanitizerArgs::needsCfiDiagRt() const {
CfiCrossDso && !ImplicitCfiRuntime;
}

bool SanitizerArgs::requiresPIE() const {
return NeedPIE || (Sanitizers.Mask & RequiresPIE);
}
bool SanitizerArgs::requiresPIE() const { return NeedPIE; }

bool SanitizerArgs::needsUnwindTables() const {
return static_cast<bool>(Sanitizers.Mask & NeedsUnwindTables);
Expand Down Expand Up @@ -699,8 +695,6 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
MsanParamRetval = Args.hasFlag(
options::OPT_fsanitize_memory_param_retval,
options::OPT_fno_sanitize_memory_param_retval, MsanParamRetval);
NeedPIE |= !(TC.getTriple().isOSLinux() &&
TC.getTriple().getArch() == llvm::Triple::x86_64);
} else if (AllAddedKinds & SanitizerKind::KernelMemory) {
MsanUseAfterDtor = false;
MsanParamRetval = Args.hasFlag(
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
28 changes: 18 additions & 10 deletions 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 Expand Up @@ -5748,20 +5752,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}

if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) {
if (!Triple.isX86()) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getOption().getName() << TripleStr;
} else {
bool IsMediumCM = false;
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ))
IsMediumCM = StringRef(A->getValue()) == "medium";
if (!IsMediumCM) {
if (Triple.getArch() == llvm::Triple::x86_64) {
bool IsMediumCM = false;
bool IsLargeCM = false;
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
IsMediumCM = StringRef(A->getValue()) == "medium";
IsLargeCM = StringRef(A->getValue()) == "large";
}
if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) {
if (!IsMediumCM && !IsLargeCM) {
D.Diag(diag::warn_drv_large_data_threshold_invalid_code_model)
<< A->getOption().getRenderName();
} else {
A->render(Args, CmdArgs);
}
} else if (IsMediumCM) {
CmdArgs.push_back("-mlarge-data-threshold=65536");
} else if (IsLargeCM) {
CmdArgs.push_back("-mlarge-data-threshold=0");
}
}

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 @@ -2256,6 +2256,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 @@ -2664,7 +2673,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 @@ -2673,7 +2684,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
34 changes: 26 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 @@ -4668,6 +4674,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
} else if (Style.Language == FormatStyle::LK_Java) {
if (Left.is(tok::r_square) && Right.is(tok::l_brace))
return true;
// spaces inside square brackets.
if (Left.is(tok::l_square) || Right.is(tok::r_square))
return Style.SpacesInSquareBrackets;

if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren)) {
return Style.SpaceBeforeParensOptions.AfterControlStatements ||
spaceRequiredBeforeParens(Right);
Expand Down Expand Up @@ -5151,6 +5161,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
13 changes: 11 additions & 2 deletions 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 Expand Up @@ -1444,8 +1451,10 @@ WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start,
} else if (C.Tok->is(tok::comma)) {
if (!Cells.empty())
Cells.back().EndIndex = i;
if (C.Tok->getNextNonComment()->isNot(tok::r_brace)) // dangling comma
if (const auto *Next = C.Tok->getNextNonComment();
Next && Next->isNot(tok::r_brace)) { // dangling comma
++Cell;
}
}
} else if (Depth == 1) {
if (C.Tok == MatchingParen) {
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
Loading