151 changes: 140 additions & 11 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,14 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_NonAtomicToAtomic:
case CK_NoOp:
case CK_UserDefinedConversion:
return this->delegate(SubExpr);

case CK_BitCast:
if (CE->getType()->isAtomicType()) {
if (!this->discard(SubExpr))
return false;
return this->emitInvalidCast(CastKind::Reinterpret, CE);
}
return this->delegate(SubExpr);

case CK_IntegralToBoolean:
Expand Down Expand Up @@ -457,7 +464,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
// Special case for C++'s three-way/spaceship operator <=>, which
// returns a std::{strong,weak,partial}_ordering (which is a class, so doesn't
// have a PrimType).
if (!T) {
if (!T && Ctx.getLangOpts().CPlusPlus) {
if (DiscardResult)
return true;
const ComparisonCategoryInfo *CmpInfo =
Expand Down Expand Up @@ -813,6 +820,19 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
return true;
}

if (QT->isAnyComplexType()) {
assert(Initializing);
QualType ElemQT = QT->getAs<ComplexType>()->getElementType();
PrimType ElemT = classifyPrim(ElemQT);
for (unsigned I = 0; I < 2; ++I) {
if (!this->visitZeroInitializer(ElemT, ElemQT, E))
return false;
if (!this->emitInitElem(ElemT, I, E))
return false;
}
return true;
}

return false;
}

Expand Down Expand Up @@ -843,6 +863,10 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
assert(E->getType()->isRecordType());
const Record *R = getRecord(E->getType());

if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) {
return this->visitInitializer(Inits[0]);
}

unsigned InitIndex = 0;
for (const Expr *Init : Inits) {
if (!this->emitDupPtr(E))
Expand Down Expand Up @@ -1023,14 +1047,17 @@ bool ByteCodeExprGen<Emitter>::VisitSubstNonTypeTemplateParmExpr(

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitConstantExpr(const ConstantExpr *E) {
// Try to emit the APValue directly, without visiting the subexpr.
// This will only fail if we can't emit the APValue, so won't emit any
// diagnostics or any double values.
std::optional<PrimType> T = classify(E->getType());
if (T && E->hasAPValueResult() &&
this->visitAPValue(E->getAPValueResult(), *T, E))
return true;
if (T && E->hasAPValueResult()) {
// Try to emit the APValue directly, without visiting the subexpr.
// This will only fail if we can't emit the APValue, so won't emit any
// diagnostics or any double values.
if (DiscardResult)
return true;

if (this->visitAPValue(E->getAPValueResult(), *T, E))
return true;
}
return this->delegate(E->getSubExpr());
}

Expand Down Expand Up @@ -1062,6 +1089,12 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(

if (Kind == UETT_SizeOf) {
QualType ArgType = E->getTypeOfArgument();

// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
if (const auto *Ref = ArgType->getAs<ReferenceType>())
ArgType = Ref->getPointeeType();

CharUnits Size;
if (ArgType->isVoidType() || ArgType->isFunctionType())
Size = CharUnits::One();
Expand Down Expand Up @@ -1122,7 +1155,7 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
if (DiscardResult)
return this->discard(Base);

if (!this->visit(Base))
if (!this->delegate(Base))
return false;

// Base above gives us a pointer on the stack.
Expand Down Expand Up @@ -1610,8 +1643,10 @@ bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
return this->emitGetPtrLocal(*LocalIndex, E);
}
} else {
const Expr *Inner = E->getSubExpr()->skipRValueSubobjectAdjustments();

if (std::optional<unsigned> LocalIndex =
allocateLocal(SubExpr, /*IsExtended=*/true)) {
allocateLocal(Inner, /*IsExtended=*/true)) {
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
return this->visitInitializer(SubExpr);
Expand Down Expand Up @@ -1932,10 +1967,32 @@ bool ByteCodeExprGen<Emitter>::VisitCXXScalarValueInitExpr(
const CXXScalarValueInitExpr *E) {
QualType Ty = E->getType();

if (Ty->isVoidType())
if (DiscardResult || Ty->isVoidType())
return true;

return this->visitZeroInitializer(classifyPrim(Ty), Ty, E);
if (std::optional<PrimType> T = classify(Ty))
return this->visitZeroInitializer(*T, Ty, E);

assert(Ty->isAnyComplexType());
if (!Initializing) {
std::optional<unsigned> LocalIndex = allocateLocal(E, /*IsExtended=*/false);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}

// Initialize both fields to 0.
QualType ElemQT = Ty->getAs<ComplexType>()->getElementType();
PrimType ElemT = classifyPrim(ElemQT);

for (unsigned I = 0; I != 2; ++I) {
if (!this->visitZeroInitializer(ElemT, ElemQT, E))
return false;
if (!this->emitInitElem(ElemT, I, E))
return false;
}
return true;
}

template <class Emitter>
Expand All @@ -1954,6 +2011,46 @@ bool ByteCodeExprGen<Emitter>::VisitChooseExpr(const ChooseExpr *E) {
return this->delegate(E->getChosenSubExpr());
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitObjCBoolLiteralExpr(
const ObjCBoolLiteralExpr *E) {
if (DiscardResult)
return true;

return this->emitConst(E->getValue(), E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitCXXInheritedCtorInitExpr(
const CXXInheritedCtorInitExpr *E) {
const CXXConstructorDecl *Ctor = E->getConstructor();
assert(!Ctor->isTrivial() &&
"Trivial CXXInheritedCtorInitExpr, implement. (possible?)");
const Function *F = this->getFunction(Ctor);
assert(F);
assert(!F->hasRVO());
assert(F->hasThisPointer());

if (!this->emitDupPtr(SourceInfo{}))
return false;

// Forward all arguments of the current function (which should be a
// constructor itself) to the inherited ctor.
// This is necessary because the calling code has pushed the pointer
// of the correct base for us already, but the arguments need
// to come after.
unsigned Offset = align(primSize(PT_Ptr)); // instance pointer.
for (const ParmVarDecl *PD : Ctor->parameters()) {
PrimType PT = this->classify(PD->getType()).value_or(PT_Ptr);

if (!this->emitGetParam(PT, Offset, E))
return false;
Offset += align(primSize(PT));
}

return this->emitCall(F, E);
}

template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
if (E->containsErrors())
return false;
Expand Down Expand Up @@ -2966,21 +3063,53 @@ 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
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);
bool VisitChooseExpr(const ChooseExpr *E);
bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);

protected:
bool visitExpr(const Expr *E) override;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
template <class Emitter>
bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
for (auto *D : DS->decls()) {
if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl>(D))
if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, UsingEnumDecl>(D))
continue;

const auto *VD = dyn_cast<VarDecl>(D);
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
template <typename T>
static void moveArrayTy(Block *, const std::byte *Src, std::byte *Dst,
const Descriptor *D) {
// FIXME: Need to copy the InitMap?
Src += sizeof(InitMapPtr);
Dst += sizeof(InitMapPtr);
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
const auto *SrcPtr = &reinterpret_cast<const T *>(Src)[I];
auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/AST/Interp/EvaluationResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,6 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
const auto *CAT =
cast<ConstantArrayType>(Ptr.getType()->getAsArrayTypeUnsafe());
return CheckArrayInitialized(S, InitLoc, Ptr, CAT);

return true;
}

void EvaluationResult::dump() const {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
}

bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return !Ptr.isZero() && !Ptr.isDummy();
return !Ptr.isDummy();
}

bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
Expand Down
45 changes: 31 additions & 14 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1855,13 +1855,38 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>();

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

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

return NarrowPtr(S, OpPC);
}

/// Just takes a pointer and checks if its' an incomplete
template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();

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

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

return NarrowPtr(S, OpPC);
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
const Pointer &Ptr = S.Stk.pop<Pointer>();

S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
return true;
}

/// Just takes a pointer and checks if it's an incomplete
/// array type.
inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
Expand All @@ -1877,17 +1902,6 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
return false;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();

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

return NarrowPtr(S, OpPC);
}

inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
if (Func->hasThisPointer()) {
size_t ThisOffset =
Expand Down Expand Up @@ -2020,8 +2034,11 @@ inline bool Invalid(InterpState &S, CodePtr OpPC) {
/// Same here, but only for casts.
inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
const SourceLocation &Loc = S.Current->getLocation(OpPC);
S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
<< static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);

// FIXME: Support diagnosing other invalid cast kinds.
if (Kind == CastKind::Reinterpret)
S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
<< static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
return false;
}

Expand Down
19 changes: 19 additions & 0 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,19 @@ static bool interp__builtin_move(InterpState &S, CodePtr OpPC,
return Func->getDecl()->isConstexpr();
}

static bool interp__builtin_eh_return_data_regno(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Arg = peekToAPSInt(S.Stk, ArgT);

int Result =
S.getCtx().getTargetInfo().getEHDataRegisterNumber(Arg.getZExtValue());
pushInt(S, Result);
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
InterpFrame *Frame = S.Current;
Expand All @@ -660,6 +673,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
break;
case Builtin::BI__builtin_assume:
case Builtin::BI__assume:
break;
case Builtin::BI__builtin_strcmp:
if (!interp__builtin_strcmp(S, OpPC, Frame))
Expand Down Expand Up @@ -868,6 +882,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_eh_return_data_regno:
if (!interp__builtin_eh_return_data_regno(S, OpPC, Frame, F, Call))
return false;
break;

default:
return false;
}
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@ def ExpandPtr : Opcode;
def ArrayElemPtr : AluOpcode;
def ArrayElemPtrPop : AluOpcode;

