126 changes: 51 additions & 75 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,27 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
if (DiscardResult)
return this->discard(SubExpr);

if (SubExpr->getType()->isAnyComplexType())
return this->delegate(SubExpr);
std::optional<PrimType> SubExprT = classify(SubExpr->getType());
// Prepare storage for the result.
if (!Initializing && !SubExprT) {
std::optional<unsigned> LocalIndex =
allocateLocal(SubExpr, /*IsExtended=*/false);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, CE))
return false;
}

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

if (std::optional<PrimType> SubExprT = classify(SubExpr->getType()))
if (SubExprT)
return this->emitLoadPop(*SubExprT, CE);
return false;

// If the subexpr type is not primitive, we need to perform a copy here.
// This happens for example in C when dereferencing a pointer of struct
// type.
return this->emitMemcpy(CE);
}

case CK_UncheckedDerivedToBase:
Expand Down Expand Up @@ -296,14 +308,11 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
// Location for the SubExpr.
// Since SubExpr is of complex type, visiting it results in a pointer
// anyway, so we just create a temporary pointer variable.
std::optional<unsigned> SubExprOffset = allocateLocalPrimitive(
unsigned SubExprOffset = allocateLocalPrimitive(
SubExpr, PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false);
if (!SubExprOffset)
return false;

if (!this->visit(SubExpr))
return false;
if (!this->emitSetLocal(PT_Ptr, *SubExprOffset, CE))
if (!this->emitSetLocal(PT_Ptr, SubExprOffset, CE))
return false;

PrimType SourceElemT = classifyComplexElementType(SubExpr->getType());
Expand All @@ -312,7 +321,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
PrimType DestElemT = classifyPrim(DestElemType);
// Cast both elements individually.
for (unsigned I = 0; I != 2; ++I) {
if (!this->emitGetLocal(PT_Ptr, *SubExprOffset, CE))
if (!this->emitGetLocal(PT_Ptr, SubExprOffset, CE))
return false;
if (!this->emitArrayElemPop(SourceElemT, I, CE))
return false;
Expand Down Expand Up @@ -676,11 +685,17 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
if (!this->emitSetLocal(PT_Ptr, ResultOffset, E))
return false;
}
QualType LHSType = LHS->getType();
if (const auto *AT = LHSType->getAs<AtomicType>())
LHSType = AT->getValueType();
QualType RHSType = RHS->getType();
if (const auto *AT = RHSType->getAs<AtomicType>())
RHSType = AT->getValueType();

// Evaluate LHS and save value to LHSOffset.
bool LHSIsComplex;
unsigned LHSOffset;
if (LHS->getType()->isAnyComplexType()) {
if (LHSType->isAnyComplexType()) {
LHSIsComplex = true;
LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false);
if (!this->visit(LHS))
Expand All @@ -689,7 +704,7 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
return false;
} else {
LHSIsComplex = false;
PrimType LHST = classifyPrim(LHS->getType());
PrimType LHST = classifyPrim(LHSType);
LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false);
if (!this->visit(LHS))
return false;
Expand All @@ -700,7 +715,7 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
// Same with RHS.
bool RHSIsComplex;
unsigned RHSOffset;
if (RHS->getType()->isAnyComplexType()) {
if (RHSType->isAnyComplexType()) {
RHSIsComplex = true;
RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false);
if (!this->visit(RHS))
Expand All @@ -709,7 +724,7 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
return false;
} else {
RHSIsComplex = false;
PrimType RHST = classifyPrim(RHS->getType());
PrimType RHST = classifyPrim(RHSType);
RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false);
if (!this->visit(RHS))
return false;
Expand Down Expand Up @@ -1233,22 +1248,19 @@ bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
// At this point we either have the evaluated source expression or a pointer
// to an object on the stack. We want to create a local variable that stores
// this value.
std::optional<unsigned> LocalIndex =
allocateLocalPrimitive(E, SubExprT, /*IsConst=*/true);
if (!LocalIndex)
return false;
if (!this->emitSetLocal(SubExprT, *LocalIndex, E))
unsigned LocalIndex = allocateLocalPrimitive(E, SubExprT, /*IsConst=*/true);
if (!this->emitSetLocal(SubExprT, LocalIndex, E))
return false;

// Here the local variable is created but the value is removed from the stack,
// so we put it back if the caller needs it.
if (!DiscardResult) {
if (!this->emitGetLocal(SubExprT, *LocalIndex, E))
if (!this->emitGetLocal(SubExprT, LocalIndex, E))
return false;
}

// This is cleaned up when the local variable is destroyed.
OpaqueExprs.insert({E, *LocalIndex});
OpaqueExprs.insert({E, LocalIndex});

return true;
}
Expand Down Expand Up @@ -1642,14 +1654,13 @@ bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(

// For everyhing else, use local variables.
if (SubExprT) {
if (std::optional<unsigned> LocalIndex = allocateLocalPrimitive(
SubExpr, *SubExprT, /*IsConst=*/true, /*IsExtended=*/true)) {
if (!this->visit(SubExpr))
return false;
if (!this->emitSetLocal(*SubExprT, *LocalIndex, E))
return false;
return this->emitGetPtrLocal(*LocalIndex, E);
}
unsigned LocalIndex = allocateLocalPrimitive(
SubExpr, *SubExprT, /*IsConst=*/true, /*IsExtended=*/true);
if (!this->visit(SubExpr))
return false;
if (!this->emitSetLocal(*SubExprT, LocalIndex, E))
return false;
return this->emitGetPtrLocal(LocalIndex, E);
} else {
const Expr *Inner = E->getSubExpr()->skipRValueSubobjectAdjustments();

Expand Down Expand Up @@ -2215,6 +2226,12 @@ bool ByteCodeExprGen<Emitter>::VisitPseudoObjectExpr(
return true;
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitPackIndexingExpr(
const PackIndexingExpr *E) {
return this->delegate(E->getSelectedExpr());
}

template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
if (E->containsErrors())
return false;
Expand All @@ -2227,7 +2244,7 @@ template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
template <class Emitter>
bool ByteCodeExprGen<Emitter>::delegate(const Expr *E) {
if (E->containsErrors())
return false;
return this->emitError(E);

// We're basically doing:
// OptionScope<Emitter> Scope(this, DicardResult, Initializing);
Expand All @@ -2237,7 +2254,7 @@ bool ByteCodeExprGen<Emitter>::delegate(const Expr *E) {

template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
if (E->containsErrors())
return false;
return this->emitError(E);

if (E->getType()->isVoidType())
return this->discard(E);
Expand Down Expand Up @@ -2266,7 +2283,7 @@ bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *E) {
assert(!classify(E->getType()));

if (E->containsErrors())
return false;
return this->emitError(E);

OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false,
/*NewInitializing=*/true);
Expand Down Expand Up @@ -2660,18 +2677,12 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
if (P.getGlobal(VD))
return true;

// Ignore external declarations. We will instead emit a dummy
// pointer when we see a DeclRefExpr for them.
if (VD->hasExternalStorage())
return true;

std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);

if (!GlobalIndex)
return false;

assert(Init);
{
if (Init) {
DeclScope<Emitter> LocalScope(this, VD);

if (VarT) {
Expand All @@ -2681,6 +2692,7 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
}
return this->visitGlobalInitializer(Init, *GlobalIndex);
}
return true;
} else {
VariableScope<Emitter> LocalScope(this);
if (VarT) {
Expand Down Expand Up @@ -3247,53 +3259,20 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
// pointer to the actual value) instead of a pointer to the pointer to the
// value.
bool IsReference = D->getType()->isReferenceType();
// Complex values are copied in the AST via a simply assignment or
// ltor cast. But we represent them as two-element arrays, which means
// we pass them around as pointers. So, to assignm from them, we will
// have to copy both (primitive) elements instead.
bool IsComplex = D->getType()->isAnyComplexType();

// Check for local/global variables and parameters.
if (auto It = Locals.find(D); It != Locals.end()) {
const unsigned Offset = It->second.Offset;
// FIXME: Fix the code duplication here with the code in the global case.
if (Initializing && IsComplex) {
PrimType ElemT = classifyComplexElementType(D->getType());
for (unsigned I = 0; I != 2; ++I) {
if (!this->emitGetPtrLocal(Offset, E))
return false;
if (!this->emitArrayElemPop(ElemT, I, E))
return false;
if (!this->emitInitElem(ElemT, I, E))
return false;
}
return true;
}

if (IsReference)
return this->emitGetLocal(PT_Ptr, Offset, E);
return this->emitGetPtrLocal(Offset, E);
} else if (auto GlobalIndex = P.getGlobal(D)) {
if (Initializing && IsComplex) {
PrimType ElemT = classifyComplexElementType(D->getType());
for (unsigned I = 0; I != 2; ++I) {
if (!this->emitGetPtrGlobal(*GlobalIndex, E))
return false;
if (!this->emitArrayElemPop(ElemT, I, E))
return false;
if (!this->emitInitElem(ElemT, I, E))
return false;
}
return true;
}

if (IsReference)
return this->emitGetGlobalPtr(*GlobalIndex, E);

return this->emitGetPtrGlobal(*GlobalIndex, E);
} else if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
if (auto It = this->Params.find(PVD); It != this->Params.end()) {
// FIXME: _Complex initializing case?
if (IsReference || !It->second.IsPtr)
return this->emitGetParamPtr(It->second.Offset, E);

Expand Down Expand Up @@ -3322,9 +3301,6 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
// Retry.
return this->VisitDeclRefExpr(E);
}

if (VD->hasExternalStorage())
return this->emitInvalidDeclRef(E, E);
}
} else {
if (const auto *VD = dyn_cast<VarDecl>(D);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E);
bool VisitPseudoObjectExpr(const PseudoObjectExpr *E);
bool VisitPackIndexingExpr(const PackIndexingExpr *E);

protected:
bool visitExpr(const Expr *E) override;
Expand Down
31 changes: 21 additions & 10 deletions clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,15 +273,18 @@ bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
return visitCaseStmt(cast<CaseStmt>(S));
case Stmt::DefaultStmtClass:
return visitDefaultStmt(cast<DefaultStmt>(S));
case Stmt::GCCAsmStmtClass:
case Stmt::MSAsmStmtClass:
return visitAsmStmt(cast<AsmStmt>(S));
case Stmt::AttributedStmtClass:
return visitAttributedStmt(cast<AttributedStmt>(S));
case Stmt::CXXTryStmtClass:
return visitCXXTryStmt(cast<CXXTryStmt>(S));
case Stmt::NullStmtClass:
return true;
// Always invalid statements.
case Stmt::GCCAsmStmtClass:
case Stmt::MSAsmStmtClass:
case Stmt::GotoStmtClass:
case Stmt::LabelStmtClass:
return this->emitInvalid(S);
default: {
if (auto *Exp = dyn_cast<Expr>(S))
return this->discard(Exp);
Expand Down Expand Up @@ -420,6 +423,11 @@ bool ByteCodeStmtGen<Emitter>::visitWhileStmt(const WhileStmt *S) {
LoopScope<Emitter> LS(this, EndLabel, CondLabel);

this->emitLabel(CondLabel);

if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
if (!visitDeclStmt(CondDecl))
return false;

if (!this->visitBool(Cond))
return false;
if (!this->jumpFalse(EndLabel))
Expand Down Expand Up @@ -484,6 +492,10 @@ bool ByteCodeStmtGen<Emitter>::visitForStmt(const ForStmt *S) {
if (Init && !this->visitStmt(Init))
return false;
this->emitLabel(CondLabel);

if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
if (!visitDeclStmt(CondDecl))
return false;
if (Cond) {
if (!this->visitBool(Cond))
return false;
Expand Down Expand Up @@ -582,17 +594,21 @@ bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
template <class Emitter>
bool ByteCodeStmtGen<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
const Expr *Cond = S->getCond();
PrimType CondT = this->classifyPrim(Cond->getType());

LabelTy EndLabel = this->getLabel();
OptLabelTy DefaultLabel = std::nullopt;
unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false);

if (const auto *CondInit = S->getInit())
if (!visitStmt(CondInit))
return false;

if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
if (!visitDeclStmt(CondDecl))
return false;

// Initialize condition variable.
PrimType CondT = this->classifyPrim(Cond->getType());
unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false);
if (!this->visit(Cond))
return false;
if (!this->emitSetLocal(CondT, CondVar, S))
Expand Down Expand Up @@ -657,11 +673,6 @@ bool ByteCodeStmtGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) {
return this->visitStmt(S->getSubStmt());
}

template <class Emitter>
bool ByteCodeStmtGen<Emitter>::visitAsmStmt(const AsmStmt *S) {
return this->emitInvalid(S);
}

template <class Emitter>
bool ByteCodeStmtGen<Emitter>::visitAttributedStmt(const AttributedStmt *S) {
// Ignore all attributes.
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/Interp/ByteCodeStmtGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ class ByteCodeStmtGen final : public ByteCodeExprGen<Emitter> {
bool visitSwitchStmt(const SwitchStmt *S);
bool visitCaseStmt(const CaseStmt *S);
bool visitDefaultStmt(const DefaultStmt *S);
bool visitAsmStmt(const AsmStmt *S);
bool visitAttributedStmt(const AttributedStmt *S);
bool visitCXXTryStmt(const CXXTryStmt *S);

Expand Down
26 changes: 18 additions & 8 deletions clang/lib/AST/Interp/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,10 @@ static BlockMoveFn getMoveArrayPrim(PrimType Type) {
Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
bool IsConst, bool IsTemporary, bool IsMutable)
: Source(D), ElemSize(primSize(Type)), Size(ElemSize),
MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), IsConst(IsConst),
IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(getCtorPrim(Type)),
DtorFn(getDtorPrim(Type)), MoveFn(getMovePrim(Type)) {
MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type),
IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)),
MoveFn(getMovePrim(Type)) {
assert(AllocSize >= Size);
assert(Source && "Missing source");
}
Expand All @@ -246,7 +247,7 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
bool IsMutable)
: Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
MDSize(MD.value_or(0)),
AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)),
AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),
IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
IsArray(true), CtorFn(getCtorArrayPrim(Type)),
DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
Expand Down Expand Up @@ -300,10 +301,19 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
assert(Source && "Missing source");
}

Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
: Source(D), ElemSize(1), Size(ElemSize), MDSize(MD.value_or(0)),
AllocSize(Size + MDSize), ElemRecord(nullptr), IsConst(true),
IsMutable(false), IsTemporary(false), IsDummy(true) {
/// Dummy.
Descriptor::Descriptor(const DeclTy &D)
: Source(D), ElemSize(1), Size(1), MDSize(0), AllocSize(MDSize),
ElemRecord(nullptr), IsConst(true), IsMutable(false), IsTemporary(false),
IsDummy(true) {
assert(Source && "Missing source");
}

/// Dummy array.
Descriptor::Descriptor(const DeclTy &D, UnknownSize)
: Source(D), ElemSize(1), Size(UnknownSizeMark), MDSize(0),
AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),
IsTemporary(false), IsArray(true), IsDummy(true) {
assert(Source && "Missing source");
}

Expand Down
15 changes: 14 additions & 1 deletion clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ struct Descriptor final {
const Record *const ElemRecord = nullptr;
/// Descriptor of the array element.
const Descriptor *const ElemDesc = nullptr;
/// The primitive type this descriptor was created for,
/// or the primitive element type in case this is
/// a primitive array.
const std::optional<PrimType> PrimT = std::nullopt;
/// Flag indicating if the block is mutable.
const bool IsConst = false;
/// Flag indicating if a field is mutable.
Expand Down Expand Up @@ -152,7 +156,11 @@ struct Descriptor final {
Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst,
bool IsTemporary, bool IsMutable);

Descriptor(const DeclTy &D, MetadataSize MD);
/// Allocates a dummy descriptor.
Descriptor(const DeclTy &D);

/// Allocates a dummy array descriptor.
Descriptor(const DeclTy &D, UnknownSize);

QualType getType() const;
QualType getElemQualType() const;
Expand Down Expand Up @@ -183,6 +191,11 @@ struct Descriptor final {
return Size;
}

PrimType getPrimType() const {
assert(isPrimitiveArray() || isPrimitive());
return *PrimT;
}

/// Returns the allocated size, including metadata.
unsigned getAllocSize() const { return AllocSize; }
/// returns the size of an element when the structure is viewed as an array.
Expand Down
49 changes: 48 additions & 1 deletion clang/lib/AST/Interp/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
//
//===----------------------------------------------------------------------===//

#include "Boolean.h"
#include "Floating.h"
#include "Function.h"
#include "FunctionPointer.h"
#include "Integral.h"
#include "IntegralAP.h"
#include "Opcode.h"
#include "PrimType.h"
Expand Down Expand Up @@ -86,6 +89,40 @@ LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {

LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }

static const char *primTypeToString(PrimType T) {
switch (T) {
case PT_Sint8:
return "Sint8";
case PT_Uint8:
return "Uint8";
case PT_Sint16:
return "Sint16";
case PT_Uint16:
return "Uint16";
case PT_Sint32:
return "Sint32";
case PT_Uint32:
return "Uint32";
case PT_Sint64:
return "Sint64";
case PT_Uint64:
return "Uint64";
case PT_IntAP:
return "IntAP";
case PT_IntAPS:
return "IntAPS";
case PT_Bool:
return "Bool";
case PT_Float:
return "Float";
case PT_Ptr:
return "Ptr";
case PT_FnPtr:
return "FnPtr";
}
llvm_unreachable("Unhandled PrimType");
}

LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
{
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
Expand All @@ -100,9 +137,10 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
unsigned GI = 0;
for (const Global *G : Globals) {
const Descriptor *Desc = G->block()->getDescriptor();
Pointer GP = getPtrGlobal(GI);

OS << GI << ": " << (void *)G->block() << " ";
{
Pointer GP = getPtrGlobal(GI);
ColorScope SC(OS, true,
GP.isInitialized()
? TerminalColor{llvm::raw_ostream::GREEN, false}
Expand All @@ -111,6 +149,15 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
}
Desc->dump(OS);
OS << "\n";
if (Desc->isPrimitive() && !Desc->isDummy()) {
OS << " ";
{
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
OS << primTypeToString(Desc->getPrimType()) << " ";
}
TYPE_SWITCH(Desc->getPrimType(), { GP.deref<T>().print(OS); });
OS << "\n";
}
++GI;
}

Expand Down
8 changes: 5 additions & 3 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,10 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
if (VD->isConstexpr())
return true;

QualType T = VD->getType();
if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)
return false;
return T->isSignedIntegerOrEnumerationType() || T->isUnsignedIntegerOrEnumerationType();

QualType T = VD->getType();
if (T.isConstQualified())
return true;

Expand Down Expand Up @@ -485,7 +485,9 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
// Don't emit anything if the function isn't defined and we're checking
// for a constant expression. It might be defined at the point we're
// actually calling it.
if (!DiagDecl->isDefined() && S.checkingPotentialConstantExpression())
bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
if (!DiagDecl->isDefined() && !IsExtern &&
S.checkingPotentialConstantExpression())
return false;

// If the declaration is defined _and_ declared 'constexpr', the below
Expand Down
41 changes: 35 additions & 6 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
const Pointer &Ptr, const APSInt &IntValue);

/// Copy the contents of Src into Dest.
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);

/// Checks if the shift operation is legal.
template <typename LT, typename RT>
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
Expand Down Expand Up @@ -165,7 +168,8 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
S.FFDiag(Op, diag::note_expr_divide_by_zero)
<< Op->getRHS()->getSourceRange();
return false;
if constexpr (!std::is_same_v<T, Floating>)
return false;
}

if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
Expand Down Expand Up @@ -1487,6 +1491,16 @@ bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
return true;
}

inline bool Memcpy(InterpState &S, CodePtr OpPC) {
const Pointer &Src = S.Stk.pop<Pointer>();
Pointer &Dest = S.Stk.peek<Pointer>();

if (!CheckLoad(S, OpPC, Src))
return false;

return DoMemcpy(S, OpPC, Src, Dest);
}

//===----------------------------------------------------------------------===//
// AddOffset, SubOffset
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1933,8 +1947,15 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>();

if (Ptr.isDummy())
return true;
if (!Ptr.isZero()) {
if (!CheckArray(S, OpPC, Ptr))
return false;

if (Ptr.isDummy()) {
S.Stk.push<Pointer>(Ptr);
return true;
}
}

if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
return false;
Expand All @@ -1947,9 +1968,14 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();