def ArrayElemPop : Opcode {
let Args = [ArgUint32];
let Types = [AllTypeClass];
let HasGroup = 1;
}

//===----------------------------------------------------------------------===//
// Direct field accessors
//===----------------------------------------------------------------------===//
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,12 @@ class Pointer {
}
/// Checks if a structure is a base class.
bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
/// Checks if the pointer pointers to a dummy value.
bool isDummy() const { return getDeclDesc()->isDummy(); }
/// Checks if the pointer points to a dummy value.
bool isDummy() const {
if (!Pointee)
return false;
return getDeclDesc()->isDummy();
}

/// Checks if an object or a subfield is mutable.
bool isConst() const {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/Interp/PrimType.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,17 @@ enum PrimType : unsigned {

enum class CastKind : uint8_t {
Reinterpret,
Atomic,
};
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
interp::CastKind CK) {
switch (CK) {
case interp::CastKind::Reinterpret:
OS << "reinterpret_cast";
break;
case interp::CastKind::Atomic:
OS << "atomic";
break;
}
return OS;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3443,6 +3443,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
case CC_PreserveMost:
case CC_PreserveAll:
case CC_M68kRTD:
case CC_PreserveNone:
// FIXME: we should be mangling all of the above.
return "";

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3438,6 +3438,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_PreserveMost: return "preserve_most";
case CC_PreserveAll: return "preserve_all";
case CC_M68kRTD: return "m68k_rtd";
case CC_PreserveNone: return "preserve_none";
}

llvm_unreachable("Invalid calling convention.");
Expand Down Expand Up @@ -3854,6 +3855,12 @@ PackIndexingType::computeDependence(QualType Pattern, Expr *IndexExpr,

if (!(IndexD & TypeDependence::UnexpandedPack))
TD &= ~TypeDependence::UnexpandedPack;

// If the pattern does not contain an unexpended pack,
// the type is still dependent, and invalid
if (!Pattern->containsUnexpandedParameterPack())
TD |= TypeDependence::Error | TypeDependence::DependentInstantiation;

return TD;
}

Expand Down Expand Up @@ -3984,6 +3991,7 @@ bool AttributedType::isCallingConv() const {
case attr::PreserveMost:
case attr::PreserveAll:
case attr::M68kRTD:
case attr::PreserveNone:
return true;
}
llvm_unreachable("invalid attr kind");
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
case CC_M68kRTD:
OS << " __attribute__((m68k_rtd))";
break;
case CC_PreserveNone:
OS << " __attribute__((preserve_none))";
break;
}
}

Expand Down Expand Up @@ -1911,6 +1914,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::M68kRTD:
OS << "m68k_rtd";
break;
case attr::PreserveNone:
OS << "preserve_none";
break;
case attr::NoDeref:
OS << "noderef";
break;
Expand Down
59 changes: 28 additions & 31 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,15 @@ static bool compareDistinctValues(QualType Type, Value &Val1,
llvm_unreachable("All cases covered in switch");
}

/// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
/// respectively, of the same type `Type`. Merging generally produces a single
/// Attempts to join distinct values `Val1` and `Val2` in `Env1` and `Env2`,
/// respectively, of the same type `Type`. Joining generally produces a single
/// value that (soundly) approximates the two inputs, although the actual
/// meaning depends on `Model`.
static Value *mergeDistinctValues(QualType Type, Value &Val1,
const Environment &Env1, Value &Val2,
const Environment &Env2,
Environment &MergedEnv,
Environment::ValueModel &Model) {
static Value *joinDistinctValues(QualType Type, Value &Val1,
const Environment &Env1, Value &Val2,
const Environment &Env2,
Environment &JoinedEnv,
Environment::ValueModel &Model) {
// Join distinct boolean values preserving information about the constraints
// in the respective path conditions.
if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
Expand All @@ -113,42 +113,39 @@ static Value *mergeDistinctValues(QualType Type, Value &Val1,
// ```
auto &Expr1 = cast<BoolValue>(Val1).formula();
auto &Expr2 = cast<BoolValue>(Val2).formula();
auto &A = MergedEnv.arena();
auto &MergedVal = A.makeAtomRef(A.makeAtom());
MergedEnv.assume(
auto &A = JoinedEnv.arena();
auto &JoinedVal = A.makeAtomRef(A.makeAtom());
JoinedEnv.assume(
A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()),
A.makeEquals(MergedVal, Expr1)),
A.makeEquals(JoinedVal, Expr1)),
A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()),
A.makeEquals(MergedVal, Expr2))));
return &A.makeBoolValue(MergedVal);
A.makeEquals(JoinedVal, Expr2))));
return &A.makeBoolValue(JoinedVal);
}

Value *MergedVal = nullptr;
Value *JoinedVal = nullptr;
if (auto *RecordVal1 = dyn_cast<RecordValue>(&Val1)) {
auto *RecordVal2 = cast<RecordValue>(&Val2);

if (&RecordVal1->getLoc() == &RecordVal2->getLoc())
// `RecordVal1` and `RecordVal2` may have different properties associated
// with them. Create a new `RecordValue` with the same location but
// without any properties so that we soundly approximate both values. If a
// particular analysis needs to merge properties, it should do so in
// `DataflowAnalysis::merge()`.
MergedVal = &MergedEnv.create<RecordValue>(RecordVal1->getLoc());
// particular analysis needs to join properties, it should do so in
// `DataflowAnalysis::join()`.
JoinedVal = &JoinedEnv.create<RecordValue>(RecordVal1->getLoc());
else
// If the locations for the two records are different, need to create a
// completely new value.
MergedVal = MergedEnv.createValue(Type);
JoinedVal = JoinedEnv.createValue(Type);
} else {
MergedVal = MergedEnv.createValue(Type);
JoinedVal = JoinedEnv.createValue(Type);
}

// FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
// returns false to avoid storing unneeded values in `DACtx`.
if (MergedVal)
if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv))
return MergedVal;
if (JoinedVal)
Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);

return nullptr;
return JoinedVal;
}

// When widening does not change `Current`, return value will equal `&Prev`.
Expand Down Expand Up @@ -240,9 +237,9 @@ joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
continue;
}

if (Value *MergedVal = mergeDistinctValues(
if (Value *JoinedVal = joinDistinctValues(
Loc->getType(), *Val, Env1, *It->second, Env2, JoinedEnv, Model)) {
Result.insert({Loc, MergedVal});
Result.insert({Loc, JoinedVal});
}
}

Expand Down Expand Up @@ -657,10 +654,10 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
// cast.
auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back());
assert(Func != nullptr);
if (Value *MergedVal =
mergeDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA,
*EnvB.ReturnVal, EnvB, JoinedEnv, Model))
JoinedEnv.ReturnVal = MergedVal;
if (Value *JoinedVal =
joinDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA,
*EnvB.ReturnVal, EnvB, JoinedEnv, Model))
JoinedEnv.ReturnVal = JoinedVal;
}

if (EnvA.ReturnLoc == EnvB.ReturnLoc)
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,10 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
VisitCallExpr(S);
}

void VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *RBO) {
propagateValue(*RBO->getSemanticForm(), *RBO, Env);
}

void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
if (S->getCastKind() == CK_ConstructorConversion) {
const Expr *SubExpr = S->getSubExpr();
Expand Down
51 changes: 47 additions & 4 deletions clang/lib/Analysis/ReachableCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
Expand Down Expand Up @@ -453,26 +454,68 @@ bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
return isDeadRoot;
}

static bool isValidDeadStmt(const Stmt *S) {
// Check if the given `DeadStmt` is a coroutine statement and is a substmt of
// the coroutine statement. `Block` is the CFGBlock containing the `DeadStmt`.
static bool isInCoroutineStmt(const Stmt *DeadStmt, const CFGBlock *Block) {
// The coroutine statement, co_return, co_await, or co_yield.
const Stmt *CoroStmt = nullptr;
// Find the first coroutine statement after the DeadStmt in the block.
bool AfterDeadStmt = false;
for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I != E;
++I)
if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
if (S == DeadStmt)
AfterDeadStmt = true;
if (AfterDeadStmt &&
// For simplicity, we only check simple coroutine statements.
(llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspendExpr>(S))) {
CoroStmt = S;
break;
}
}
if (!CoroStmt)
return false;
struct Checker : RecursiveASTVisitor<Checker> {
const Stmt *DeadStmt;
bool CoroutineSubStmt = false;
Checker(const Stmt *S) : DeadStmt(S) {}
bool VisitStmt(const Stmt *S) {
if (S == DeadStmt)
CoroutineSubStmt = true;
return true;
}
// Statements captured in the CFG can be implicit.
bool shouldVisitImplicitCode() const { return true; }
};
Checker checker(DeadStmt);
checker.TraverseStmt(const_cast<Stmt *>(CoroStmt));
return checker.CoroutineSubStmt;
}

static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) {
if (S->getBeginLoc().isInvalid())
return false;
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
return BO->getOpcode() != BO_Comma;
return true;
// Coroutine statements are never considered dead statements, because removing
// them may change the function semantic if it is the only coroutine statement
// of the coroutine.
return !isInCoroutineStmt(S, Block);
}

const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
if (isValidDeadStmt(S))
if (isValidDeadStmt(S, Block))
return S;
}

CFGTerminator T = Block->getTerminator();
if (T.isStmtBranch()) {
const Stmt *S = T.getStmt();
if (S && isValidDeadStmt(S))
if (S && isValidDeadStmt(S, Block))
return S;
}