if (Ptr.isDummy()) {
S.Stk.push<Pointer>(Ptr);
return true;
if (!Ptr.isZero()) {
if (!CheckArray(S, OpPC, Ptr))
return false;

if (Ptr.isDummy()) {
S.Stk.push<Pointer>(Ptr);
return true;
}
}

if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
Expand Down Expand Up @@ -2201,6 +2227,9 @@ inline bool Invalid(InterpState &S, CodePtr OpPC) {
return false;
}

/// Do nothing and just abort execution.
inline bool Error(InterpState &S, CodePtr OpPC) { return false; }

/// Same here, but only for casts.
inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
const SourceLocation &Loc = S.Current->getLocation(OpPC);
Expand Down
65 changes: 56 additions & 9 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,11 +533,12 @@ static bool interp__builtin_rotate(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func, const CallExpr *Call,
bool Right) {
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
assert(ArgT == *S.getContext().classify(Call->getArg(1)->getType()));
PrimType AmountT = *S.getContext().classify(Call->getArg(1)->getType());
PrimType ValueT = *S.getContext().classify(Call->getArg(0)->getType());

APSInt Amount = peekToAPSInt(S.Stk, ArgT);
APSInt Value = peekToAPSInt(S.Stk, ArgT, align(primSize(ArgT)) * 2);
APSInt Amount = peekToAPSInt(S.Stk, AmountT);
APSInt Value = peekToAPSInt(
S.Stk, ValueT, align(primSize(AmountT)) + align(primSize(ValueT)));

APSInt Result;
if (Right)
Expand Down Expand Up @@ -605,10 +606,9 @@ static bool interp__builtin_eh_return_data_regno(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_launder(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
/// Just takes the first Argument to the call and puts it on the stack.
static bool noopPointer(InterpState &S, CodePtr OpPC, const InterpFrame *Frame,
const Function *Func, const CallExpr *Call) {
const Pointer &Arg = S.Stk.peek<Pointer>();
S.Stk.push<Pointer>(Arg);
return true;
Expand Down Expand Up @@ -1143,7 +1143,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
break;

case Builtin::BI__builtin_launder:
if (!interp__builtin_launder(S, OpPC, Frame, F, Call))
case Builtin::BI__builtin___CFStringMakeConstantString:
case Builtin::BI__builtin___NSStringMakeConstantString:
if (!noopPointer(S, OpPC, Frame, F, Call))
return false;
break;

Expand Down Expand Up @@ -1326,5 +1328,50 @@ bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
return true;
}

bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest) {
assert(Src.isLive() && Dest.isLive());

[[maybe_unused]] const Descriptor *SrcDesc = Src.getFieldDesc();
const Descriptor *DestDesc = Dest.getFieldDesc();

assert(!DestDesc->isPrimitive() && !SrcDesc->isPrimitive());

if (DestDesc->isPrimitiveArray()) {
assert(SrcDesc->isPrimitiveArray());
assert(SrcDesc->getNumElems() == DestDesc->getNumElems());
PrimType ET = DestDesc->getPrimType();
for (unsigned I = 0, N = DestDesc->getNumElems(); I != N; ++I) {
Pointer DestElem = Dest.atIndex(I);
TYPE_SWITCH(ET, {
DestElem.deref<T>() = Src.atIndex(I).deref<T>();
DestElem.initialize();
});
}
return true;
}

if (DestDesc->isRecord()) {
assert(SrcDesc->isRecord());
assert(SrcDesc->ElemRecord == DestDesc->ElemRecord);
const Record *R = DestDesc->ElemRecord;
for (const Record::Field &F : R->fields()) {
Pointer DestField = Dest.atField(F.Offset);
if (std::optional<PrimType> FT = S.Ctx.classify(F.Decl->getType())) {
TYPE_SWITCH(*FT, {
DestField.deref<T>() = Src.atField(F.Offset).deref<T>();
DestField.initialize();
});
} else {
return Invalid(S, OpPC);
}
}
return true;
}

// FIXME: Composite types.

return Invalid(S, OpPC);
}

} // namespace interp
} // namespace clang
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ def Dup : Opcode {

// [] -> []
def Invalid : Opcode {}
def Error : Opcode {}
def InvalidCast : Opcode {
let Args = [ArgCastKind];
}
Expand All @@ -720,3 +721,5 @@ def CheckNonNullArg : Opcode {
let Types = [PtrTypeClass];
let HasGroup = 1;
}

def Memcpy : Opcode;
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,10 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
// Complex types.
if (const auto *CT = Ty->getAs<ComplexType>()) {
QualType ElemTy = CT->getElementType();
std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
assert(ElemT);

if (ElemTy->isIntegerType()) {
std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
assert(ElemT);
INT_TYPE_SWITCH(*ElemT, {
auto V1 = Ptr.atIndex(0).deref<T>();
auto V2 = Ptr.atIndex(1).deref<T>();
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ class Pointer {
bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); }
/// Checks if the structure is an array of unknown size.
bool isUnknownSizeArray() const {
// If this points inside a dummy block, return true.
// FIXME: This might change in the future. If it does, we need
// to set the proper Ctor/Dtor functions for dummy Descriptors.
if (Base != 0 && Base != sizeof(InlineDescriptor) && isDummy())
return true;
return getFieldDesc()->isUnknownSizeArray();
}
/// Checks if the pointer points to an array.
Expand Down
15 changes: 12 additions & 3 deletions clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,20 @@ std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,

std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {
// Dedup blocks since they are immutable and pointers cannot be compared.
if (auto It = DummyParams.find(VD); It != DummyParams.end())
if (auto It = DummyVariables.find(VD); It != DummyVariables.end())
return It->second;

// Create dummy descriptor.
Descriptor *Desc = allocateDescriptor(VD, std::nullopt);
// We create desriptors of 'array of unknown size' if the type is an array
// type _and_ the size isn't known (it's not a ConstantArrayType). If the size
// is known however, we create a regular dummy pointer.
Descriptor *Desc;
if (const auto *AT = VD->getType()->getAsArrayTypeUnsafe();
AT && !isa<ConstantArrayType>(AT))
Desc = allocateDescriptor(VD, Descriptor::UnknownSize{});
else
Desc = allocateDescriptor(VD);

// Allocate a block for storage.
unsigned I = Globals.size();

Expand All @@ -158,7 +167,7 @@ std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {
G->block()->invokeCtor();

Globals.push_back(G);
DummyParams[VD] = I;
DummyVariables[VD] = I;
return I;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Program.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ class Program final {
llvm::DenseMap<const RecordDecl *, Record *> Records;

/// Dummy parameter to generate pointers from.
llvm::DenseMap<const ValueDecl *, unsigned> DummyParams;
llvm::DenseMap<const ValueDecl *, unsigned> DummyVariables;

/// Creates a new descriptor.
template <typename... Ts>
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,10 @@ bool TargetInfo::validateInputConstraint(
return true;
}

bool TargetInfo::validatePointerAuthKey(const llvm::APSInt &value) const {
return false;
}

void TargetInfo::CheckFixedPointBits() const {
// Check that the number of fractional and integral bits (and maybe sign) can
// fit into the bits given for a fixed point type.
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
Expand Down Expand Up @@ -1450,6 +1451,11 @@ int AArch64TargetInfo::getEHDataRegisterNumber(unsigned RegNo) const {
return -1;
}

bool AArch64TargetInfo::validatePointerAuthKey(
const llvm::APSInt &value) const {
return 0 <= value && value <= 3;
}

bool AArch64TargetInfo::hasInt128Type() const { return true; }

AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {

int getEHDataRegisterNumber(unsigned RegNo) const override;

bool validatePointerAuthKey(const llvm::APSInt &value) const override;

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

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Basic/Targets/BPF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
return;
}

Builder.defineMacro("__BPF_FEATURE_ARENA_CAST");
Builder.defineMacro("__BPF_FEATURE_ADDR_SPACE_CAST");

if (CPU.empty() || CPU == "generic" || CPU == "v1") {
Builder.defineMacro("__BPF_CPU_VERSION__", "1");
Expand All @@ -45,6 +45,7 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,

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

int CpuVerNum = std::stoi(CpuVerNumStr);
if (CpuVerNum >= 2)
Expand Down
130 changes: 99 additions & 31 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5208,6 +5208,73 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__iso_volatile_store64:
return RValue::get(EmitISOVolatileStore(*this, E));

case Builtin::BI__builtin_ptrauth_auth:
case Builtin::BI__builtin_ptrauth_auth_and_resign:
case Builtin::BI__builtin_ptrauth_blend_discriminator:
case Builtin::BI__builtin_ptrauth_sign_generic_data:
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
case Builtin::BI__builtin_ptrauth_strip: {
// Emit the arguments.
SmallVector<llvm::Value *, 5> Args;
for (auto argExpr : E->arguments())
Args.push_back(EmitScalarExpr(argExpr));

// Cast the value to intptr_t, saving its original type.
llvm::Type *OrigValueType = Args[0]->getType();
if (OrigValueType->isPointerTy())
Args[0] = Builder.CreatePtrToInt(Args[0], IntPtrTy);

switch (BuiltinID) {
case Builtin::BI__builtin_ptrauth_auth_and_resign:
if (Args[4]->getType()->isPointerTy())
Args[4] = Builder.CreatePtrToInt(Args[4], IntPtrTy);
LLVM_FALLTHROUGH;

case Builtin::BI__builtin_ptrauth_auth:
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
if (Args[2]->getType()->isPointerTy())
Args[2] = Builder.CreatePtrToInt(Args[2], IntPtrTy);
break;

case Builtin::BI__builtin_ptrauth_sign_generic_data:
if (Args[1]->getType()->isPointerTy())
Args[1] = Builder.CreatePtrToInt(Args[1], IntPtrTy);
break;

case Builtin::BI__builtin_ptrauth_blend_discriminator:
case Builtin::BI__builtin_ptrauth_strip:
break;
}

// Call the intrinsic.
auto IntrinsicID = [&]() -> unsigned {
switch (BuiltinID) {
case Builtin::BI__builtin_ptrauth_auth:
return llvm::Intrinsic::ptrauth_auth;
case Builtin::BI__builtin_ptrauth_auth_and_resign:
return llvm::Intrinsic::ptrauth_resign;
case Builtin::BI__builtin_ptrauth_blend_discriminator:
return llvm::Intrinsic::ptrauth_blend;
case Builtin::BI__builtin_ptrauth_sign_generic_data:
return llvm::Intrinsic::ptrauth_sign_generic;
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
return llvm::Intrinsic::ptrauth_sign;
case Builtin::BI__builtin_ptrauth_strip:
return llvm::Intrinsic::ptrauth_strip;
}
llvm_unreachable("bad ptrauth intrinsic");
}();
auto Intrinsic = CGM.getIntrinsic(IntrinsicID);
llvm::Value *Result = EmitRuntimeCall(Intrinsic, Args);

if (BuiltinID != Builtin::BI__builtin_ptrauth_sign_generic_data &&
BuiltinID != Builtin::BI__builtin_ptrauth_blend_discriminator &&
OrigValueType->isPointerTy()) {
Result = Builder.CreateIntToPtr(Result, OrigValueType);
}
return RValue::get(Result);
}

case Builtin::BI__exception_code:
case Builtin::BI_exception_code:
return RValue::get(EmitSEHExceptionCode());
Expand Down Expand Up @@ -10686,6 +10753,12 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
}

if (BuiltinID == clang::AArch64::BI__builtin_arm_trap) {
Function *F = CGM.getIntrinsic(Intrinsic::aarch64_break);
llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
return Builder.CreateCall(F, Builder.CreateZExt(Arg, CGM.Int32Ty));
}

if (BuiltinID == clang::AArch64::BI__builtin_arm_get_sme_state) {
// Create call to __arm_sme_state and store the results to the two pointers.
CallInst *CI = EmitRuntimeCall(CGM.CreateRuntimeFunction(
Expand Down Expand Up @@ -18015,38 +18088,11 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *X = EmitScalarExpr(E->getArg(0));
Value *Y = EmitScalarExpr(E->getArg(1));
Value *S = EmitScalarExpr(E->getArg(2));
llvm::Type *Xty = X->getType();
llvm::Type *Yty = Y->getType();
llvm::Type *Sty = S->getType();
if (!Xty->isVectorTy() && !Yty->isVectorTy() && !Sty->isVectorTy()) {
if (Xty->isFloatingPointTy()) {
auto V = Builder.CreateFSub(Y, X);
V = Builder.CreateFMul(S, V);
return Builder.CreateFAdd(X, V, "dx.lerp");
}
llvm_unreachable("Scalar Lerp is only supported on floats.");
}
// A VectorSplat should have happened
assert(Xty->isVectorTy() && Yty->isVectorTy() && Sty->isVectorTy() &&
"Lerp of vector and scalar is not supported.");

[[maybe_unused]] auto *XVecTy =
E->getArg(0)->getType()->getAs<VectorType>();
[[maybe_unused]] auto *YVecTy =
E->getArg(1)->getType()->getAs<VectorType>();
[[maybe_unused]] auto *SVecTy =
E->getArg(2)->getType()->getAs<VectorType>();
// A HLSLVectorTruncation should have happend
assert(XVecTy->getNumElements() == YVecTy->getNumElements() &&
XVecTy->getNumElements() == SVecTy->getNumElements() &&
"Lerp requires vectors to be of the same size.");
assert(XVecTy->getElementType()->isRealFloatingType() &&
XVecTy->getElementType() == YVecTy->getElementType() &&
XVecTy->getElementType() == SVecTy->getElementType() &&
"Lerp requires float vectors to be of the same type.");
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("lerp operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType=*/Xty, Intrinsic::dx_lerp, ArrayRef<Value *>{X, Y, S},
nullptr, "dx.lerp");
/*ReturnType=*/X->getType(), Intrinsic::dx_lerp,
ArrayRef<Value *>{X, Y, S}, nullptr, "dx.lerp");
}
case Builtin::BI__builtin_hlsl_elementwise_frac: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Expand All @@ -18056,6 +18102,20 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/Op0->getType(), Intrinsic::dx_frac,
ArrayRef<Value *>{Op0}, nullptr, "dx.frac");
}
case Builtin::BI__builtin_hlsl_elementwise_isinf: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
llvm::Type *Xty = Op0->getType();
llvm::Type *retType = llvm::Type::getInt1Ty(this->getLLVMContext());
if (Xty->isVectorTy()) {
auto *XVecTy = E->getArg(0)->getType()->getAs<VectorType>();
retType = llvm::VectorType::get(
retType, ElementCount::getFixed(XVecTy->getNumElements()));
}
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("isinf operand must have a float representation");
return Builder.CreateIntrinsic(retType, Intrinsic::dx_isinf,
ArrayRef<Value *>{Op0}, nullptr, "dx.isinf");
}
case Builtin::BI__builtin_hlsl_mad: {
Value *M = EmitScalarExpr(E->getArg(0));
Value *A = EmitScalarExpr(E->getArg(1));
Expand Down Expand Up @@ -18083,6 +18143,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/Op0->getType(), Intrinsic::dx_rcp,
ArrayRef<Value *>{Op0}, nullptr, "dx.rcp");
}
case Builtin::BI__builtin_hlsl_elementwise_rsqrt: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("rsqrt operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType=*/Op0->getType(), Intrinsic::dx_rsqrt,
ArrayRef<Value *>{Op0}, nullptr, "dx.rsqrt");
}
}
return nullptr;
}
Expand Down
6 changes: 0 additions & 6 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,12 +453,6 @@ ToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
return UnwindTableLevel::None;
}

unsigned ToolChain::GetDefaultDwarfVersion() const {
// TODO: Remove the RISC-V special case when R_RISCV_SET_ULEB128 linker
// support becomes more widely available.
return getTriple().isRISCV() ? 4 : 5;
}

Tool *ToolChain::getClang() const {
if (!Clang)
Clang.reset(new tools::Clang(*this, useIntegratedBackend()));
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Driver/ToolChains/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,11 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
}
}

if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
options::OPT_munaligned_access)) {
if (A->getOption().matches(options::OPT_mno_unaligned_access))
if (Arg *A = Args.getLastArg(
options::OPT_mstrict_align, options::OPT_mno_strict_align,
options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) {
if (A->getOption().matches(options::OPT_mstrict_align) ||
A->getOption().matches(options::OPT_mno_unaligned_access))
Features.push_back("+strict-align");
} else if (Triple.isOSOpenBSD())
Features.push_back("+strict-align");
Expand Down
19 changes: 11 additions & 8 deletions clang/lib/Driver/ToolChains/Arch/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -868,21 +868,24 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
}
}

// Kernel code has more strict alignment requirements.
if (KernelOrKext) {
Features.push_back("+strict-align");
} else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
options::OPT_munaligned_access)) {
if (A->getOption().matches(options::OPT_munaligned_access)) {
if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
options::OPT_munaligned_access,
options::OPT_mstrict_align,
options::OPT_mno_strict_align)) {
// Kernel code has more strict alignment requirements.
if (KernelOrKext ||
A->getOption().matches(options::OPT_mno_unaligned_access) ||
A->getOption().matches(options::OPT_mstrict_align)) {
Features.push_back("+strict-align");
} else {
// No v6M core supports unaligned memory access (v6M ARM ARM A3.2).
if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
D.Diag(diag::err_target_unsupported_unaligned) << "v6m";
// v8M Baseline follows on from v6M, so doesn't support unaligned memory
// access either.
else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline)
D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base";
} else
Features.push_back("+strict-align");
}
} else {
// Assume pre-ARMv6 doesn't support unaligned accesses.
//
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,9 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
}
}

// Select the `ual` feature determined by -m[no-]unaligned-access
// or the alias -m[no-]strict-align.
AddTargetFeature(Args, Features, options::OPT_munaligned_access,
options::OPT_mno_unaligned_access, "ual");
// Select the `ual` feature determined by -m[no-]strict-align.
AddTargetFeature(Args, Features, options::OPT_mno_strict_align,
options::OPT_mstrict_align, "ual");

// Accept but warn about these TargetSpecific options.
if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))
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 @@ -167,9 +167,9 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("-relax");
}

// -mno-unaligned-access is default, unless -munaligned-access is specified.
AddTargetFeature(Args, Features, options::OPT_munaligned_access,
options::OPT_mno_unaligned_access, "fast-unaligned-access");
// -mstrict-align is default, unless -mno-strict-align is specified.
AddTargetFeature(Args, Features, options::OPT_mno_strict_align,
options::OPT_mstrict_align, "fast-unaligned-access");

// Now add any that the user explicitly requested on the command line,
// which may override the defaults.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7199,6 +7199,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fno-common is the default, set -fcommon only when that flag is set.
Args.addOptInFlag(CmdArgs, options::OPT_fcommon, options::OPT_fno_common);

if (Args.hasFlag(options::OPT_fptrauth_intrinsics,
options::OPT_fno_ptrauth_intrinsics, false))
CmdArgs.push_back("-fptrauth-intrinsics");