Expand Down
37 changes: 22 additions & 15 deletions clang/lib/Analysis/UnsafeBufferUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2870,19 +2870,6 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
#endif
it = FixablesForAllVars.byVar.erase(it);
} else if (Tracker.hasUnclaimedUses(it->first)) {
#ifndef NDEBUG
auto AllUnclaimed = Tracker.getUnclaimedUses(it->first);
for (auto UnclaimedDRE : AllUnclaimed) {
std::string UnclaimedUseTrace =
getDREAncestorString(UnclaimedDRE, D->getASTContext());

Handler.addDebugNoteForVar(
it->first, UnclaimedDRE->getBeginLoc(),
("failed to produce fixit for '" + it->first->getNameAsString() +
"' : has an unclaimed use\nThe unclaimed DRE trace: " +
UnclaimedUseTrace));
}
#endif
it = FixablesForAllVars.byVar.erase(it);
} else if (it->first->isInitCapture()) {
#ifndef NDEBUG
Expand All @@ -2892,10 +2879,30 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
"' : init capture"));
#endif
it = FixablesForAllVars.byVar.erase(it);
}else {
++it;
} else {
++it;
}
}

#ifndef NDEBUG
for (const auto &it : UnsafeOps.byVar) {
const VarDecl *const UnsafeVD = it.first;
auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
if (UnclaimedDREs.empty())
continue;
const auto UnfixedVDName = UnsafeVD->getNameAsString();
for (const clang::DeclRefExpr *UnclaimedDRE : UnclaimedDREs) {
std::string UnclaimedUseTrace =
getDREAncestorString(UnclaimedDRE, D->getASTContext());

Handler.addDebugNoteForVar(
UnsafeVD, UnclaimedDRE->getBeginLoc(),
("failed to produce fixit for '" + UnfixedVDName +
"' : has an unclaimed use\nThe unclaimed DRE trace: " +
UnclaimedUseTrace));
}
}
#endif

// Fixpoint iteration for pointer assignments
using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Basic/Sarif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ static std::string percentEncodeURICharacter(char C) {
// should be written out directly. Otherwise, percent
// encode the character and write that out instead of the
// reserved character.
if (llvm::isAlnum(C) ||
StringRef::npos != StringRef("-._~:@!$&'()*+,;=").find(C))
if (llvm::isAlnum(C) || StringRef("-._~:@!$&'()*+,;=").contains(C))
return std::string(&C, 1);
return "%" + llvm::toHex(StringRef(&C, 1));
}
Expand Down
8 changes: 2 additions & 6 deletions clang/lib/Basic/Targets/AMDGPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,7 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
return true;
}

bool HasLeftParen = false;
if (S.consume_front("{"))
HasLeftParen = true;
bool HasLeftParen = S.consume_front("{");
if (S.empty())
return false;
if (S.front() != 'v' && S.front() != 's' && S.front() != 'a') {
Expand All @@ -196,9 +194,7 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
Name = S.data() - 1;
return true;
}
bool HasLeftBracket = false;
if (S.consume_front("["))
HasLeftBracket = true;
bool HasLeftBracket = S.consume_front("[");
unsigned long long N;
if (S.empty() || consumeUnsignedInteger(S, 10, N))
return false;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ bool X86TargetInfo::initFeatureMap(
if (Feature.substr(1, 6) == "avx10.") {
if (Feature[0] == '+') {
HasAVX10 = true;
if (Feature.substr(Feature.size() - 3, 3) == "512")
if (StringRef(Feature).ends_with("512"))
HasAVX10_512 = true;
LastAVX10 = Feature;
} else if (HasAVX10 && Feature == "-avx10.1-256") {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,7 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
case CC_Win64:
case CC_PreserveMost:
case CC_PreserveAll:
case CC_PreserveNone:
case CC_X86RegCall:
case CC_OpenCLKernel:
return CCCR_OK;
Expand Down Expand Up @@ -854,6 +855,7 @@ class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo
case CC_IntelOclBicc:
case CC_PreserveMost:
case CC_PreserveAll:
case CC_PreserveNone:
case CC_X86_64SysV:
case CC_Swift:
case CC_SwiftAsync:
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5710,6 +5710,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *HalfVal = Builder.CreateLoad(Address);
return RValue::get(Builder.CreateFPExt(HalfVal, Builder.getFloatTy()));
}
case Builtin::BI__builtin_printf:
case Builtin::BIprintf:
if (getTarget().getTriple().isNVPTX() ||
getTarget().getTriple().isAMDGCN()) {
Expand Down Expand Up @@ -5907,7 +5908,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
}

assert(PTy->canLosslesslyBitCastTo(FTy->getParamType(i)) &&
assert(ArgValue->getType()->canLosslesslyBitCastTo(PTy) &&
"Must be able to losslessly bit cast to param");
// Cast vector type (e.g., v256i32) to x86_amx, this only happen
// in amx intrinsics.
Expand Down Expand Up @@ -17756,9 +17757,9 @@ Value *EmitAMDGPUImplicitArgPtr(CodeGenFunction &CGF) {
// \p Index is 0, 1, and 2 for x, y, and z dimension, respectively.
/// Emit code based on Code Object ABI version.
/// COV_4 : Emit code to use dispatch ptr
/// COV_5 : Emit code to use implicitarg ptr
/// COV_5+ : Emit code to use implicitarg ptr
/// COV_NONE : Emit code to load a global variable "__oclc_ABI_version"
/// and use its value for COV_4 or COV_5 approach. It is used for
/// and use its value for COV_4 or COV_5+ approach. It is used for
/// compiling device libraries in an ABI-agnostic way.
///
/// Note: "__oclc_ABI_version" is supposed to be emitted and intialized by
Expand Down Expand Up @@ -17801,7 +17802,7 @@ Value *EmitAMDGPUWorkGroupSize(CodeGenFunction &CGF, unsigned Index) {
Address(Result, CGF.Int16Ty, CharUnits::fromQuantity(2)));
} else {
Value *GEP = nullptr;
if (Cov == CodeObjectVersionKind::COV_5) {
if (Cov >= CodeObjectVersionKind::COV_5) {
// Indexing the implicit kernarg segment.
GEP = CGF.Builder.CreateConstGEP1_32(
CGF.Int8Ty, EmitAMDGPUImplicitArgPtr(CGF), 12 + Index * 2);
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_Swift: return llvm::CallingConv::Swift;
case CC_SwiftAsync: return llvm::CallingConv::SwiftTail;
case CC_M68kRTD: return llvm::CallingConv::M68k_RTD;
case CC_PreserveNone: return llvm::CallingConv::PreserveNone;
}
}

Expand Down Expand Up @@ -256,6 +257,9 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D,
if (D->hasAttr<M68kRTDAttr>())
return CC_M68kRTD;

if (D->hasAttr<PreserveNoneAttr>())
return CC_PreserveNone;

return CC_C;
}

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1450,6 +1450,8 @@ static unsigned getDwarfCC(CallingConv CC) {
return llvm::dwarf::DW_CC_LLVM_X86RegCall;
case CC_M68kRTD:
return llvm::dwarf::DW_CC_LLVM_M68kRTD;
case CC_PreserveNone:
return llvm::dwarf::DW_CC_LLVM_PreserveNone;
}
return 0;
}
Expand Down
26 changes: 17 additions & 9 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ class ScalarExprEmitter
void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops,
llvm::Value *Zero,bool isDiv);
// Common helper for getting how wide LHS of shift is.
static Value *GetWidthMinusOneValue(Value* LHS,Value* RHS);
static Value *GetMaximumShiftAmount(Value *LHS, Value *RHS);

// Used for shifting constraints for OpenCL, do mask for powers of 2, URem for
// non powers of two.
Expand Down Expand Up @@ -4115,13 +4115,21 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
return Builder.CreateExactSDiv(diffInChars, divisor, "sub.ptr.div");
}