// -fsigned-bitfields is default, and clang doesn't yet support
// -funsigned-bitfields.
if (!Args.hasFlag(options::OPT_fsigned_bitfields,
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,8 @@ bool tools::isTLSDESCEnabled(const ToolChain &TC,
SupportedArgument = V == "desc" || V == "trad";
EnableTLSDESC = V == "desc";
} else if (Triple.isX86()) {
SupportedArgument = V == "gnu";
SupportedArgument = V == "gnu" || V == "gnu2";
EnableTLSDESC = V == "gnu2";
} else {
Unsupported = true;
}
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,9 @@ ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
: Style(Style), Keywords(Keywords), SourceMgr(SourceMgr),
Whitespaces(Whitespaces), Encoding(Encoding),
BinPackInconclusiveFunctions(BinPackInconclusiveFunctions),
CommentPragmasRegex(Style.CommentPragmas), RawStringFormats(Style) {}
CommentPragmasRegex(Style.CommentPragmas), RawStringFormats(Style) {
assert(IsCpp == Style.isCpp());
}

LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
unsigned FirstStartColumn,
Expand Down Expand Up @@ -406,7 +408,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
}
if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
(Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName) &&
State.Line->First->isNot(TT_AttributeSquare) && Style.isCpp() &&
State.Line->First->isNot(TT_AttributeSquare) && IsCpp &&
// FIXME: This is a temporary workaround for the case where clang-format
// sets BreakBeforeParameter to avoid bin packing and this creates a
// completely unnecessary line break after a template type that isn't
Expand Down Expand Up @@ -677,8 +679,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
auto &CurrentState = State.Stack.back();

bool DisallowLineBreaksOnThisLine =
Style.LambdaBodyIndentation == FormatStyle::LBI_Signature &&
Style.isCpp() && [&Current] {
Style.LambdaBodyIndentation == FormatStyle::LBI_Signature && IsCpp &&
[&Current] {
// Deal with lambda arguments in C++. The aim here is to ensure that we
// don't over-indent lambda function bodies when lambdas are passed as
// arguments to function calls. We do this by ensuring that either all
Expand Down Expand Up @@ -1091,7 +1093,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
// Any break on this level means that the parent level has been broken
// and we need to avoid bin packing there.
bool NestedBlockSpecialCase =
(!Style.isCpp() && Current.is(tok::r_brace) && State.Stack.size() > 1 &&
(!IsCpp && Current.is(tok::r_brace) && State.Stack.size() > 1 &&
State.Stack[State.Stack.size() - 2].NestedBlockInlined) ||
(Style.Language == FormatStyle::LK_ObjC && Current.is(tok::r_brace) &&
State.Stack.size() > 1 && !Style.ObjCBreakBeforeNestedBlockParam);
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3841,13 +3841,15 @@ tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
}

LangOptions getFormattingLangOpts(const FormatStyle &Style) {
LangOptions LangOpts;
IsCpp = Style.isCpp();

FormatStyle::LanguageStandard LexingStd = Style.Standard;
if (LexingStd == FormatStyle::LS_Auto)
LexingStd = FormatStyle::LS_Latest;
if (LexingStd == FormatStyle::LS_Latest)
LexingStd = FormatStyle::LS_Cpp20;

LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
LangOpts.CPlusPlus11 = LexingStd >= FormatStyle::LS_Cpp11;
LangOpts.CPlusPlus14 = LexingStd >= FormatStyle::LS_Cpp14;
Expand All @@ -3858,10 +3860,8 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {
// the sequence "<::" will be unconditionally treated as "[:".
// Cf. Lexer::LexTokenInternal.
LangOpts.Digraphs = LexingStd >= FormatStyle::LS_Cpp11;

LangOpts.LineComment = 1;
bool AlternativeOperators = Style.isCpp();
LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
LangOpts.CXXOperatorNames = IsCpp;
LangOpts.Bool = 1;
LangOpts.ObjC = 1;
LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
Expand Down Expand Up @@ -3943,6 +3943,8 @@ const char *DefaultFormatStyle = "file";

const char *DefaultFallbackStyle = "LLVM";

bool IsCpp = false;

llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
loadAndParseConfigFile(StringRef ConfigFile, llvm::vfs::FileSystem *FS,
FormatStyle *Style, bool AllowUnknownOptions) {
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Format/FormatToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,15 @@ static SmallVector<StringRef> CppNonKeywordTypes = {
"uint32_t", "uint64_t", "uint8_t", "uintptr_t",
};

bool FormatToken::isTypeName(bool IsCpp) const {
bool FormatToken::isTypeName() const {
return is(TT_TypeName) || isSimpleTypeSpecifier() ||
(IsCpp && is(tok::identifier) &&
std::binary_search(CppNonKeywordTypes.begin(),
CppNonKeywordTypes.end(), TokenText));
}

bool FormatToken::isTypeOrIdentifier(bool IsCpp) const {
return isTypeName(IsCpp) || isOneOf(tok::kw_auto, tok::identifier);
bool FormatToken::isTypeOrIdentifier() const {
return isTypeName() || isOneOf(tok::kw_auto, tok::identifier);
}

bool FormatToken::isBlockIndentedInitRBrace(const FormatStyle &Style) const {
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -676,9 +676,9 @@ struct FormatToken {
/// Determine whether the token is a simple-type-specifier.
[[nodiscard]] bool isSimpleTypeSpecifier() const;

[[nodiscard]] bool isTypeName(bool IsCpp) const;
[[nodiscard]] bool isTypeName() const;

[[nodiscard]] bool isTypeOrIdentifier(bool IsCpp) const;
[[nodiscard]] bool isTypeOrIdentifier() const;

bool isObjCAccessSpecifier() const {
return is(tok::at) && Next &&
Expand Down Expand Up @@ -823,7 +823,7 @@ struct FormatToken {

/// Returns whether the token is the left square bracket of a C++
/// structured binding declaration.
bool isCppStructuredBinding(bool IsCpp) const {
bool isCppStructuredBinding() const {
if (!IsCpp || isNot(tok::l_square))
return false;
const FormatToken *T = this;
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ FormatTokenLexer::FormatTokenLexer(
Encoding(Encoding), Allocator(Allocator), FirstInLineIndex(0),
FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin),
MacroBlockEndRegex(Style.MacroBlockEnd) {
assert(IsCpp == Style.isCpp());
Lex.reset(new Lexer(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, LangOpts));
Lex->SetKeepWhitespaceMode(true);

Expand Down Expand Up @@ -114,7 +115,7 @@ void FormatTokenLexer::tryMergePreviousTokens() {
return;
if (tryMergeForEach())
return;
if (Style.isCpp() && tryTransformTryUsageForC())
if (IsCpp && tryTransformTryUsageForC())
return;

if (Style.isJavaScript() || Style.isCSharp()) {
Expand Down Expand Up @@ -1341,7 +1342,7 @@ FormatToken *FormatTokenLexer::getNextToken() {
Column = FormatTok->LastLineColumnWidth;
}

if (Style.isCpp()) {
if (IsCpp) {
auto *Identifier = FormatTok->Tok.getIdentifierInfo();
auto it = Macros.find(Identifier);
if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() &&
Expand Down
29 changes: 13 additions & 16 deletions clang/lib/Format/QualifierAlignmentFixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,24 +268,20 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
if (isPossibleMacro(TypeToken))
return Tok;

const bool IsCpp = Style.isCpp();

// The case `const long long int volatile` -> `long long int const volatile`
// The case `long const long int volatile` -> `long long int const volatile`
// The case `long long volatile int const` -> `long long int const volatile`
// The case `const long long volatile int` -> `long long int const volatile`
if (TypeToken->isTypeName(IsCpp)) {
if (TypeToken->isTypeName()) {
// The case `const decltype(foo)` -> `const decltype(foo)`
// The case `const typeof(foo)` -> `const typeof(foo)`
// The case `const _Atomic(foo)` -> `const _Atomic(foo)`
if (TypeToken->isOneOf(tok::kw_decltype, tok::kw_typeof, tok::kw__Atomic))
return Tok;

const FormatToken *LastSimpleTypeSpecifier = TypeToken;
while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(),
IsCpp)) {
while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment()))
LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment();
}

rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier,
/*Left=*/false);
Expand All @@ -295,7 +291,7 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight(
// The case `unsigned short const` -> `unsigned short const`
// The case:
// `unsigned short volatile const` -> `unsigned short const volatile`
if (PreviousCheck && PreviousCheck->isTypeName(IsCpp)) {
if (PreviousCheck && PreviousCheck->isTypeName()) {
if (LastQual != Tok)
rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false);
return Tok;
Expand Down Expand Up @@ -412,11 +408,11 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
// The case `volatile long long const int` -> `const volatile long long int`
// The case `const long long volatile int` -> `const volatile long long int`
// The case `long volatile long int const` -> `const volatile long long int`
if (const bool IsCpp = Style.isCpp(); TypeToken->isTypeName(IsCpp)) {
if (TypeToken->isTypeName()) {
const FormatToken *LastSimpleTypeSpecifier = TypeToken;
while (isConfiguredQualifierOrType(
LastSimpleTypeSpecifier->getPreviousNonComment(),
ConfiguredQualifierTokens, IsCpp)) {
ConfiguredQualifierTokens)) {
LastSimpleTypeSpecifier =
LastSimpleTypeSpecifier->getPreviousNonComment();
}
Expand Down Expand Up @@ -531,7 +527,9 @@ LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer(
const std::string &Qualifier,
const std::vector<tok::TokenKind> &QualifierTokens, bool RightAlign)
: TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign),
ConfiguredQualifierTokens(QualifierTokens) {}
ConfiguredQualifierTokens(QualifierTokens) {
IsCpp = Style.isCpp();
}

std::pair<tooling::Replacements, unsigned>
LeftRightQualifierAlignmentFixer::analyze(
Expand Down Expand Up @@ -614,16 +612,15 @@ void prepareLeftRightOrderingForQualifierAlignmentFixer(
}
}

bool LeftRightQualifierAlignmentFixer::isQualifierOrType(const FormatToken *Tok,
bool IsCpp) {
bool LeftRightQualifierAlignmentFixer::isQualifierOrType(
const FormatToken *Tok) {
return Tok &&
(Tok->isTypeName(IsCpp) || Tok->is(tok::kw_auto) || isQualifier(Tok));
(Tok->isTypeName() || Tok->is(tok::kw_auto) || isQualifier(Tok));
}

bool LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType(
const FormatToken *Tok, const std::vector<tok::TokenKind> &Qualifiers,
bool IsCpp) {
return Tok && (Tok->isTypeName(IsCpp) || Tok->is(tok::kw_auto) ||
const FormatToken *Tok, const std::vector<tok::TokenKind> &Qualifiers) {
return Tok && (Tok->isTypeName() || Tok->is(tok::kw_auto) ||
isConfiguredQualifier(Tok, Qualifiers));
}

Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Format/QualifierAlignmentFixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,10 @@ class LeftRightQualifierAlignmentFixer : public TokenAnalyzer {
tok::TokenKind QualifierType);

// Is the Token a simple or qualifier type
static bool isQualifierOrType(const FormatToken *Tok, bool IsCpp = true);
static bool isQualifierOrType(const FormatToken *Tok);
static bool
isConfiguredQualifierOrType(const FormatToken *Tok,
const std::vector<tok::TokenKind> &Qualifiers,
bool IsCpp = true);
const std::vector<tok::TokenKind> &Qualifiers);

// Is the Token likely a Macro
static bool isPossibleMacro(const FormatToken *Tok);
Expand Down
49 changes: 23 additions & 26 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static bool isKeywordWithCondition(const FormatToken &Tok) {
}

/// Returns \c true if the token starts a C++ attribute, \c false otherwise.
static bool isCppAttribute(bool IsCpp, const FormatToken &Tok) {
static bool isCppAttribute(const FormatToken &Tok) {
if (!IsCpp || !Tok.startsSequence(tok::l_square, tok::l_square))
return false;
// The first square bracket is part of an ObjC array literal
Expand Down Expand Up @@ -126,7 +126,8 @@ class AnnotatingParser {
const AdditionalKeywords &Keywords,
SmallVector<ScopeType> &Scopes)
: Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
IsCpp(Style.isCpp()), Keywords(Keywords), Scopes(Scopes) {
Keywords(Keywords), Scopes(Scopes) {
assert(IsCpp == Style.isCpp());
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
resetTokenMetadata();
}
Expand Down Expand Up @@ -562,7 +563,7 @@ class AnnotatingParser {
(CurrentToken->is(tok::l_paren) && CurrentToken->Next &&
CurrentToken->Next->isOneOf(tok::star, tok::amp, tok::caret));
if ((CurrentToken->Previous->isOneOf(tok::kw_const, tok::kw_auto) ||
CurrentToken->Previous->isTypeName(IsCpp)) &&
CurrentToken->Previous->isTypeName()) &&
!(CurrentToken->is(tok::l_brace) ||
(CurrentToken->is(tok::l_paren) && !ProbablyFunctionTypeLParen))) {
Contexts.back().IsExpression = false;
Expand Down Expand Up @@ -682,15 +683,15 @@ class AnnotatingParser {

const bool IsInnerSquare = Contexts.back().InCpp11AttributeSpecifier;
const bool IsCpp11AttributeSpecifier =
isCppAttribute(IsCpp, *Left) || IsInnerSquare;
isCppAttribute(*Left) || IsInnerSquare;

// Treat C# Attributes [STAThread] much like C++ attributes [[...]].
bool IsCSharpAttributeSpecifier =
isCSharpAttributeSpecifier(*Left) ||
Contexts.back().InCSharpAttributeSpecifier;

bool InsideInlineASM = Line.startsWith(tok::kw_asm);
bool IsCppStructuredBinding = Left->isCppStructuredBinding(IsCpp);
bool IsCppStructuredBinding = Left->isCppStructuredBinding();
bool StartsObjCMethodExpr =
!IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates &&
IsCpp && !IsCpp11AttributeSpecifier && !IsCSharpAttributeSpecifier &&
Expand Down Expand Up @@ -2573,7 +2574,7 @@ class AnnotatingParser {
return true;

// MyClass a;
if (PreviousNotConst->isTypeName(IsCpp))
if (PreviousNotConst->isTypeName())
return true;

// type[] a in Java
Expand Down Expand Up @@ -2688,7 +2689,7 @@ class AnnotatingParser {
if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,
tok::kw_requires, tok::kw_throw, tok::arrow,
Keywords.kw_override, Keywords.kw_final) ||
isCppAttribute(IsCpp, *Tok.Next)) {
isCppAttribute(*Tok.Next)) {
return false;
}

Expand All @@ -2704,10 +2705,9 @@ class AnnotatingParser {
}

// Heuristically try to determine whether the parentheses contain a type.
auto IsQualifiedPointerOrReference = [this](FormatToken *T) {
auto IsQualifiedPointerOrReference = [](FormatToken *T) {
// This is used to handle cases such as x = (foo *const)&y;
assert(!T->isTypeName(IsCpp) && "Should have already been checked");
(void)IsCpp; // Avoid -Wunused-lambda-capture when assertion is disabled.
assert(!T->isTypeName() && "Should have already been checked");
// Strip trailing qualifiers such as const or volatile when checking
// whether the parens could be a cast to a pointer/reference type.
while (T) {
Expand Down Expand Up @@ -2739,7 +2739,7 @@ class AnnotatingParser {
bool ParensAreType =
!Tok.Previous ||
Tok.Previous->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) ||
Tok.Previous->isTypeName(IsCpp) ||
Tok.Previous->isTypeName() ||
IsQualifiedPointerOrReference(Tok.Previous);
bool ParensCouldEndDecl =
Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater);
Expand Down Expand Up @@ -3010,7 +3010,6 @@ class AnnotatingParser {
AnnotatedLine &Line;
FormatToken *CurrentToken;
bool AutoFound;
bool IsCpp;
const AdditionalKeywords &Keywords;

SmallVector<ScopeType> &Scopes;
Expand Down Expand Up @@ -3585,7 +3584,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {

// This function heuristically determines whether 'Current' starts the name of a
// function declaration.
static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
static bool isFunctionDeclarationName(const FormatToken &Current,
const AnnotatedLine &Line,
FormatToken *&ClosingParen) {
assert(Current.Previous);
Expand All @@ -3596,8 +3595,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
if (!Current.Tok.getIdentifierInfo())
return false;

auto skipOperatorName =
[IsCpp](const FormatToken *Next) -> const FormatToken * {
auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * {
for (; Next; Next = Next->Next) {
if (Next->is(TT_OverloadedOperatorLParen))
return Next;
Expand All @@ -3616,8 +3614,8 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
Next = Next->Next;
continue;
}
if ((Next->isTypeName(IsCpp) || Next->is(tok::identifier)) &&
Next->Next && Next->Next->isPointerOrReference()) {
if ((Next->isTypeName() || Next->is(tok::identifier)) && Next->Next &&
Next->Next->isPointerOrReference()) {
// For operator void*(), operator char*(), operator Foo*().
Next = Next->Next;
continue;
Expand Down Expand Up @@ -3665,7 +3663,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
}
if (Next->isNot(tok::identifier))
return false;
} else if (isCppAttribute(IsCpp, *Next)) {
} else if (isCppAttribute(*Next)) {
Next = Next->MatchingParen;
if (!Next)
return false;
Expand Down Expand Up @@ -3714,7 +3712,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
Tok = Tok->MatchingParen;
continue;
}
if (Tok->is(tok::kw_const) || Tok->isTypeName(IsCpp) ||
if (Tok->is(tok::kw_const) || Tok->isTypeName() ||
Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis)) {
return true;
}
Expand Down Expand Up @@ -3776,8 +3774,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
if (Tok->Previous->EndsCppAttributeGroup)
AfterLastAttribute = Tok;
if (const bool IsCtorOrDtor = Tok->is(TT_CtorDtorDeclName);
IsCtorOrDtor ||
isFunctionDeclarationName(IsCpp, *Tok, Line, ClosingParen)) {
IsCtorOrDtor || isFunctionDeclarationName(*Tok, Line, ClosingParen)) {
if (!IsCtorOrDtor)
Tok->setFinalizedType(TT_FunctionDeclarationName);
LineIsFunctionDeclaration = true;
Expand Down Expand Up @@ -4377,7 +4374,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.Tok.isLiteral())
return true;
// for (auto a = 0, b = 0; const auto & c : {1, 2, 3})
if (Left.isTypeOrIdentifier(IsCpp) && Right.Next && Right.Next->Next &&
if (Left.isTypeOrIdentifier() && Right.Next && Right.Next->Next &&
Right.Next->Next->is(TT_RangeBasedForLoopColon)) {
return getTokenPointerOrReferenceAlignment(Right) !=
FormatStyle::PAS_Left;
Expand Down Expand Up @@ -4420,8 +4417,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Right.is(tok::l_brace) && Right.is(BK_Block))
return true;
// for (auto a = 0, b = 0; const auto& c : {1, 2, 3})
if (Left.Previous && Left.Previous->isTypeOrIdentifier(IsCpp) &&
Right.Next && Right.Next->is(TT_RangeBasedForLoopColon)) {
if (Left.Previous && Left.Previous->isTypeOrIdentifier() && Right.Next &&
Right.Next->is(TT_RangeBasedForLoopColon)) {
return getTokenPointerOrReferenceAlignment(Left) !=
FormatStyle::PAS_Right;
}
Expand Down Expand Up @@ -4459,7 +4456,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Right.isPointerOrReference()) {
const FormatToken *Previous = &Left;
while (Previous && Previous->isNot(tok::kw_operator)) {
if (Previous->is(tok::identifier) || Previous->isTypeName(IsCpp)) {
if (Previous->is(tok::identifier) || Previous->isTypeName()) {
Previous = Previous->getPreviousNonComment();
continue;
}
Expand Down Expand Up @@ -4648,7 +4645,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (!Style.isVerilog() &&
(Left.isOneOf(tok::identifier, tok::greater, tok::r_square,
tok::r_paren) ||
Left.isTypeName(IsCpp)) &&
Left.isTypeName()) &&
Right.is(tok::l_brace) && Right.getNextNonComment() &&
Right.isNot(BK_Block)) {
return false;
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Format/TokenAnnotator.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,9 @@ class AnnotatedLine {
class TokenAnnotator {
public:
TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
: Style(Style), IsCpp(Style.isCpp()), Keywords(Keywords) {}
: Style(Style), Keywords(Keywords) {
assert(IsCpp == Style.isCpp());
}

/// Adapts the indent levels of comment lines to the indent of the
/// subsequent line.
Expand Down Expand Up @@ -260,8 +262,6 @@ class TokenAnnotator {

const FormatStyle &Style;

bool IsCpp;

const AdditionalKeywords &Keywords;

SmallVector<ScopeType> Scopes;
Expand Down
22 changes: 12 additions & 10 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,16 @@ UnwrappedLineParser::UnwrappedLineParser(
llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
IdentifierTable &IdentTable)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), Style(Style), IsCpp(Style.isCpp()),
Keywords(Keywords), CommentPragmasRegex(Style.CommentPragmas),
Tokens(nullptr), Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
CurrentLines(&Lines), Style(Style), Keywords(Keywords),
CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None
? IG_Rejected
: IG_Inited),
IncludeGuardToken(nullptr), FirstStartColumn(FirstStartColumn),
Macros(Style.Macros, SourceMgr, Style, Allocator, IdentTable) {}
Macros(Style.Macros, SourceMgr, Style, Allocator, IdentTable) {
assert(IsCpp == Style.isCpp());
}

void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
Expand Down Expand Up @@ -1865,7 +1867,7 @@ void UnwrappedLineParser::parseStructuralElement(
case tok::caret:
nextToken();
// Block return type.
if (FormatTok->Tok.isAnyIdentifier() || FormatTok->isTypeName(IsCpp)) {
if (FormatTok->Tok.isAnyIdentifier() || FormatTok->isTypeName()) {
nextToken();
// Return types: pointers are ok too.
while (FormatTok->is(tok::star))
Expand Down Expand Up @@ -2221,7 +2223,7 @@ bool UnwrappedLineParser::tryToParseLambda() {
bool InTemplateParameterList = false;

while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->isTypeName(IsCpp)) {
if (FormatTok->isTypeName()) {
nextToken();
continue;
}
Expand Down Expand Up @@ -2338,7 +2340,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
!Previous->isOneOf(tok::kw_return, tok::kw_co_await,
tok::kw_co_yield, tok::kw_co_return)) ||
Previous->closesScope())) ||
LeftSquare->isCppStructuredBinding(IsCpp)) {
LeftSquare->isCppStructuredBinding()) {
return false;
}
if (FormatTok->is(tok::l_square) || tok::isLiteral(FormatTok->Tok.getKind()))
Expand Down Expand Up @@ -3414,7 +3416,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
break;
}
default:
if (PreviousNonComment->isTypeOrIdentifier(IsCpp)) {
if (PreviousNonComment->isTypeOrIdentifier()) {
// This is a requires clause.
parseRequiresClause(RequiresToken);
return true;
Expand Down Expand Up @@ -3477,7 +3479,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
--OpenAngles;
break;
default:
if (NextToken->isTypeName(IsCpp)) {
if (NextToken->isTypeName()) {
FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresExpression(RequiresToken);
return false;
Expand Down Expand Up @@ -3962,7 +3964,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
if (FormatTok->is(tok::l_square)) {
FormatToken *Previous = FormatTok->Previous;
if (!Previous || (Previous->isNot(tok::r_paren) &&
!Previous->isTypeOrIdentifier(IsCpp))) {
!Previous->isTypeOrIdentifier())) {
// Don't try parsing a lambda if we had a closing parenthesis before,
// it was probably a pointer to an array: int (*)[].
if (!tryToParseLambda())
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,6 @@ class UnwrappedLineParser {
llvm::BitVector DeclarationScopeStack;

const FormatStyle &Style;
bool IsCpp;
const AdditionalKeywords &Keywords;

llvm::Regex CommentPragmasRegex;
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3293,6 +3293,17 @@ static void ParseAPINotesArgs(APINotesOptions &Opts, ArgList &Args,
Opts.ModuleSearchPaths.push_back(A->getValue());
}

static void GeneratePointerAuthArgs(const LangOptions &Opts,
ArgumentConsumer Consumer) {
if (Opts.PointerAuthIntrinsics)
GenerateArg(Consumer, OPT_fptrauth_intrinsics);
}

static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags) {
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
}

/// Check if input file kind and language standard are compatible.
static bool IsInputCompatibleWithStandard(InputKind IK,
const LangStandard &S) {
Expand Down Expand Up @@ -4014,6 +4025,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,

if (TT.getArch() == llvm::Triple::UnknownArch ||
!(TT.getArch() == llvm::Triple::aarch64 || TT.isPPC() ||
TT.getArch() == llvm::Triple::systemz ||
TT.getArch() == llvm::Triple::nvptx ||
TT.getArch() == llvm::Triple::nvptx64 ||
TT.getArch() == llvm::Triple::amdgcn ||
Expand Down Expand Up @@ -4612,6 +4624,8 @@ bool CompilerInvocation::CreateFromArgsImpl(
Res.getFileSystemOpts().WorkingDir);
ParseAPINotesArgs(Res.getAPINotesOpts(), Args, Diags);

ParsePointerAuthArgs(LangOpts, Args, Diags);

ParseLangArgs(LangOpts, Args, DashX, T, Res.getPreprocessorOpts().Includes,
Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
Expand Down Expand Up @@ -4842,6 +4856,7 @@ void CompilerInvocationBase::generateCC1CommandLine(
GenerateTargetArgs(getTargetOpts(), Consumer);
GenerateHeaderSearchArgs(getHeaderSearchOpts(), Consumer);
GenerateAPINotesArgs(getAPINotesOpts(), Consumer);
GeneratePointerAuthArgs(getLangOpts(), Consumer);
GenerateLangArgs(getLangOpts(), Consumer, T, getFrontendOpts().DashX);
GenerateCodeGenArgs(getCodeGenOpts(), Consumer, T,
getFrontendOpts().OutputFile, &getLangOpts());
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Headers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ set(x86_files
popcntintrin.h
prfchiintrin.h
prfchwintrin.h
ptrauth.h
ptwriteintrin.h
raointintrin.h
rdpruintrin.h
Expand Down
66 changes: 66 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,39 @@ float3 frac(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_frac)
float4 frac(float4);

//===----------------------------------------------------------------------===//
// isinf builtins
//===----------------------------------------------------------------------===//

/// \fn T isinf(T x)
/// \brief Determines if the specified value \a x is infinite.
/// \param x The specified input value.
///
/// Returns a value of the same size as the input, with a value set
/// to True if the x parameter is +INF or -INF. Otherwise, False.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
bool isinf(half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
bool2 isinf(half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
bool3 isinf(half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
bool4 isinf(half4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
bool isinf(float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
bool2 isinf(float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
bool3 isinf(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_isinf)
bool4 isinf(float4);

//===----------------------------------------------------------------------===//
// lerp builtins
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1153,6 +1186,39 @@ double3 rcp(double3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rcp)
double4 rcp(double4);

//===----------------------------------------------------------------------===//
// rsqrt builtins
//===----------------------------------------------------------------------===//

/// \fn T rsqrt(T x)
/// \brief Returns the reciprocal of the square root of the specified value.
/// ie 1 / sqrt( \a x).
/// \param x The specified input value.
///
/// This function uses the following formula: 1 / sqrt(x).

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rsqrt)
half rsqrt(half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rsqrt)
half2 rsqrt(half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rsqrt)
half3 rsqrt(half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rsqrt)
half4 rsqrt(half4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rsqrt)
float rsqrt(float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rsqrt)
float2 rsqrt(float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rsqrt)
float3 rsqrt(float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_rsqrt)
float4 rsqrt(float4);

//===----------------------------------------------------------------------===//
// round builtins
//===----------------------------------------------------------------------===//
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Headers/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,8 @@ module opencl_c {
header "opencl-c.h"
header "opencl-c-base.h"
}

module ptrauth {
header "ptrauth.h"
export *
}
185 changes: 185 additions & 0 deletions clang/lib/Headers/ptrauth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*===---- ptrauth.h - Pointer authentication -------------------------------===
*
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
* See https://llvm.org/LICENSE.txt for license information.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*===-----------------------------------------------------------------------===
*/

#ifndef __PTRAUTH_H
#define __PTRAUTH_H

typedef enum {
ptrauth_key_asia = 0,
ptrauth_key_asib = 1,
ptrauth_key_asda = 2,
ptrauth_key_asdb = 3,
} ptrauth_key;

/* An integer type of the appropriate size for a discriminator argument. */
typedef __UINTPTR_TYPE__ ptrauth_extra_data_t;

/* An integer type of the appropriate size for a generic signature. */
typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;

/* A signed pointer value embeds the original pointer together with
a signature that attests to the validity of that pointer. Because
this signature must use only "spare" bits of the pointer, a
signature's validity is probabilistic in practice: it is unlikely
but still plausible that an invalidly-derived signature will
somehow equal the correct signature and therefore successfully
authenticate. Nonetheless, this scheme provides a strong degree
of protection against certain kinds of attacks. */

/* Authenticating a pointer that was not signed with the given key
and extra-data value will (likely) fail by trapping. */

#if __has_feature(ptrauth_intrinsics)

/* Strip the signature from a value without authenticating it.

If the value is a function pointer, the result will not be a
legal function pointer because of the missing signature, and
attempting to call it will result in an authentication failure.

The value must be an expression of pointer type.
The key must be a constant expression of type ptrauth_key.
The result will have the same type as the original value. */
#define ptrauth_strip(__value, __key) __builtin_ptrauth_strip(__value, __key)

/* Blend a constant discriminator into the given pointer-like value
to form a new discriminator. Not all bits of the inputs are
guaranteed to contribute to the result.

On arm64e, the integer must fall within the range of a uint16_t;
other bits may be ignored.

The first argument must be an expression of pointer type.
The second argument must be an expression of integer type.
The result will have type uintptr_t. */
#define ptrauth_blend_discriminator(__pointer, __integer) \
__builtin_ptrauth_blend_discriminator(__pointer, __integer)

/* Add a signature to the given pointer value using a specific key,
using the given extra data as a salt to the signing process.

This operation does not authenticate the original value and is
therefore potentially insecure if an attacker could possibly
control that value.

The value must be an expression of pointer type.
The key must be a constant expression of type ptrauth_key.
The extra data must be an expression of pointer or integer type;
if an integer, it will be coerced to ptrauth_extra_data_t.
The result will have the same type as the original value. */
#define ptrauth_sign_unauthenticated(__value, __key, __data) \
__builtin_ptrauth_sign_unauthenticated(__value, __key, __data)

/* Authenticate a pointer using one scheme and resign it using another.

If the result is subsequently authenticated using the new scheme, that
authentication is guaranteed to fail if and only if the initial
authentication failed.

The value must be an expression of pointer type.
The key must be a constant expression of type ptrauth_key.
The extra data must be an expression of pointer or integer type;
if an integer, it will be coerced to ptrauth_extra_data_t.
The result will have the same type as the original value.

This operation is guaranteed to not leave the intermediate value
available for attack before it is re-signed.

Do not pass a null pointer to this function. A null pointer
will not successfully authenticate.

This operation traps if the authentication fails. */
#define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
__new_data) \
__builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
__new_data)

/* Authenticate a data pointer.

The value must be an expression of non-function pointer type.
The key must be a constant expression of type ptrauth_key.
The extra data must be an expression of pointer or integer type;
if an integer, it will be coerced to ptrauth_extra_data_t.
The result will have the same type as the original value.

This operation traps if the authentication fails. */
#define ptrauth_auth_data(__value, __old_key, __old_data) \
__builtin_ptrauth_auth(__value, __old_key, __old_data)

/* Compute a signature for the given pair of pointer-sized values.
The order of the arguments is significant.

Like a pointer signature, the resulting signature depends on
private key data and therefore should not be reliably reproducible
by attackers. That means that this can be used to validate the
integrity of arbitrary data by storing a signature for that data
alongside it, then checking that the signature is still valid later.
Data which exceeds two pointers in size can be signed by either
computing a tree of generic signatures or just signing an ordinary
cryptographic hash of the data.

The result has type ptrauth_generic_signature_t. However, it may
not have as many bits of entropy as that type's width would suggest;
some implementations are known to compute a compressed signature as
if the arguments were a pointer and a discriminator.

The arguments must be either pointers or integers; if integers, they
will be coerce to uintptr_t. */
#define ptrauth_sign_generic_data(__value, __data) \
__builtin_ptrauth_sign_generic_data(__value, __data)

#else

#define ptrauth_strip(__value, __key) \
({ \
(void)__key; \
__value; \
})

#define ptrauth_blend_discriminator(__pointer, __integer) \
({ \
(void)__pointer; \
(void)__integer; \
((ptrauth_extra_data_t)0); \
})

#define ptrauth_sign_unauthenticated(__value, __key, __data) \
({ \
(void)__key; \
(void)__data; \
__value; \
})

#define ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
__new_data) \
({ \
(void)__old_key; \
(void)__old_data; \
(void)__new_key; \
(void)__new_data; \
__value; \
})

#define ptrauth_auth_data(__value, __old_key, __old_data) \
({ \
(void)__old_key; \
(void)__old_data; \
__value; \
})

#define ptrauth_sign_generic_data(__value, __data) \
({ \
(void)__value; \
(void)__data; \
((ptrauth_generic_signature_t)0); \
})

#endif /* __has_feature(ptrauth_intrinsics) */

#endif /* __PTRAUTH_H */
258 changes: 248 additions & 10 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1971,6 +1971,191 @@ static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID,
return false;
}

namespace {
enum PointerAuthOpKind {
PAO_Strip,
PAO_Sign,
PAO_Auth,
PAO_SignGeneric,
PAO_Discriminator,
PAO_BlendPointer,
PAO_BlendInteger
};
}

static bool checkPointerAuthEnabled(Sema &S, Expr *E) {
if (S.getLangOpts().PointerAuthIntrinsics)
return false;

S.Diag(E->getExprLoc(), diag::err_ptrauth_disabled) << E->getSourceRange();
return true;
}

static bool checkPointerAuthKey(Sema &S, Expr *&Arg) {
// Convert it to type 'int'.
if (convertArgumentToType(S, Arg, S.Context.IntTy))
return true;

// Value-dependent expressions are okay; wait for template instantiation.
if (Arg->isValueDependent())
return false;

unsigned KeyValue;
return S.checkConstantPointerAuthKey(Arg, KeyValue);
}

bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
// Attempt to constant-evaluate the expression.
std::optional<llvm::APSInt> KeyValue = Arg->getIntegerConstantExpr(Context);
if (!KeyValue) {
Diag(Arg->getExprLoc(), diag::err_expr_not_ice)
<< 0 << Arg->getSourceRange();
return true;
}

// Ask the target to validate the key parameter.
if (!Context.getTargetInfo().validatePointerAuthKey(*KeyValue)) {
llvm::SmallString<32> Value;
{
llvm::raw_svector_ostream Str(Value);
Str << *KeyValue;
}

Diag(Arg->getExprLoc(), diag::err_ptrauth_invalid_key)
<< Value << Arg->getSourceRange();
return true;
}

Result = KeyValue->getZExtValue();
return false;
}

static bool checkPointerAuthValue(Sema &S, Expr *&Arg,
PointerAuthOpKind OpKind) {
if (Arg->hasPlaceholderType()) {
ExprResult R = S.CheckPlaceholderExpr(Arg);
if (R.isInvalid())
return true;
Arg = R.get();
}

auto AllowsPointer = [](PointerAuthOpKind OpKind) {
return OpKind != PAO_BlendInteger;
};
auto AllowsInteger = [](PointerAuthOpKind OpKind) {
return OpKind == PAO_Discriminator || OpKind == PAO_BlendInteger ||
OpKind == PAO_SignGeneric;
};

// Require the value to have the right range of type.
QualType ExpectedTy;
if (AllowsPointer(OpKind) && Arg->getType()->isPointerType()) {
ExpectedTy = Arg->getType().getUnqualifiedType();
} else if (AllowsPointer(OpKind) && Arg->getType()->isNullPtrType()) {
ExpectedTy = S.Context.VoidPtrTy;
} else if (AllowsInteger(OpKind) &&
Arg->getType()->isIntegralOrUnscopedEnumerationType()) {
ExpectedTy = S.Context.getUIntPtrType();

} else {
// Diagnose the failures.
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_value_bad_type)
<< unsigned(OpKind == PAO_Discriminator ? 1
: OpKind == PAO_BlendPointer ? 2
: OpKind == PAO_BlendInteger ? 3
: 0)
<< unsigned(AllowsInteger(OpKind) ? (AllowsPointer(OpKind) ? 2 : 1) : 0)
<< Arg->getType() << Arg->getSourceRange();
return true;
}

// Convert to that type. This should just be an lvalue-to-rvalue
// conversion.
if (convertArgumentToType(S, Arg, ExpectedTy))
return true;

// Warn about null pointers for non-generic sign and auth operations.
if ((OpKind == PAO_Sign || OpKind == PAO_Auth) &&
Arg->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) {
S.Diag(Arg->getExprLoc(), OpKind == PAO_Sign
? diag::warn_ptrauth_sign_null_pointer
: diag::warn_ptrauth_auth_null_pointer)
<< Arg->getSourceRange();
}

return false;
}

static ExprResult SemaPointerAuthStrip(Sema &S, CallExpr *Call) {
if (checkArgCount(S, Call, 2))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Strip) ||
checkPointerAuthKey(S, Call->getArgs()[1]))
return ExprError();

Call->setType(Call->getArgs()[0]->getType());
return Call;
}

static ExprResult SemaPointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) {
if (checkArgCount(S, Call, 2))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_BlendPointer) ||
checkPointerAuthValue(S, Call->getArgs()[1], PAO_BlendInteger))
return ExprError();

Call->setType(S.Context.getUIntPtrType());
return Call;
}

static ExprResult SemaPointerAuthSignGenericData(Sema &S, CallExpr *Call) {
if (checkArgCount(S, Call, 2))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_SignGeneric) ||
checkPointerAuthValue(S, Call->getArgs()[1], PAO_Discriminator))
return ExprError();

Call->setType(S.Context.getUIntPtrType());
return Call;
}

static ExprResult SemaPointerAuthSignOrAuth(Sema &S, CallExpr *Call,
PointerAuthOpKind OpKind) {
if (checkArgCount(S, Call, 3))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind) ||
checkPointerAuthKey(S, Call->getArgs()[1]) ||
checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator))
return ExprError();

Call->setType(Call->getArgs()[0]->getType());
return Call;
}

static ExprResult SemaPointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
if (checkArgCount(S, Call, 5))
return ExprError();
if (checkPointerAuthEnabled(S, Call))
return ExprError();
if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) ||
checkPointerAuthKey(S, Call->getArgs()[1]) ||
checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) ||
checkPointerAuthKey(S, Call->getArgs()[3]) ||
checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator))
return ExprError();

Call->setType(Call->getArgs()[0]->getType());
return Call;
}

static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 1))
return ExprError();
Expand Down Expand Up @@ -2683,6 +2868,18 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
}
break;
}
case Builtin::BI__builtin_ptrauth_strip:
return SemaPointerAuthStrip(*this, TheCall);
case Builtin::BI__builtin_ptrauth_blend_discriminator:
return SemaPointerAuthBlendDiscriminator(*this, TheCall);
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Sign);
case Builtin::BI__builtin_ptrauth_auth:
return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Auth);
case Builtin::BI__builtin_ptrauth_sign_generic_data:
return SemaPointerAuthSignGenericData(*this, TheCall);
case Builtin::BI__builtin_ptrauth_auth_and_resign:
return SemaPointerAuthAuthAndResign(*this, TheCall);
// OpenCL v2.0, s6.13.16 - Pipe functions
case Builtin::BIread_pipe:
case Builtin::BIwrite_pipe:
Expand Down Expand Up @@ -5233,10 +5430,6 @@ bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) {
TheCall->getArg(1)->getEndLoc());
retValue = true;
}

if (!retValue)
TheCall->setType(VecTyA->getElementType());

return retValue;
}
}
Expand All @@ -5250,11 +5443,12 @@ bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) {
return true;
}

bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) {
QualType ExpectedType = S->Context.FloatTy;
bool CheckArgsTypesAreCorrect(
Sema *S, CallExpr *TheCall, QualType ExpectedType,
llvm::function_ref<bool(clang::QualType PassedType)> Check) {
for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) {
QualType PassedType = TheCall->getArg(i)->getType();
if (!PassedType->hasFloatingRepresentation()) {
if (Check(PassedType)) {
if (auto *VecTyA = PassedType->getAs<VectorType>())
ExpectedType = S->Context.getVectorType(
ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind());
Expand All @@ -5267,6 +5461,35 @@ bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) {
return false;
}

bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) {
auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool {
return !PassedType->hasFloatingRepresentation();
};
return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy,
checkAllFloatTypes);
}

bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) {
auto checkFloatorHalf = [](clang::QualType PassedType) -> bool {
clang::QualType BaseType =
PassedType->isVectorType()
? PassedType->getAs<clang::VectorType>()->getElementType()
: PassedType;
return !BaseType->isHalfType() && !BaseType->isFloat32Type();
};
return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy,
checkFloatorHalf);
}

void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall,
QualType ReturnType) {
auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
if (VecTyA)
ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(),
VectorKind::Generic);
TheCall->setType(ReturnType);
}

// Note: returning true in this case results in CheckBuiltinFunctionCall
// returning an ExprError
bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
Expand All @@ -5285,12 +5508,27 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
case Builtin::BI__builtin_hlsl_elementwise_rcp:
case Builtin::BI__builtin_hlsl_elementwise_rcp: {
if (CheckAllArgsHaveFloatRepresentation(this, TheCall))
return true;
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
break;
}
case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
case Builtin::BI__builtin_hlsl_elementwise_frac: {
if (CheckFloatOrHalfRepresentations(this, TheCall))
return true;
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
if (CheckAllArgsHaveFloatRepresentation(this, TheCall))
break;
}
case Builtin::BI__builtin_hlsl_elementwise_isinf: {
if (CheckFloatOrHalfRepresentations(this, TheCall))
return true;
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return true;
SetElementTypeAsReturnType(this, TheCall, this->Context.BoolTy);
break;
}
case Builtin::BI__builtin_hlsl_lerp: {
Expand All @@ -5300,7 +5538,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
if (SemaBuiltinElementwiseTernaryMath(TheCall))
return true;
if (CheckAllArgsHaveFloatRepresentation(this, TheCall))
if (CheckFloatOrHalfRepresentations(this, TheCall))
return true;
break;
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14366,7 +14366,8 @@ StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective(
// The point of exit cannot be a branch out of the structured block.
// longjmp() and throw() must not violate the entry/exit criteria.
CS->getCapturedDecl()->setNothrow();
for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_for);
for (int ThisCaptureLevel =
getOpenMPCaptureLevels(OMPD_target_parallel_for_simd);
ThisCaptureLevel > 1; --ThisCaptureLevel) {
CS = cast<CapturedStmt>(CS->getCapturedStmt());
// 1.2.2 OpenMP Language Terminology
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1727,6 +1727,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
assert(!Owner->isDependentContext());
Inst->setLexicalDeclContext(Owner);
RecordInst->setLexicalDeclContext(Owner);
Inst->setObjectOfFriendDecl();

if (PrevClassTemplate) {
Inst->setCommonPtr(PrevClassTemplate->getCommonPtr());
Expand Down
9 changes: 8 additions & 1 deletion clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,18 @@ bool clang::CanElideDeclDef(const Decl *D) {

if (FD->isDependentContext())
return false;

if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return false;
}

if (auto *VD = dyn_cast<VarDecl>(D)) {
if (!VD->getDeclContext()->getRedeclContext()->isFileContext() ||
VD->isInline() || VD->isConstexpr() || isa<ParmVarDecl>(VD))
VD->isInline() || VD->isConstexpr() || isa<ParmVarDecl>(VD) ||
// Constant initialized variable may not affect the ABI, but they
// may be used in constant evaluation in the frontend, so we have
// to remain them.
VD->hasConstantInitialization())
return false;

if (VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
Expand Down
27 changes: 22 additions & 5 deletions clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,17 @@ static bool isCapturedByReference(ExplodedNode *N, const DeclRefExpr *DR) {
return FD->getType()->isReferenceType();
}

static bool isFoundInStmt(const Stmt *S, const VarDecl *VD) {
if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
for (const Decl *D : DS->decls()) {
// Once we reach the declaration of the VD we can return.
if (D->getCanonicalDecl() == VD)
return true;
}
}
return false;
}

// A loop counter is considered escaped if:
// case 1: It is a global variable.
// case 2: It is a reference parameter or a reference capture.
Expand Down Expand Up @@ -219,13 +230,19 @@ static bool isPossiblyEscaped(ExplodedNode *N, const DeclRefExpr *DR) {
continue;
}

if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
for (const Decl *D : DS->decls()) {
// Once we reach the declaration of the VD we can return.
if (D->getCanonicalDecl() == VD)
return false;
if (isFoundInStmt(S, VD)) {
return false;
}

if (const auto *SS = dyn_cast<SwitchStmt>(S)) {
if (const auto *CST = dyn_cast<CompoundStmt>(SS->getBody())) {
for (const Stmt *CB : CST->body()) {
if (isFoundInStmt(CB, VD))
return false;
}
}
}

// Check the usage of the pass-by-ref function calls and adress-of operator
// on VD and reference initialized by VD.
ASTContext &ASTCtx =
Expand Down
13 changes: 4 additions & 9 deletions clang/test/AST/Interp/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,18 +429,13 @@ namespace Incomplete {
// both-note {{array-to-pointer decay of array member without known bound}}

/// These are from test/SemaCXX/constant-expression-cxx11.cpp
/// and are the only tests using the 'indexing of array without known bound' diagnostic.
/// We currently diagnose them differently.
extern int arr[]; // expected-note 3{{declared here}}
extern int arr[];
constexpr int *c = &arr[1]; // both-error {{must be initialized by a constant expression}} \
// ref-note {{indexing of array without known bound}} \
// expected-note {{read of non-constexpr variable 'arr'}}
// both-note {{indexing of array without known bound}}
constexpr int *d = &arr[1]; // both-error {{must be initialized by a constant expression}} \
// ref-note {{indexing of array without known bound}} \
// expected-note {{read of non-constexpr variable 'arr'}}
// both-note {{indexing of array without known bound}}
constexpr int *e = arr + 1; // both-error {{must be initialized by a constant expression}} \
// ref-note {{indexing of array without known bound}} \
// expected-note {{read of non-constexpr variable 'arr'}}
// both-note {{indexing of array without known bound}}
}

namespace GH69115 {
Expand Down
9 changes: 9 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,3 +510,12 @@ namespace bswap {
int h4 = __builtin_bswap32(0x1234) == 0x34120000 ? 1 : f();
int h5 = __builtin_bswap64(0x1234) == 0x3412000000000000 ? 1 : f();
}

#define CFSTR __builtin___CFStringMakeConstantString
void test7(void) {
const void *X;
X = CFSTR("\242"); // both-warning {{input conversion stopped}}
X = CFSTR("\0"); // no-warning
X = CFSTR(242); // both-error {{cannot initialize a parameter of type 'const char *' with an rvalue of type 'int'}}
X = CFSTR("foo", "bar"); // both-error {{too many arguments to function call}}
}
8 changes: 8 additions & 0 deletions clang/test/AST/Interp/c.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,11 @@ void localCompoundLiteral(void) {
// pedantic-ref-warning {{use of an empty initializer}}
};
}

/// struct copy
struct StrA {int a; };
const struct StrA sa = { 12 };
const struct StrA * const sb = &sa;
const struct StrA sc = *sb;
_Static_assert(sc.a == 12, ""); // pedantic-ref-warning {{GNU extension}} \
// pedantic-expected-warning {{GNU extension}}
11 changes: 11 additions & 0 deletions clang/test/AST/Interp/c23.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: %clang_cc1 -std=c23 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -std=c23 -verify=ref,both %s



const _Bool inf1 = (1.0/0.0 == __builtin_inf());
constexpr _Bool inf2 = (1.0/0.0 == __builtin_inf()); // both-error {{must be initialized by a constant expression}} \
// both-note {{division by zero}}
constexpr _Bool inf3 = __builtin_inf() == __builtin_inf();


Loading