Value *ScalarExprEmitter::GetWidthMinusOneValue(Value* LHS,Value* RHS) {
Value *ScalarExprEmitter::GetMaximumShiftAmount(Value *LHS, Value *RHS) {
llvm::IntegerType *Ty;
if (llvm::VectorType *VT = dyn_cast<llvm::VectorType>(LHS->getType()))
Ty = cast<llvm::IntegerType>(VT->getElementType());
else
Ty = cast<llvm::IntegerType>(LHS->getType());
return llvm::ConstantInt::get(RHS->getType(), Ty->getBitWidth() - 1);
// For a given type of LHS the maximum shift amount is width(LHS)-1, however
// it can occur that width(LHS)-1 > range(RHS). Since there is no check for
// this in ConstantInt::get, this results in the value getting truncated.
// Constrain the return value to be max(RHS) in this case.
llvm::Type *RHSTy = RHS->getType();
llvm::APInt RHSMax = llvm::APInt::getMaxValue(RHSTy->getScalarSizeInBits());
if (RHSMax.ult(Ty->getBitWidth()))
return llvm::ConstantInt::get(RHSTy, RHSMax);
return llvm::ConstantInt::get(RHSTy, Ty->getBitWidth() - 1);
}

Value *ScalarExprEmitter::ConstrainShiftValue(Value *LHS, Value *RHS,
Expand All @@ -4133,7 +4141,7 @@ Value *ScalarExprEmitter::ConstrainShiftValue(Value *LHS, Value *RHS,
Ty = cast<llvm::IntegerType>(LHS->getType());

if (llvm::isPowerOf2_64(Ty->getBitWidth()))
return Builder.CreateAnd(RHS, GetWidthMinusOneValue(LHS, RHS), Name);
return Builder.CreateAnd(RHS, GetMaximumShiftAmount(LHS, RHS), Name);

return Builder.CreateURem(
RHS, llvm::ConstantInt::get(RHS->getType(), Ty->getBitWidth()), Name);
Expand All @@ -4160,13 +4168,13 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
bool SanitizeBase = SanitizeSignedBase || SanitizeUnsignedBase;
bool SanitizeExponent = CGF.SanOpts.has(SanitizerKind::ShiftExponent);
// OpenCL 6.3j: shift values are effectively % word size of LHS.
if (CGF.getLangOpts().OpenCL)
if (CGF.getLangOpts().OpenCL || CGF.getLangOpts().HLSL)
RHS = ConstrainShiftValue(Ops.LHS, RHS, "shl.mask");
else if ((SanitizeBase || SanitizeExponent) &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
SmallVector<std::pair<Value *, SanitizerMask>, 2> Checks;
llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, Ops.RHS);
llvm::Value *WidthMinusOne = GetMaximumShiftAmount(Ops.LHS, Ops.RHS);
llvm::Value *ValidExponent = Builder.CreateICmpULE(Ops.RHS, WidthMinusOne);

if (SanitizeExponent) {
Expand All @@ -4184,7 +4192,7 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
Builder.CreateCondBr(ValidExponent, CheckShiftBase, Cont);
llvm::Value *PromotedWidthMinusOne =
(RHS == Ops.RHS) ? WidthMinusOne
: GetWidthMinusOneValue(Ops.LHS, RHS);
: GetMaximumShiftAmount(Ops.LHS, RHS);
CGF.EmitBlock(CheckShiftBase);
llvm::Value *BitsShiftedOff = Builder.CreateLShr(
Ops.LHS, Builder.CreateSub(PromotedWidthMinusOne, RHS, "shl.zeros",
Expand Down Expand Up @@ -4229,13 +4237,13 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");

// OpenCL 6.3j: shift values are effectively % word size of LHS.
if (CGF.getLangOpts().OpenCL)
if (CGF.getLangOpts().OpenCL || CGF.getLangOpts().HLSL)
RHS = ConstrainShiftValue(Ops.LHS, RHS, "shr.mask");
else if (CGF.SanOpts.has(SanitizerKind::ShiftExponent) &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *Valid =
Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS));
Builder.CreateICmpULE(Ops.RHS, GetMaximumShiftAmount(Ops.LHS, Ops.RHS));
EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::ShiftExponent), Ops);
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGGPUBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ RValue EmitDevicePrintfCallExpr(const CallExpr *E, CodeGenFunction *CGF,
llvm::Function *Decl, bool WithSizeArg) {
CodeGenModule &CGM = CGF->CGM;
CGBuilderTy &Builder = CGF->Builder;
assert(E->getBuiltinCallee() == Builtin::BIprintf);
assert(E->getBuiltinCallee() == Builtin::BIprintf ||
E->getBuiltinCallee() == Builtin::BI__builtin_printf);
assert(E->getNumArgs() >= 1); // printf always has at least one arg.

// Uses the same format as nvptx for the argument packing, but also passes
Expand Down
14 changes: 4 additions & 10 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1044,17 +1044,14 @@ void CodeGenModule::Release() {
llvm::MDString::get(VMContext, "ascii"));
}

llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
if ( Arch == llvm::Triple::arm
|| Arch == llvm::Triple::armeb
|| Arch == llvm::Triple::thumb
|| Arch == llvm::Triple::thumbeb) {
llvm::Triple T = Context.getTargetInfo().getTriple();
if (T.isARM() || T.isThumb()) {
// The minimum width of an enum in bytes
uint64_t EnumWidth = Context.getLangOpts().ShortEnums ? 1 : 4;
getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth);
}

if (Arch == llvm::Triple::riscv32 || Arch == llvm::Triple::riscv64) {
if (T.isRISCV()) {
StringRef ABIStr = Target.getABI();
llvm::LLVMContext &Ctx = TheModule.getContext();
getModule().addModuleFlag(llvm::Module::Error, "target-abi",
Expand Down Expand Up @@ -1127,10 +1124,7 @@ void CodeGenModule::Release() {
getModule().addModuleFlag(llvm::Module::Override,
"tag-stack-memory-buildattr", 1);

if (Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb ||
Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb ||
Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 ||
Arch == llvm::Triple::aarch64_be) {
if (T.isARM() || T.isThumb() || T.isAArch64()) {
if (LangOpts.BranchTargetEnforcement)
getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
1);
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1347,9 +1347,10 @@ static llvm::FunctionCallee getItaniumDynamicCastFn(CodeGenFunction &CGF) {

llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);

// Mark the function as nounwind readonly.
// Mark the function as nounwind willreturn readonly.
llvm::AttrBuilder FuncAttrs(CGF.getLLVMContext());
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
FuncAttrs.addAttribute(llvm::Attribute::WillReturn);
FuncAttrs.addMemoryAttr(llvm::MemoryEffects::readOnly());
llvm::AttributeList Attrs = llvm::AttributeList::get(
CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/MacroPPCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
void MacroPPCallbacks::InclusionDirective(
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported, SrcMgr::CharacteristicKind FileType) {

// Record the line location of the current included file.
LastHashLoc = HashLoc;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/MacroPPCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ class MacroPPCallbacks : public PPCallbacks {
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported,
SrcMgr::CharacteristicKind FileType) override;

/// Hook called whenever a macro definition is seen.
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1443,11 +1443,14 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
const ToolChain &TC = getToolChain(
*UArgs, computeTargetTriple(*this, TargetTriple, *UArgs));

if (TC.getTriple().isAndroid()) {
llvm::Triple Triple = TC.getTriple();
// Check if the environment version is valid except wasm case.
llvm::Triple Triple = TC.getTriple();
if (!Triple.isWasm()) {
StringRef TripleVersionName = Triple.getEnvironmentVersionString();

if (Triple.getEnvironmentVersion().empty() && TripleVersionName != "") {
StringRef TripleObjectFormat =
Triple.getObjectFormatTypeName(Triple.getObjectFormat());
if (Triple.getEnvironmentVersion().empty() && TripleVersionName != "" &&
TripleVersionName != TripleObjectFormat) {
Diags.Report(diag::err_drv_triple_version_invalid)
<< TripleVersionName << TC.getTripleString();
ContainsError = true;
Expand Down
37 changes: 17 additions & 20 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5781,6 +5781,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// NVPTX/AMDGPU does not care about the code model and will accept
// whatever works for the host.
Ok = true;
} else if (Triple.isSPARC64()) {
if (CM == "medlow")
CM = "small";
else if (CM == "medmid")
CM = "medium";
else if (CM == "medany")
CM = "large";
Ok = CM == "small" || CM == "medium" || CM == "large";
}
if (Ok) {
CmdArgs.push_back(Args.MakeArgString("-mcmodel=" + CM));
Expand Down Expand Up @@ -5964,6 +5972,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
<< A->getAsString(Args) << A->getValue();
else
A->render(Args, CmdArgs);
} else if (Triple.isAArch64() && Triple.isOSBinFormatELF()) {
// "all" is not supported on AArch64 since branch relaxation creates new
// basic blocks for some cross-section branches.
if (Val != "labels" && Val != "none" && !Val.starts_with("list="))
D.Diag(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
else
A->render(Args, CmdArgs);
} else if (Triple.isNVPTX()) {
// Do not pass the option to the GPU compilation. We still want it enabled
// for the host-side compilation, so seeing it here is not an error.
Expand Down Expand Up @@ -7665,26 +7681,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,

addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false);

if (Arg *A = Args.getLastArg(options::OPT_moutline_atomics,
options::OPT_mno_outline_atomics)) {
// Option -moutline-atomics supported for AArch64 target only.
if (!Triple.isAArch64()) {
D.Diag(diag::warn_drv_moutline_atomics_unsupported_opt)
<< Triple.getArchName() << A->getOption().getName();
} else {
if (A->getOption().matches(options::OPT_moutline_atomics)) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+outline-atomics");
} else {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("-outline-atomics");
}
}
} else if (Triple.isAArch64() &&
getToolChain().IsAArch64OutlineAtomicsDefault(Args)) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+outline-atomics");
}
addOutlineAtomicsArgs(D, getToolChain(), Args, CmdArgs, Triple);

if (Triple.isAArch64() &&
(Args.hasArg(options::OPT_mno_fmv) ||
Expand Down
33 changes: 32 additions & 1 deletion clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2650,7 +2650,7 @@ getAMDGPUCodeObjectArgument(const Driver &D, const llvm::opt::ArgList &Args) {
void tools::checkAMDGPUCodeObjectVersion(const Driver &D,
const llvm::opt::ArgList &Args) {
const unsigned MinCodeObjVer = 4;
const unsigned MaxCodeObjVer = 5;
const unsigned MaxCodeObjVer = 6;

if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) {
if (CodeObjArg->getOption().getID() ==
Expand All @@ -2661,6 +2661,12 @@ void tools::checkAMDGPUCodeObjectVersion(const Driver &D,
if (Remnant || CodeObjVer < MinCodeObjVer || CodeObjVer > MaxCodeObjVer)
D.Diag(diag::err_drv_invalid_int_value)
<< CodeObjArg->getAsString(Args) << CodeObjArg->getValue();

// COV6 is only supported by LLVM at the time of writing this, and it's
// expected to take some time before all ROCm components fully
// support it. In the meantime, make sure users are aware of this.
if (CodeObjVer == 6)
D.Diag(diag::warn_drv_amdgpu_cov6);
}
}
}
Expand Down Expand Up @@ -2790,3 +2796,28 @@ void tools::addHIPRuntimeLibArgs(const ToolChain &TC, Compilation &C,
}
}
}

void tools::addOutlineAtomicsArgs(const Driver &D, const ToolChain &TC,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
const llvm::Triple &Triple) {
if (Arg *A = Args.getLastArg(options::OPT_moutline_atomics,
options::OPT_mno_outline_atomics)) {
// Option -moutline-atomics supported for AArch64 target only.
if (!Triple.isAArch64()) {
D.Diag(diag::warn_drv_moutline_atomics_unsupported_opt)
<< Triple.getArchName() << A->getOption().getName();
} else {
if (A->getOption().matches(options::OPT_moutline_atomics)) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+outline-atomics");
} else {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("-outline-atomics");
}
}
} else if (Triple.isAArch64() && TC.IsAArch64OutlineAtomicsDefault(Args)) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+outline-atomics");
}
}
6 changes: 6 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ void addMachineOutlinerArgs(const Driver &D, const llvm::opt::ArgList &Args,
void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
StringRef BitcodeSuffix, const llvm::Triple &Triple);

void addOutlineAtomicsArgs(const Driver &D, const ToolChain &TC,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
const llvm::Triple &Triple);

} // end namespace tools
} // end namespace driver
} // end namespace clang
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ void Flang::addTargetOptions(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString(CPU));
}

addOutlineAtomicsArgs(D, getToolChain(), Args, CmdArgs, Triple);

// Add the target features.
switch (TC.getArch()) {
default:
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Format/BreakableToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,11 +449,11 @@ const FormatToken &BreakableComment::tokenAt(unsigned LineIndex) const {

static bool mayReflowContent(StringRef Content) {
Content = Content.trim(Blanks);
// Lines starting with '@' commonly have special meaning.
// Lines starting with '@' or '\' commonly have special meaning.
// Lines starting with '-', '-#', '+' or '*' are bulleted/numbered lists.
bool hasSpecialMeaningPrefix = false;
for (StringRef Prefix :
{"@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) {
{"@", "\\", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) {
if (Content.starts_with(Prefix)) {
hasSpecialMeaningPrefix = true;
break;
Expand Down
26 changes: 20 additions & 6 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,17 @@ bool ContinuationIndenter::canBreak(const LineState &State) {

// Don't break after very short return types (e.g. "void") as that is often
// unexpected.
if (Current.is(TT_FunctionDeclarationName) && State.Column < 6) {
if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None)
if (Current.is(TT_FunctionDeclarationName)) {
if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None &&
State.Column < 6) {
return false;
}

if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_ExceptShortType) {
assert(State.Column >= State.FirstIndent);
if (State.Column - State.FirstIndent < 6)
return false;
}
}

// If binary operators are moved to the next line (including commas for some
Expand Down Expand Up @@ -561,7 +569,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
}
}
return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No;
return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No &&
(Style.AlwaysBreakTemplateDeclarations !=
FormatStyle::BTDS_Leave ||
Current.NewlinesBefore > 0);
}
if (Previous.is(TT_FunctionAnnotationRParen) &&
State.Line->Type != LT_PreprocessorDirective) {
Expand All @@ -587,7 +598,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
!State.Line->ReturnTypeWrapped &&
// Don't break before a C# function when no break after return type.
(!Style.isCSharp() ||
Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None) &&
Style.AlwaysBreakAfterReturnType > FormatStyle::RTBS_ExceptShortType) &&
// Don't always break between a JavaScript `function` and the function
// name.
!Style.isJavaScript() && Previous.isNot(tok::kw_template) &&
Expand Down Expand Up @@ -1694,8 +1705,11 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
// Special case for generic selection expressions, its comma-separated
// expressions are not aligned to the opening paren like regular calls, but
// rather continuation-indented relative to the _Generic keyword.
if (Previous && Previous->endsSequence(tok::l_paren, tok::kw__Generic))
NewParenState.Indent = CurrentState.LastSpace;
if (Previous && Previous->endsSequence(tok::l_paren, tok::kw__Generic) &&
State.Stack.size() > 1) {
NewParenState.Indent = State.Stack[State.Stack.size() - 2].Indent +
Style.ContinuationIndentWidth;
}

if ((shouldUnindentNextOperator(Current) ||
(Previous &&
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ template <>
struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> {
static void enumeration(IO &IO,
FormatStyle::BreakTemplateDeclarationsStyle &Value) {
IO.enumCase(Value, "Leave", FormatStyle::BTDS_Leave);
IO.enumCase(Value, "No", FormatStyle::BTDS_No);
IO.enumCase(Value, "MultiLine", FormatStyle::BTDS_MultiLine);
IO.enumCase(Value, "Yes", FormatStyle::BTDS_Yes);
Expand Down Expand Up @@ -558,6 +559,8 @@ template <>
struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
IO.enumCase(Value, "None", FormatStyle::RTBS_None);
IO.enumCase(Value, "Automatic", FormatStyle::RTBS_Automatic);
IO.enumCase(Value, "ExceptShortType", FormatStyle::RTBS_ExceptShortType);
IO.enumCase(Value, "All", FormatStyle::RTBS_All);
IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
IO.enumCase(Value, "TopLevelDefinitions",
Expand Down Expand Up @@ -1016,6 +1019,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
IO.mapOptional("Macros", Style.Macros);
IO.mapOptional("MainIncludeChar", Style.IncludeStyle.MainIncludeChar);
IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
IO.mapOptional("NamespaceMacros", Style.NamespaceMacros);
Expand Down Expand Up @@ -1494,6 +1498,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
{".*", 1, 0, false}};
LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$";
LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve;
LLVMStyle.IncludeStyle.MainIncludeChar = tooling::IncludeStyle::MICD_Quote;
LLVMStyle.IndentAccessModifiers = false;
LLVMStyle.IndentCaseLabels = false;
LLVMStyle.IndentCaseBlocks = false;
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3434,6 +3434,8 @@ bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const {

switch (Style.AlwaysBreakAfterReturnType) {
case FormatStyle::RTBS_None:
case FormatStyle::RTBS_Automatic:
case FormatStyle::RTBS_ExceptShortType:
return false;
case FormatStyle::RTBS_All:
case FormatStyle::RTBS_TopLevel:
Expand Down Expand Up @@ -5182,7 +5184,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
// concept ...
if (Right.is(tok::kw_concept))
return Style.BreakBeforeConceptDeclarations == FormatStyle::BBCDS_Always;
return Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes;
return Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes ||
(Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Leave &&
Right.NewlinesBefore > 0);
}
if (Left.ClosesRequiresClause && Right.isNot(tok::semi)) {
switch (Style.RequiresClausePosition) {
Expand Down Expand Up @@ -5615,7 +5619,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return Style.BreakBeforeConceptDeclarations != FormatStyle::BBCDS_Never;
if (Right.is(TT_RequiresClause))
return true;
if (Left.ClosesTemplateDeclaration || Left.is(TT_FunctionAnnotationRParen))
if (Left.ClosesTemplateDeclaration) {
return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_Leave ||
Right.NewlinesBefore > 0;
}
if (Left.is(TT_FunctionAnnotationRParen))
return true;
if (Left.ClosesRequiresClause)
return true;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Frontend/DependencyFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported,
SrcMgr::CharacteristicKind FileType) override {
if (!File)
DepCollector.maybeAddDependency(FileName, /*FromModule*/ false,
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Frontend/DependencyGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class DependencyGraphCallback : public PPCallbacks {
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported,
SrcMgr::CharacteristicKind FileType) override;

void EndOfMainFile() override {
Expand All @@ -68,8 +69,8 @@ void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
void DependencyGraphCallback::InclusionDirective(
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
if (!File)
return;

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Frontend/ModuleDependencyCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ struct ModuleDependencyPPCallbacks : public PPCallbacks {
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported,
SrcMgr::CharacteristicKind FileType) override {
if (!File)
return;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Frontend/PrecompiledPreamble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ class MissingFileCollector : public PPCallbacks {
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported,
SrcMgr::CharacteristicKind FileType) override {
// File is std::nullopt if it wasn't found.
// (We have some false negatives if PP recovered e.g. <foo> -> "foo")
Expand Down
11 changes: 6 additions & 5 deletions clang/lib/Frontend/PrintPreprocessedOutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported,
SrcMgr::CharacteristicKind FileType) override;
void Ident(SourceLocation Loc, StringRef str) override;
void PragmaMessage(SourceLocation Loc, StringRef Namespace,
Expand Down Expand Up @@ -401,8 +402,8 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
void PrintPPOutputPPCallbacks::InclusionDirective(
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
// In -dI mode, dump #include directives prior to dumping their content or
// interpretation. Similar for -fkeep-system-includes.
if (DumpIncludeDirectives || (KeepSystemIncludes && isSystem(FileType))) {
Expand All @@ -418,14 +419,14 @@ void PrintPPOutputPPCallbacks::InclusionDirective(
}

// When preprocessing, turn implicit imports into module import pragmas.
if (Imported) {
if (ModuleImported) {
switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_import:
case tok::pp_include_next:
MoveToLine(HashLoc, /*RequireStartOfLine=*/true);
*OS << "#pragma clang module import "
<< Imported->getFullModuleName(true)
<< SuggestedModule->getFullModuleName(true)
<< " /* clang -E: implicit import for "
<< "#" << PP.getSpelling(IncludeTok) << " "
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ class InclusionRewriter : public PPCallbacks {
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported,
SrcMgr::CharacteristicKind FileType) override;
void If(SourceLocation Loc, SourceRange ConditionRange,
ConditionValueKind ConditionValue) override;
Expand Down Expand Up @@ -189,9 +190,10 @@ void InclusionRewriter::InclusionDirective(
StringRef /*FileName*/, bool /*IsAngled*/,
CharSourceRange /*FilenameRange*/, OptionalFileEntryRef /*File*/,
StringRef /*SearchPath*/, StringRef /*RelativePath*/,
const Module *Imported, SrcMgr::CharacteristicKind FileType) {
if (Imported) {
auto P = ModuleIncludes.insert(std::make_pair(HashLoc, Imported));
const Module *SuggestedModule, bool ModuleImported,
SrcMgr::CharacteristicKind FileType) {
if (ModuleImported) {
auto P = ModuleIncludes.insert(std::make_pair(HashLoc, SuggestedModule));
(void)P;
assert(P.second && "Unexpected revisitation of the same include directive");
} else
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,12 @@ class VerifyDiagnosticConsumer::MarkerTracker {
}
};

static std::string DetailedErrorString(const DiagnosticsEngine &Diags) {
if (Diags.getDiagnosticOptions().VerifyPrefixes.empty())
return "expected";
return *Diags.getDiagnosticOptions().VerifyPrefixes.begin();
}

/// ParseDirective - Go through the comment and see if it indicates expected
/// diagnostics. If so, then put them in the appropriate directive list.
///
Expand Down Expand Up @@ -478,14 +484,14 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
if (NoDiag) {
if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
Diags.Report(Pos, diag::err_verify_invalid_no_diags)
<< /*IsExpectedNoDiagnostics=*/true;
<< DetailedErrorString(Diags) << /*IsExpectedNoDiagnostics=*/true;
else
Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
continue;
}
if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
Diags.Report(Pos, diag::err_verify_invalid_no_diags)
<< /*IsExpectedNoDiagnostics=*/false;
<< DetailedErrorString(Diags) << /*IsExpectedNoDiagnostics=*/false;
continue;
}
Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;
Expand Down Expand Up @@ -1104,7 +1110,8 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
// Produce an error if no expected-* directives could be found in the
// source file(s) processed.
if (Status == HasNoDirectives) {
Diags.Report(diag::err_verify_no_directives).setForceEmit();
Diags.Report(diag::err_verify_no_directives).setForceEmit()
<< DetailedErrorString(Diags);
++NumErrors;
Status = HasNoDirectivesReported;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ CreateFrontendAction(CompilerInstance &CI) {
#endif

// Wrap the base FE action in an extract api action to generate
// symbol graph as a biproduct of comilation ( enabled with
// symbol graph as a biproduct of compilation ( enabled with
// --emit-symbol-graph option )
if (!FEOpts.SymbolGraphOutputDir.empty()) {
CI.getCodeGenOpts().ClearASTBeforeBackend = false;
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Headers/cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@
#define bit_AMXINT8 0x02000000

/* Features in %eax for leaf 7 sub-leaf 1 */
#define bit_SHA512 0x00000001
#define bit_SM3 0x00000002
#define bit_SM4 0x00000004
#define bit_RAOINT 0x00000008
#define bit_AVXVNNI 0x00000010
#define bit_AVX512BF16 0x00000020
Expand All @@ -211,7 +214,11 @@
/* Features in %edx for leaf 7 sub-leaf 1 */
#define bit_AVXVNNIINT8 0x00000010
#define bit_AVXNECONVERT 0x00000020
#define bit_AMXCOMPLEX 0x00000100
#define bit_AVXVNNIINT16 0x00000400
#define bit_PREFETCHI 0x00004000
#define bit_USERMSR 0x00008000
#define bit_AVX10 0x00080000

/* Features in %eax for leaf 13 sub-leaf 1 */
#define bit_XSAVEOPT 0x00000001
Expand Down Expand Up @@ -244,6 +251,9 @@
#define bit_RDPRU 0x00000010
#define bit_WBNOINVD 0x00000200

/* Features in %ebx for leaf 0x24 */
#define bit_AVX10_256 0x00020000
#define bit_AVX10_512 0x00040000

#if __i386__
#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \
Expand Down
72 changes: 36 additions & 36 deletions clang/lib/Lex/PPDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2253,26 +2253,27 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(

// FIXME: We do not have a good way to disambiguate C++ clang modules from
// C++ standard modules (other than use/non-use of Header Units).
Module *SM = SuggestedModule.getModule();

bool MaybeTranslateInclude =
Action == Enter && File && SM && !SM->isForBuilding(getLangOpts());
Module *ModuleToImport = SuggestedModule.getModule();

bool MaybeTranslateInclude = Action == Enter && File && ModuleToImport &&
!ModuleToImport->isForBuilding(getLangOpts());

// Maybe a usable Header Unit
bool UsableHeaderUnit = false;
if (getLangOpts().CPlusPlusModules && SM && SM->isHeaderUnit()) {
if (getLangOpts().CPlusPlusModules && ModuleToImport &&
ModuleToImport->isHeaderUnit()) {
if (TrackGMFState.inGMF() || IsImportDecl)
UsableHeaderUnit = true;
else if (!IsImportDecl) {
// This is a Header Unit that we do not include-translate
SuggestedModule = ModuleMap::KnownHeader();
SM = nullptr;
ModuleToImport = nullptr;
}
}
// Maybe a usable clang header module.
bool UsableClangHeaderModule =
(getLangOpts().CPlusPlusModules || getLangOpts().Modules) && SM &&
!SM->isHeaderUnit();
(getLangOpts().CPlusPlusModules || getLangOpts().Modules) &&
ModuleToImport && !ModuleToImport->isHeaderUnit();

// Determine whether we should try to import the module for this #include, if
// there is one. Don't do so if precompiled module support is disabled or we
Expand All @@ -2282,20 +2283,19 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// unavailable, diagnose the situation and bail out.
// FIXME: Remove this; loadModule does the same check (but produces
// slightly worse diagnostics).
if (checkModuleIsAvailable(getLangOpts(), getTargetInfo(),
*SuggestedModule.getModule(),
if (checkModuleIsAvailable(getLangOpts(), getTargetInfo(), *ModuleToImport,
getDiagnostics())) {
Diag(FilenameTok.getLocation(),
diag::note_implicit_top_level_module_import_here)
<< SuggestedModule.getModule()->getTopLevelModuleName();
<< ModuleToImport->getTopLevelModuleName();
return {ImportAction::None};
}

// Compute the module access path corresponding to this module.
// FIXME: Should we have a second loadModule() overload to avoid this
// extra lookup step?
SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
for (Module *Mod = SM; Mod; Mod = Mod->Parent)
for (Module *Mod = ModuleToImport; Mod; Mod = Mod->Parent)
Path.push_back(std::make_pair(getIdentifierInfo(Mod->Name),
FilenameTok.getLocation()));
std::reverse(Path.begin(), Path.end());
Expand All @@ -2306,12 +2306,12 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(

// Load the module to import its macros. We'll make the declarations
// visible when the parser gets here.
// FIXME: Pass SuggestedModule in here rather than converting it to a path
// FIXME: Pass ModuleToImport in here rather than converting it to a path
// and making the module loader convert it back again.
ModuleLoadResult Imported = TheModuleLoader.loadModule(
IncludeTok.getLocation(), Path, Module::Hidden,
/*IsInclusionDirective=*/true);
assert((Imported == nullptr || Imported == SuggestedModule.getModule()) &&
assert((Imported == nullptr || Imported == ModuleToImport) &&
"the imported module is different than the suggested one");

if (Imported) {
Expand All @@ -2323,8 +2323,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// was in the directory of an umbrella header, for instance), but no
// actual module containing it exists (because the umbrella header is
// incomplete). Treat this as a textual inclusion.
SuggestedModule = ModuleMap::KnownHeader();
SM = nullptr;
ModuleToImport = nullptr;
} else if (Imported.isConfigMismatch()) {
// On a configuration mismatch, enter the header textually. We still know
// that it's part of the corresponding module.
Expand Down Expand Up @@ -2365,7 +2364,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// this file will have no effect.
if (Action == Enter && File &&
!HeaderInfo.ShouldEnterIncludeFile(*this, *File, EnterOnce,
getLangOpts().Modules, SM,
getLangOpts().Modules, ModuleToImport,
IsFirstIncludeOfFile)) {
// C++ standard modules:
// If we are not in the GMF, then we textually include only
Expand All @@ -2380,7 +2379,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
if (UsableHeaderUnit && !getLangOpts().CompilingPCH)
Action = TrackGMFState.inGMF() ? Import : Skip;
else
Action = (SuggestedModule && !getLangOpts().CompilingPCH) ? Import : Skip;
Action = (ModuleToImport && !getLangOpts().CompilingPCH) ? Import : Skip;
}

// Check for circular inclusion of the main file.
Expand All @@ -2400,8 +2399,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// FIXME: Use a different callback for a pp-import?
Callbacks->InclusionDirective(HashLoc, IncludeTok, LookupFilename, isAngled,
FilenameRange, File, SearchPath, RelativePath,
Action == Import ? SuggestedModule.getModule()
: nullptr,
SuggestedModule.getModule(), Action == Import,
FileCharacter);
if (Action == Skip && File)
Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
Expand All @@ -2412,7 +2410,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(

// If this is a C++20 pp-import declaration, diagnose if we didn't find any
// module corresponding to the named header.
if (IsImportDecl && !SuggestedModule) {
if (IsImportDecl && !ModuleToImport) {
Diag(FilenameTok, diag::err_header_import_not_header_unit)
<< OriginalFilename << File->getName();
return {ImportAction::None};
Expand Down Expand Up @@ -2517,8 +2515,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
switch (Action) {
case Skip:
// If we don't need to enter the file, stop now.
if (SM)
return {ImportAction::SkippedModuleImport, SM};
if (ModuleToImport)
return {ImportAction::SkippedModuleImport, ModuleToImport};
return {ImportAction::None};

case IncludeLimitReached:
Expand All @@ -2528,15 +2526,15 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(

case Import: {
// If this is a module import, make it visible if needed.
assert(SM && "no module to import");
assert(ModuleToImport && "no module to import");

makeModuleVisible(SM, EndLoc);
makeModuleVisible(ModuleToImport, EndLoc);

if (IncludeTok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp___include_macros)
return {ImportAction::None};

return {ImportAction::ModuleImport, SM};
return {ImportAction::ModuleImport, ModuleToImport};
}

case Enter:
Expand Down Expand Up @@ -2573,13 +2571,14 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(

// Determine if we're switching to building a new submodule, and which one.
// This does not apply for C++20 modules header units.
if (SM && !SM->isHeaderUnit()) {
if (SM->getTopLevelModule()->ShadowingModule) {
if (ModuleToImport && !ModuleToImport->isHeaderUnit()) {
if (ModuleToImport->getTopLevelModule()->ShadowingModule) {
// We are building a submodule that belongs to a shadowed module. This
// means we find header files in the shadowed module.
Diag(SM->DefinitionLoc, diag::err_module_build_shadowed_submodule)
<< SM->getFullModuleName();
Diag(SM->getTopLevelModule()->ShadowingModule->DefinitionLoc,
Diag(ModuleToImport->DefinitionLoc,
diag::err_module_build_shadowed_submodule)
<< ModuleToImport->getFullModuleName();
Diag(ModuleToImport->getTopLevelModule()->ShadowingModule->DefinitionLoc,
diag::note_previous_definition);
return {ImportAction::None};
}
Expand All @@ -2591,21 +2590,22 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// that behaves the same as the header would behave in a compilation using
// that PCH, which means we should enter the submodule. We need to teach
// the AST serialization layer to deal with the resulting AST.
if (getLangOpts().CompilingPCH && SM->isForBuilding(getLangOpts()))
if (getLangOpts().CompilingPCH &&
ModuleToImport->isForBuilding(getLangOpts()))
return {ImportAction::None};

assert(!CurLexerSubmodule && "should not have marked this as a module yet");
CurLexerSubmodule = SM;
CurLexerSubmodule = ModuleToImport;

// Let the macro handling code know that any future macros are within
// the new submodule.
EnterSubmodule(SM, EndLoc, /*ForPragma*/ false);
EnterSubmodule(ModuleToImport, EndLoc, /*ForPragma*/ false);

// Let the parser know that any future declarations are within the new
// submodule.
// FIXME: There's no point doing this if we're handling a #__include_macros
// directive.
return {ImportAction::ModuleBegin, SM};
return {ImportAction::ModuleBegin, ModuleToImport};
}

assert(!IsImportDecl && "failed to diagnose missing module for import decl");
Expand Down Expand Up @@ -3288,7 +3288,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result,
return;
}

emitMacroExpansionWarnings(MacroNameTok);
emitMacroExpansionWarnings(MacroNameTok, /*IsIfnDef=*/true);

// Check to see if this is the last token on the #if[n]def line.
CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef");
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Lex/PPExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
DT.IncludedUndefinedIds = !Macro;

PP.emitMacroExpansionWarnings(PeekTok);
PP.emitMacroExpansionWarnings(
PeekTok,
(II->getName() == "INFINITY" || II->getName() == "NAN") ? true : false);

// If there is a macro, mark it used.
if (Result.Val != 0 && ValueLive)
Expand Down
11 changes: 5 additions & 6 deletions clang/lib/Lex/PreprocessingRecord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,8 @@ void PreprocessingRecord::MacroUndefined(const Token &Id,
void PreprocessingRecord::InclusionDirective(
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
InclusionDirective::InclusionKind Kind = InclusionDirective::Include;

switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
Expand Down Expand Up @@ -506,10 +506,9 @@ void PreprocessingRecord::InclusionDirective(
EndLoc = EndLoc.getLocWithOffset(-1); // the InclusionDirective expects
// a token range.
}
clang::InclusionDirective *ID =
new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
(bool)Imported, File,
SourceRange(HashLoc, EndLoc));
clang::InclusionDirective *ID = new (*this) clang::InclusionDirective(
*this, Kind, FileName, !IsAngled, ModuleImported, File,
SourceRange(HashLoc, EndLoc));
addPreprocessedEntity(ID);
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
.Case("declare", OpenACCDirectiveKind::Declare)
.Case("init", OpenACCDirectiveKind::Init)
.Case("shutdown", OpenACCDirectiveKind::Shutdown)
.Case("set", OpenACCDirectiveKind::Shutdown)
.Case("set", OpenACCDirectiveKind::Set)
.Case("update", OpenACCDirectiveKind::Update)
.Case("wait", OpenACCDirectiveKind::Wait)
.Default(OpenACCDirectiveKind::Invalid);
Expand Down
16 changes: 8 additions & 8 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16129,10 +16129,10 @@ static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E,
/// Check conversion of given expression to boolean.
/// Input argument E is a logical expression.
static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
// While C23 does have bool as a keyword, we still need to run the bool-like
// conversion checks as bools are still not used as the return type from
// "boolean" operators or as the input type for conditional operators.
if (S.getLangOpts().Bool && !S.getLangOpts().C23)
// Run the bool-like conversion checks only for C since there bools are
// still not used as the return type from "boolean" operators or as the input
// type for conditional operators.
if (S.getLangOpts().CPlusPlus)
return;
if (E->IgnoreParenImpCasts()->getType()->isAtomicType())
return;
Expand Down Expand Up @@ -17183,7 +17183,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
// evaluates to true.
bool EvalResult = false;
bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
bool ShouldVisitRHS = !EvalOK || (EvalOK && !EvalResult);
bool ShouldVisitRHS = !EvalOK || !EvalResult;
if (ShouldVisitRHS) {
Region = RHSRegion;
Visit(BO->getRHS());
Expand Down Expand Up @@ -17215,7 +17215,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
// [...] the second operand is not evaluated if the first operand is false.
bool EvalResult = false;
bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
bool ShouldVisitRHS = !EvalOK || (EvalOK && EvalResult);
bool ShouldVisitRHS = !EvalOK || EvalResult;
if (ShouldVisitRHS) {
Region = RHSRegion;
Visit(BO->getRHS());
Expand Down Expand Up @@ -17266,8 +17266,8 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
// evaluated. [...]
bool EvalResult = false;
bool EvalOK = Eval.evaluate(CO->getCond(), EvalResult);
bool ShouldVisitTrueExpr = !EvalOK || (EvalOK && EvalResult);
bool ShouldVisitFalseExpr = !EvalOK || (EvalOK && !EvalResult);
bool ShouldVisitTrueExpr = !EvalOK || EvalResult;
bool ShouldVisitFalseExpr = !EvalOK || !EvalResult;
if (ShouldVisitTrueExpr) {
Region = TrueRegion;
Visit(CO->getTrueExpr());
Expand Down
105 changes: 55 additions & 50 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9759,7 +9759,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
SmallVector<TemplateParameterList *, 4> TemplateParamLists;
llvm::append_range(TemplateParamLists, TemplateParamListsRef);
if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) {
if (!TemplateParamLists.empty() &&
if (!TemplateParamLists.empty() && !TemplateParamLists.back()->empty() &&
Invented->getDepth() == TemplateParamLists.back()->getDepth())
TemplateParamLists.back() = Invented;
else
Expand Down Expand Up @@ -10440,6 +10440,60 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::ext_operator_new_delete_declared_inline)
<< NewFD->getDeclName();

if (Expr *TRC = NewFD->getTrailingRequiresClause()) {
// C++20 [dcl.decl.general]p4:
// The optional requires-clause in an init-declarator or
// member-declarator shall be present only if the declarator declares a
// templated function.
//
// C++20 [temp.pre]p8:
// An entity is templated if it is
// - a template,
// - an entity defined or created in a templated entity,
// - a member of a templated entity,
// - an enumerator for an enumeration that is a templated entity, or
// - the closure type of a lambda-expression appearing in the
// declaration of a templated entity.
//
// [Note 6: A local class, a local or block variable, or a friend
// function defined in a templated entity is a templated entity.
// — end note]
//
// A templated function is a function template or a function that is
// templated. A templated class is a class template or a class that is
// templated. A templated variable is a variable template or a variable
// that is templated.
if (!FunctionTemplate) {
if (isFunctionTemplateSpecialization || isMemberSpecialization) {
// C++ [temp.expl.spec]p8 (proposed resolution for CWG2847):
// An explicit specialization shall not have a trailing
// requires-clause unless it declares a function template.
//
// Since a friend function template specialization cannot be
// definition, and since a non-template friend declaration with a
// trailing requires-clause must be a definition, we diagnose
// friend function template specializations with trailing
// requires-clauses on the same path as explicit specializations
// even though they aren't necessarily prohibited by the same
// language rule.
Diag(TRC->getBeginLoc(), diag::err_non_temp_spec_requires_clause)
<< isFriend;
} else if (isFriend && NewFD->isTemplated() &&
!D.isFunctionDefinition()) {
// C++ [temp.friend]p9:
// A non-template friend declaration with a requires-clause shall be
// a definition.
Diag(NewFD->getBeginLoc(),
diag::err_non_temp_friend_decl_with_requires_clause_must_be_def);
NewFD->setInvalidDecl();
} else if (!NewFD->isTemplated() ||
!(isa<CXXMethodDecl>(NewFD) || D.isFunctionDefinition())) {
Diag(TRC->getBeginLoc(),
diag::err_constrained_non_templated_function);
}
}
}

// We do not add HD attributes to specializations here because
// they may have different constexpr-ness compared to their
// templates and, after maybeAddCUDAHostDeviceAttrs() is applied,
Expand Down Expand Up @@ -12063,55 +12117,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
checkThisInStaticMemberFunctionType(Method);
}

if (Expr *TRC = NewFD->getTrailingRequiresClause()) {
// C++20: dcl.decl.general p4:
// The optional requires-clause ([temp.pre]) in an init-declarator or
// member-declarator shall be present only if the declarator declares a
// templated function ([dcl.fct]).
//
// [temp.pre]/8:
// An entity is templated if it is
// - a template,
// - an entity defined ([basic.def]) or created ([class.temporary]) in a
// templated entity,
// - a member of a templated entity,
// - an enumerator for an enumeration that is a templated entity, or
// - the closure type of a lambda-expression ([expr.prim.lambda.closure])
// appearing in the declaration of a templated entity. [Note 6: A local
// class, a local or block variable, or a friend function defined in a
// templated entity is a templated entity. — end note]
//
// A templated function is a function template or a function that is
// templated. A templated class is a class template or a class that is
// templated. A templated variable is a variable template or a variable
// that is templated.

bool IsTemplate = NewFD->getDescribedFunctionTemplate();
bool IsFriend = NewFD->getFriendObjectKind();
if (!IsTemplate && // -a template
// defined... in a templated entity
!(DeclIsDefn && NewFD->isTemplated()) &&
// a member of a templated entity
!(isa<CXXMethodDecl>(NewFD) && NewFD->isTemplated()) &&
// Don't complain about instantiations, they've already had these
// rules + others enforced.
!NewFD->isTemplateInstantiation() &&
// If the function violates [temp.friend]p9 because it is missing
// a definition, and adding a definition would make it templated,
// then let that error take precedence.
!(!DeclIsDefn && IsFriend && NewFD->isTemplated())) {
Diag(TRC->getBeginLoc(), diag::err_constrained_non_templated_function);
} else if (!DeclIsDefn && !IsTemplate && IsFriend &&
!NewFD->isTemplateInstantiation()) {
// C++ [temp.friend]p9:
// A non-template friend declaration with a requires-clause shall be a
// definition.
Diag(NewFD->getBeginLoc(),
diag::err_non_temp_friend_decl_with_requires_clause_must_be_def);
NewFD->setInvalidDecl();
}
}

if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
ActOnConversionDeclarator(Conversion);

Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5235,6 +5235,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
case ParsedAttr::AT_M68kRTD:
D->addAttr(::new (S.Context) M68kRTDAttr(S.Context, AL));
return;
case ParsedAttr::AT_PreserveNone:
D->addAttr(::new (S.Context) PreserveNoneAttr(S.Context, AL));
return;
default:
llvm_unreachable("unexpected attribute kind");
}
Expand Down Expand Up @@ -5441,6 +5444,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
case ParsedAttr::AT_M68kRTD:
CC = CC_M68kRTD;
break;
case ParsedAttr::AT_PreserveNone:
CC = CC_PreserveNone;
break;
default: llvm_unreachable("unexpected attribute kind");
}

Expand Down Expand Up @@ -9559,6 +9565,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_AArch64SVEPcs:
case ParsedAttr::AT_AMDGPUKernelCall:
case ParsedAttr::AT_M68kRTD:
case ParsedAttr::AT_PreserveNone:
handleCallConvAttr(S, D, AL);
break;
case ParsedAttr::AT_Suppress:
Expand Down
11 changes: 10 additions & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19294,7 +19294,16 @@ void Sema::ActOnStartFunctionDeclarationDeclarator(
ExplicitLists, /*IsFriend=*/false, IsMemberSpecialization, IsInvalid,
/*SuppressDiagnostic=*/true);
}
if (ExplicitParams) {
// C++23 [dcl.fct]p23:
// An abbreviated function template can have a template-head. The invented
// template-parameters are appended to the template-parameter-list after
// the explicitly declared template-parameters.
//
// A template-head must have one or more template-parameters (read:
// 'template<>' is *not* a template-head). Only append the invented
// template parameters if we matched the nested-name-specifier to a non-empty
// TemplateParameterList.
if (ExplicitParams && !ExplicitParams->empty()) {
Info.AutoTemplateParameterDepth = ExplicitParams->getDepth();
llvm::append_range(Info.TemplateParams, *ExplicitParams);
Info.NumExplicitTemplateParams = ExplicitParams->size();
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14073,7 +14073,7 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
Expr::EvalResult EVResult;
if (RHS.get()->EvaluateAsInt(EVResult, Context)) {
llvm::APSInt Result = EVResult.Val.getInt();
if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType() &&
if ((getLangOpts().CPlusPlus && !RHS.get()->getType()->isBooleanType() &&
!RHS.get()->getExprLoc().isMacroID()) ||
(Result != 0 && Result != 1)) {
Diag(Loc, diag::warn_logical_instead_of_bitwise)
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21124,6 +21124,8 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
ExprTy = ATy->getElementType();
else
ExprTy = BaseType->getPointeeType();
if (BaseType.isNull() || ExprTy.isNull())
return nullptr;
ExprTy = ExprTy.getNonReferenceType();
const Expr *Length = OASE->getLength();
Expr::EvalResult Result;
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2177,7 +2177,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
From->isIntegerConstantExpr(S.getASTContext())) {
SCS.Second = ICK_Compatible_Conversion;
FromType = ToType;
} else if (ToType->isFixedPointType() || FromType->isFixedPointType()) {
} else if ((ToType->isFixedPointType() &&
FromType->isConvertibleToFixedPointType()) ||
(FromType->isFixedPointType() &&
ToType->isConvertibleToFixedPointType())) {
SCS.Second = ICK_Fixed_Point_Conversion;
FromType = ToType;
} else {
Expand Down Expand Up @@ -7719,8 +7722,8 @@ bool Sema::CheckNonDependentConversions(
unsigned Offset =
Method && Method->hasCXXExplicitFunctionObjectParameter() ? 1 : 0;

for (unsigned I = 0, N = std::min(ParamTypes.size(), Args.size()); I != N;
++I) {
for (unsigned I = 0, N = std::min(ParamTypes.size() - Offset, Args.size());
I != N; ++I) {
QualType ParamType = ParamTypes[I + Offset];
if (!ParamType->isDependentType()) {
unsigned ConvIdx;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaRISCVVectorLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ void RISCVIntrinsicManagerImpl::ConstructRVVIntrinsics(
{"zvknhb", RVV_REQ_Zvknhb},
{"zvksed", RVV_REQ_Zvksed},
{"zvksh", RVV_REQ_Zvksh},
{"zvfbfwma", RVV_REQ_Zvfbfwma},
{"experimental", RVV_REQ_Experimental}};

// Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics
Expand Down
32 changes: 30 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,38 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,

while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
if (NNS->isInstantiationDependent()) {
if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>())
if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) {
ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments();
// Prefer template arguments from the injected-class-type if possible.
// For example,
// ```cpp
// template <class... Pack> struct S {
// template <class T> void foo();
// };
// template <class... Pack> template <class T>
// ^^^^^^^^^^^^^ InjectedTemplateArgs
// They're of kind TemplateArgument::Pack, not of
// TemplateArgument::Type.
// void S<Pack...>::foo() {}
// ^^^^^^^
// TSTy->template_arguments() (which are of PackExpansionType)
// ```
// This meets the contract in
// TreeTransform::TryExpandParameterPacks that the template arguments
// for unexpanded parameters should be of a Pack kind.
if (TSTy->isCurrentInstantiation()) {
auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl();
if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
Arguments = CTD->getInjectedTemplateArgs();
else if (auto *Specialization =
dyn_cast<ClassTemplateSpecializationDecl>(RD))
Arguments =
Specialization->getTemplateInstantiationArgs().asArray();
}
Result.addOuterTemplateArguments(
const_cast<FunctionTemplateDecl *>(FTD), TSTy->template_arguments(),
const_cast<FunctionTemplateDecl *>(FTD), Arguments,
/*Final=*/false);
}
}

NNS = NNS->getPrefix();
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
case ParsedAttr::AT_IntelOclBicc: \
case ParsedAttr::AT_PreserveMost: \
case ParsedAttr::AT_PreserveAll: \
case ParsedAttr::AT_M68kRTD
case ParsedAttr::AT_M68kRTD: \
case ParsedAttr::AT_PreserveNone

// Function type attributes.
#define FUNCTION_TYPE_ATTRS_CASELIST \
Expand Down Expand Up @@ -7919,6 +7920,8 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
return createSimpleAttr<PreserveAllAttr>(Ctx, Attr);
case ParsedAttr::AT_M68kRTD:
return createSimpleAttr<M68kRTDAttr>(Ctx, Attr);
case ParsedAttr::AT_PreserveNone:
return createSimpleAttr<PreserveNoneAttr>(Ctx, Attr);
}
llvm_unreachable("unexpected attribute kind!");
}
Expand Down
Loading