54 changes: 40 additions & 14 deletions clang/lib/AST/Interp/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,12 @@ bool InitLink::emit(Compiler<Emitter> *Ctx, const Expr *E) const {
case K_Field:
// We're assuming there's a base pointer on the stack already.
return Ctx->emitGetPtrFieldPop(Offset, E);
case K_Temp:
return Ctx->emitGetPtrLocal(Offset, E);
case K_Decl:
return Ctx->visitDeclRef(D, E);
default:
llvm_unreachable("Unhandled InitLink kind");
}
return true;
}
Expand Down Expand Up @@ -1285,7 +1289,13 @@ bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
template <class Emitter>
bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
const Expr *ArrayFiller, const Expr *E) {
if (E->getType()->isVoidType())

QualType QT = E->getType();

if (const auto *AT = QT->getAs<AtomicType>())
QT = AT->getValueType();

if (QT->isVoidType())
return this->emitInvalid(E);

// Handle discarding first.
Expand All @@ -1298,17 +1308,16 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
}

// Primitive values.
if (std::optional<PrimType> T = classify(E->getType())) {
if (std::optional<PrimType> T = classify(QT)) {
assert(!DiscardResult);
if (Inits.size() == 0)
return this->visitZeroInitializer(*T, E->getType(), E);
return this->visitZeroInitializer(*T, QT, E);
assert(Inits.size() == 1);
return this->delegate(Inits[0]);
}

QualType T = E->getType();
if (T->isRecordType()) {
const Record *R = getRecord(E->getType());
if (QT->isRecordType()) {
const Record *R = getRecord(QT);

if (Inits.size() == 1 && E->getType() == Inits[0]->getType())
return this->delegate(Inits[0]);
Expand All @@ -1325,6 +1334,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,

auto initCompositeField = [=](const Record::Field *FieldToInit,
const Expr *Init) -> bool {
InitLinkScope<Emitter> ILS(this, InitLink::Field(FieldToInit->Offset));
// Non-primitive case. Get a pointer to the field-to-initialize
// on the stack and recurse into visitInitializer().
if (!this->emitGetPtrField(FieldToInit->Offset, Init))
Expand Down Expand Up @@ -1405,8 +1415,8 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
return this->emitFinishInit(E);
}

if (T->isArrayType()) {
if (Inits.size() == 1 && E->getType() == Inits[0]->getType())
if (QT->isArrayType()) {
if (Inits.size() == 1 && QT == Inits[0]->getType())
return this->delegate(Inits[0]);

unsigned ElementIndex = 0;
Expand Down Expand Up @@ -1438,7 +1448,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
// FIXME: This should go away.
if (ArrayFiller) {
const ConstantArrayType *CAT =
Ctx.getASTContext().getAsConstantArrayType(E->getType());
Ctx.getASTContext().getAsConstantArrayType(QT);
uint64_t NumElems = CAT->getZExtSize();

for (; ElementIndex != NumElems; ++ElementIndex) {
Expand All @@ -1450,7 +1460,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
return this->emitFinishInit(E);
}

if (const auto *ComplexTy = E->getType()->getAs<ComplexType>()) {
if (const auto *ComplexTy = QT->getAs<ComplexType>()) {
unsigned NumInits = Inits.size();

if (NumInits == 1)
Expand Down Expand Up @@ -1480,7 +1490,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
return true;
}

if (const auto *VecT = E->getType()->getAs<VectorType>()) {
if (const auto *VecT = QT->getAs<VectorType>()) {
unsigned NumVecElements = VecT->getNumElements();
assert(NumVecElements >= Inits.size());

Expand Down Expand Up @@ -2266,6 +2276,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
const Expr *Inner = E->getSubExpr()->skipRValueSubobjectAdjustments();
if (std::optional<unsigned> LocalIndex =
allocateLocal(Inner, E->getExtendingDecl())) {
InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex));
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
return this->visitInitializer(SubExpr);
Expand Down Expand Up @@ -2442,6 +2453,13 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (T->isRecordType()) {
const CXXConstructorDecl *Ctor = E->getConstructor();

// Trivial copy/move constructor. Avoid copy.
if (Ctor->isDefaulted() && Ctor->isCopyOrMoveConstructor() &&
Ctor->isTrivial() &&
E->getArg(0)->isTemporaryObject(Ctx.getASTContext(),
T->getAsCXXRecordDecl()))
return this->visitInitializer(E->getArg(0));

// If we're discarding a construct expression, we still need
// to allocate a variable and call the constructor and destructor.
if (DiscardResult) {
Expand Down Expand Up @@ -3572,6 +3590,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, bool Topleve
return !Init || (checkDecl() && initGlobal(*GlobalIndex));
} else {
VariableScope<Emitter> LocalScope(this, VD);
InitLinkScope<Emitter> ILS(this, InitLink::Decl(VD));

if (VarT) {
unsigned Offset = this->allocateLocalPrimitive(
Expand Down Expand Up @@ -3906,7 +3925,8 @@ bool Compiler<Emitter>::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
SourceLocScope<Emitter> SLS(this, E);

bool Old = InitStackActive;
InitStackActive = !isa<FunctionDecl>(E->getUsedContext());
InitStackActive =
!(E->getUsedContext()->getDeclKind() == Decl::CXXConstructor);
bool Result = this->delegate(E->getExpr());
InitStackActive = Old;
return Result;
Expand Down Expand Up @@ -3968,8 +3988,14 @@ bool Compiler<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
// currently being initialized. Here we emit the necessary instruction(s) for
// this scenario.
if (InitStackActive && !InitStack.empty()) {
for (const InitLink &IL : InitStack) {
if (!IL.emit<Emitter>(this, E))
unsigned StartIndex = 0;
for (StartIndex = InitStack.size() - 1; StartIndex > 0; --StartIndex) {
if (InitStack[StartIndex].Kind != InitLink::K_Field)
break;
}

for (unsigned I = StartIndex, N = InitStack.size(); I != N; ++I) {
if (!InitStack[I].template emit<Emitter>(this, E))
return false;
}
return true;
Expand Down
9 changes: 7 additions & 2 deletions clang/lib/AST/Interp/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ struct InitLink {
enum {
K_This = 0,
K_Field = 1,
K_Decl = 2,
K_Temp = 2,
K_Decl = 3,
};

static InitLink This() { return InitLink{K_This}; }
Expand All @@ -56,6 +57,11 @@ struct InitLink {
IL.Offset = Offset;
return IL;
}
static InitLink Temp(unsigned Offset) {
InitLink IL{K_Temp};
IL.Offset = Offset;
return IL;
}
static InitLink Decl(const ValueDecl *D) {
InitLink IL{K_Decl};
IL.D = D;
Expand All @@ -66,7 +72,6 @@ struct InitLink {
template <class Emitter>
bool emit(Compiler<Emitter> *Ctx, const Expr *E) const;

private:
uint32_t Kind;
union {
unsigned Offset;
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
bool CheckFullyInitialized) {
this->CheckFullyInitialized = CheckFullyInitialized;
S.EvaluatingDecl = VD;
EvalResult.setSource(VD);

if (const Expr *Init = VD->getAnyInitializer()) {
QualType T = VD->getType();
Expand Down Expand Up @@ -156,7 +157,8 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID())
return false;

if (std::optional<APValue> V = Ptr.toRValue(Ctx)) {
if (std::optional<APValue> V =
Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
EvalResult.setValue(*V);
} else {
return false;
Expand Down Expand Up @@ -186,7 +188,8 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
return false;

if (std::optional<APValue> APV = Ptr.toRValue(S.getCtx())) {
if (std::optional<APValue> APV =
Ptr.toRValue(S.getCtx(), EvalResult.getSourceType())) {
EvalResult.setValue(*APV);
return true;
}
Expand Down Expand Up @@ -257,7 +260,8 @@ void EvalEmitter::updateGlobalTemporaries() {
if (std::optional<PrimType> T = Ctx.classify(E->getType())) {
TYPE_SWITCH(*T, { *Cached = Ptr.deref<T>().toAPValue(); });
} else {
if (std::optional<APValue> APV = Ptr.toRValue(Ctx))
if (std::optional<APValue> APV =
Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))
*Cached = *APV;
}
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/EvaluationResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ std::optional<APValue> EvaluationResult::toRValue() const {

// We have a pointer and want an RValue.
if (const auto *P = std::get_if<Pointer>(&Value))
return P->toRValue(*Ctx);
return P->toRValue(*Ctx, getSourceType());
else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
return FP->toAPValue();
llvm_unreachable("Unhandled lvalue kind");
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/Interp/EvaluationResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ class EvaluationResult final {

bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;

QualType getSourceType() const {
if (const auto *D =
dyn_cast_if_present<ValueDecl>(Source.dyn_cast<const Decl *>()))
return D->getType();
else if (const auto *E = Source.dyn_cast<const Expr *>())
return E->getType();
return QualType();
}

/// Dump to stderr.
void dump() const;

Expand Down
18 changes: 17 additions & 1 deletion clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
return true;
}

// Reject comparisons to weak pointers.
for (const auto &P : {LHS, RHS}) {
if (P.isZero())
continue;
Expand All @@ -934,6 +935,20 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
}

if (!Pointer::hasSameBase(LHS, RHS)) {
if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
RHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
<< LHS.toDiagnosticString(S.getCtx());
return false;
} else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
LHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
<< RHS.toDiagnosticString(S.getCtx());
return false;
}

S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
return true;
} else {
Expand Down Expand Up @@ -1294,7 +1309,8 @@ inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
S.SeenGlobalTemporaries.push_back(
std::make_pair(P.getDeclDesc()->asExpr(), Temp));

if (std::optional<APValue> APV = P.toRValue(S.getCtx())) {
if (std::optional<APValue> APV =
P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {
*Cached = *APV;
return true;
}
Expand Down
27 changes: 18 additions & 9 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ APValue Pointer::toAPValue() const {

if (isDummy() || isUnknownSizeArray() || Desc->asExpr())
return APValue(Base, CharUnits::Zero(), Path,
/*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
/*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);

// TODO: compute the offset into the object.
CharUnits Offset = CharUnits::Zero();
Expand Down Expand Up @@ -181,7 +181,8 @@ APValue Pointer::toAPValue() const {
// Just invert the order of the elements.
std::reverse(Path.begin(), Path.end());

return APValue(Base, Offset, Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(),
/*IsNullPtr=*/false);
}

void Pointer::print(llvm::raw_ostream &OS) const {
Expand Down Expand Up @@ -339,7 +340,9 @@ bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
A.getFieldDesc()->IsArray;
}

std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
std::optional<APValue> Pointer::toRValue(const Context &Ctx,
QualType ResultType) const {
assert(!ResultType.isNull());
// Method to recursively traverse composites.
std::function<bool(QualType, const Pointer &, APValue &)> Composite;
Composite = [&Composite, &Ctx](QualType Ty, const Pointer &Ptr, APValue &R) {
Expand All @@ -348,7 +351,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {

// Invalid pointers.
if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
(!Ptr.isUnknownSizeArray() && Ptr.isOnePastEnd()))
Ptr.isPastEnd())
return false;

// Primitive values.
Expand Down Expand Up @@ -482,13 +485,19 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
llvm_unreachable("invalid value to return");
};

if (isZero())
return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {}, false,
true);

if (isDummy() || !isLive())
// Invalid to read from.
if (isDummy() || !isLive() || isPastEnd())
return std::nullopt;

// We can return these as rvalues, but we can't deref() them.
if (isZero() || isIntegralPointer())
return toAPValue();

// Just load primitive types.
if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
TYPE_SWITCH(*T, return this->deref<T>().toAPValue());
}

// Return the composite type.
APValue Result;
if (!Composite(getType(), *this, Result))
Expand Down
14 changes: 12 additions & 2 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ class Pointer {
}

/// Converts the pointer to an APValue that is an rvalue.
std::optional<APValue> toRValue(const Context &Ctx) const;
std::optional<APValue> toRValue(const Context &Ctx,
QualType ResultType) const;

/// Offsets a pointer inside an array.
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
Expand Down Expand Up @@ -556,10 +557,18 @@ class Pointer {
if (isUnknownSizeArray())
return false;

return isElementPastEnd() ||
return isElementPastEnd() || isPastEnd() ||
(getSize() == getOffset() && !isZeroSizeArray());
}

/// Checks if the pointer points past the end of the object.
bool isPastEnd() const {
if (isIntegralPointer())
return false;

return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize();
}

/// Checks if the pointer is an out-of-bounds element pointer.
bool isElementPastEnd() const { return Offset == PastEndMark; }

Expand Down Expand Up @@ -629,6 +638,7 @@ class Pointer {
/// Returns the embedded descriptor preceding a field.
InlineDescriptor *getInlineDesc() const {
assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor));
assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize());
return getDescriptor(asBlockPointer().Base);
}

Expand Down
14 changes: 7 additions & 7 deletions clang/lib/AST/JSONNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ void JSONNodeDumper::Visit(const APValue &Value, QualType Ty) {
std::string Str;
llvm::raw_string_ostream OS(Str);
Value.printPretty(OS, Ctx, Ty);
JOS.attribute("value", OS.str());
JOS.attribute("value", Str);
}

void JSONNodeDumper::Visit(const ConceptReference *CR) {
Expand Down Expand Up @@ -802,7 +802,7 @@ void JSONNodeDumper::VisitTemplateSpecializationType(
std::string Str;
llvm::raw_string_ostream OS(Str);
TST->getTemplateName().print(OS, PrintPolicy);
JOS.attribute("templateName", OS.str());
JOS.attribute("templateName", Str);
}

void JSONNodeDumper::VisitInjectedClassNameType(
Expand All @@ -824,7 +824,7 @@ void JSONNodeDumper::VisitElaboratedType(const ElaboratedType *ET) {
std::string Str;
llvm::raw_string_ostream OS(Str);
NNS->print(OS, PrintPolicy, /*ResolveTemplateArgs*/ true);
JOS.attribute("qualifier", OS.str());
JOS.attribute("qualifier", Str);
}
if (const TagDecl *TD = ET->getOwnedTagDecl())
JOS.attribute("ownedTagDecl", createBareDeclRef(TD));
Expand Down Expand Up @@ -1246,7 +1246,7 @@ void JSONNodeDumper::VisitObjCMessageExpr(const ObjCMessageExpr *OME) {
llvm::raw_string_ostream OS(Str);

OME->getSelector().print(OS);
JOS.attribute("selector", OS.str());
JOS.attribute("selector", Str);

switch (OME->getReceiverKind()) {
case ObjCMessageExpr::Instance:
Expand Down Expand Up @@ -1277,7 +1277,7 @@ void JSONNodeDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *OBE) {
llvm::raw_string_ostream OS(Str);

MD->getSelector().print(OS);
JOS.attribute("selector", OS.str());
JOS.attribute("selector", Str);
}
}

Expand All @@ -1286,7 +1286,7 @@ void JSONNodeDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *OSE) {
llvm::raw_string_ostream OS(Str);

OSE->getSelector().print(OS);
JOS.attribute("selector", OS.str());
JOS.attribute("selector", Str);
}

void JSONNodeDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *OPE) {
Expand Down Expand Up @@ -1634,7 +1634,7 @@ void JSONNodeDumper::VisitStringLiteral(const StringLiteral *SL) {
std::string Buffer;
llvm::raw_string_ostream SS(Buffer);
SL->outputString(SS);
JOS.attribute("value", SS.str());
JOS.attribute("value", Buffer);
}
void JSONNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *BLE) {
JOS.attribute("value", BLE->getValue());
Expand Down
73 changes: 56 additions & 17 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,15 @@ class MicrosoftCXXNameMangler {
void mangleFunctionEncoding(GlobalDecl GD, bool ShouldMangle);
void mangleVariableEncoding(const VarDecl *VD);
void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD,
const NonTypeTemplateParmDecl *PD,
QualType TemplateArgType,
StringRef Prefix = "$");
void mangleMemberDataPointerInClassNTTP(const CXXRecordDecl *,
const ValueDecl *);
void mangleMemberFunctionPointer(const CXXRecordDecl *RD,
const CXXMethodDecl *MD,
const NonTypeTemplateParmDecl *PD,
QualType TemplateArgType,
StringRef Prefix = "$");
void mangleFunctionPointer(const FunctionDecl *FD,
const NonTypeTemplateParmDecl *PD,
Expand Down Expand Up @@ -673,12 +677,17 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
}
}

void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
const ValueDecl *VD,
StringRef Prefix) {
void MicrosoftCXXNameMangler::mangleMemberDataPointer(
const CXXRecordDecl *RD, const ValueDecl *VD,
const NonTypeTemplateParmDecl *PD, QualType TemplateArgType,
StringRef Prefix) {
// <member-data-pointer> ::= <integer-literal>
// ::= $F <number> <number>
// ::= $G <number> <number> <number>
//
// <auto-nttp> ::= $ M <type> <integer-literal>
// <auto-nttp> ::= $ M <type> F <name> <number>
// <auto-nttp> ::= $ M <type> G <name> <number> <number>

int64_t FieldOffset;
int64_t VBTableOffset;
Expand Down Expand Up @@ -707,7 +716,18 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
case MSInheritanceModel::Unspecified: Code = 'G'; break;
}

Out << Prefix << Code;
Out << Prefix;

if (VD &&
getASTContext().getLangOpts().isCompatibleWithMSVC(
LangOptions::MSVC2019) &&
PD && PD->getType()->getTypeClass() == Type::Auto &&
!TemplateArgType.isNull()) {
Out << "M";
mangleType(TemplateArgType, SourceRange(), QMM_Drop);
}

Out << Code;

mangleNumber(FieldOffset);

Expand All @@ -728,7 +748,7 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointerInClassNTTP(
// ::= 8 <postfix> @ <unqualified-name> @

if (IM != MSInheritanceModel::Single && IM != MSInheritanceModel::Multiple)
return mangleMemberDataPointer(RD, VD, "");
return mangleMemberDataPointer(RD, VD, nullptr, QualType(), "");

if (!VD) {
Out << 'N';
Expand All @@ -742,14 +762,19 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointerInClassNTTP(
Out << '@';
}

void
MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
const CXXMethodDecl *MD,
StringRef Prefix) {
void MicrosoftCXXNameMangler::mangleMemberFunctionPointer(
const CXXRecordDecl *RD, const CXXMethodDecl *MD,
const NonTypeTemplateParmDecl *PD, QualType TemplateArgType,
StringRef Prefix) {
// <member-function-pointer> ::= $1? <name>
// ::= $H? <name> <number>
// ::= $I? <name> <number> <number>
// ::= $J? <name> <number> <number> <number>
//
// <auto-nttp> ::= $ M <type> 1? <name>
// <auto-nttp> ::= $ M <type> H? <name> <number>
// <auto-nttp> ::= $ M <type> I? <name> <number> <number>
// <auto-nttp> ::= $ M <type> J? <name> <number> <number> <number>

MSInheritanceModel IM = RD->getMSInheritanceModel();

Expand All @@ -767,7 +792,17 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
uint64_t VBTableOffset = 0;
uint64_t VBPtrOffset = 0;
if (MD) {
Out << Prefix << Code << '?';
Out << Prefix;

if (getASTContext().getLangOpts().isCompatibleWithMSVC(
LangOptions::MSVC2019) &&
PD && PD->getType()->getTypeClass() == Type::Auto &&
!TemplateArgType.isNull()) {
Out << "M";
mangleType(TemplateArgType, SourceRange(), QMM_Drop);
}

Out << Code << '?';
if (MD->isVirtual()) {
MicrosoftVTableContext *VTContext =
cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
Expand Down Expand Up @@ -859,7 +894,7 @@ void MicrosoftCXXNameMangler::mangleMemberFunctionPointerInClassNTTP(

if (!MD) {
if (RD->getMSInheritanceModel() != MSInheritanceModel::Single)
return mangleMemberFunctionPointer(RD, MD, "");
return mangleMemberFunctionPointer(RD, MD, nullptr, QualType(), "");

Out << 'N';
return;
Expand Down Expand Up @@ -1732,12 +1767,15 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
if (isa<FieldDecl>(ND) || isa<IndirectFieldDecl>(ND)) {
mangleMemberDataPointer(cast<CXXRecordDecl>(ND->getDeclContext())
->getMostRecentNonInjectedDecl(),
cast<ValueDecl>(ND));
cast<ValueDecl>(ND),
cast<NonTypeTemplateParmDecl>(Parm),
TA.getParamTypeForDecl());
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
if (MD && MD->isInstance()) {
mangleMemberFunctionPointer(
MD->getParent()->getMostRecentNonInjectedDecl(), MD);
MD->getParent()->getMostRecentNonInjectedDecl(), MD,
cast<NonTypeTemplateParmDecl>(Parm), TA.getParamTypeForDecl());
} else {
mangleFunctionPointer(FD, cast<NonTypeTemplateParmDecl>(Parm),
TA.getParamTypeForDecl());
Expand Down Expand Up @@ -1767,12 +1805,12 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
if (MPT->isMemberFunctionPointerType() &&
!isa<FunctionTemplateDecl>(TD)) {
mangleMemberFunctionPointer(RD, nullptr);
mangleMemberFunctionPointer(RD, nullptr, nullptr, QualType());
return;
}
if (MPT->isMemberDataPointer()) {
if (!isa<FunctionTemplateDecl>(TD)) {
mangleMemberDataPointer(RD, nullptr);
mangleMemberDataPointer(RD, nullptr, nullptr, QualType());
return;
}
// nullptr data pointers are always represented with a single field
Expand Down Expand Up @@ -1979,9 +2017,10 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
cast_or_null<CXXMethodDecl>(D));
} else {
if (T->isMemberDataPointerType())
mangleMemberDataPointer(RD, D, "");
mangleMemberDataPointer(RD, D, nullptr, QualType(), "");
else
mangleMemberFunctionPointer(RD, cast_or_null<CXXMethodDecl>(D), "");
mangleMemberFunctionPointer(RD, cast_or_null<CXXMethodDecl>(D), nullptr,
QualType(), "");
}
return;
}
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasQuadwordAtomics = true;
} else if (Feature == "+aix-shared-lib-tls-model-opt") {
HasAIXShLibTLSModelOpt = true;
} else if (Feature == "+longcall") {
UseLongCalls = true;
}
// TODO: Finish this list and add an assert that we've handled them
// all.
Expand Down Expand Up @@ -728,6 +730,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const {
.Case("isa-v31-instructions", IsISA3_1)
.Case("quadword-atomics", HasQuadwordAtomics)
.Case("aix-shared-lib-tls-model-opt", HasAIXShLibTLSModelOpt)
.Case("longcall", UseLongCalls)
.Default(false);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
bool IsISA3_1 = false;
bool HasQuadwordAtomics = false;
bool HasAIXShLibTLSModelOpt = false;
bool UseLongCalls = false;

protected:
std::string ABI;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasCF = true;
} else if (Feature == "+zu") {
HasZU = true;
} else if (Feature == "+branch-hint") {
HasBranchHint = true;
}

X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
Expand Down Expand Up @@ -1292,6 +1294,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("nf", HasNF)
.Case("cf", HasCF)
.Case("zu", HasZU)
.Case("branch-hint", HasBranchHint)
.Default(false);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasCF = false;
bool HasZU = false;
bool HasInlineAsmUseGPR32 = false;
bool HasBranchHint = false;

protected:
llvm::X86::CPUKind CPU = llvm::X86::CK_None;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/BackendConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class BackendConsumer : public ASTConsumer {
void HandleTagDeclDefinition(TagDecl *D) override;
void HandleTagDeclRequiredDefinition(const TagDecl *D) override;
void CompleteTentativeDefinition(VarDecl *D) override;
void CompleteExternalDeclaration(VarDecl *D) override;
void CompleteExternalDeclaration(DeclaratorDecl *D) override;
void AssignInheritanceModel(CXXRecordDecl *RD) override;
void HandleVTable(CXXRecordDecl *RD) override;

Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
Options.MCOptions.Dwarf64 = CodeGenOpts.Dwarf64;
Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments;
Options.MCOptions.Crel = CodeGenOpts.Crel;
Options.MCOptions.X86RelaxRelocations = CodeGenOpts.RelaxELFRelocations;
Options.MCOptions.CompressDebugSections =
CodeGenOpts.getCompressDebugSections();
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5888,12 +5888,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_printf:
case Builtin::BIprintf:
if (getTarget().getTriple().isNVPTX() ||
getTarget().getTriple().isAMDGCN()) {
getTarget().getTriple().isAMDGCN() ||
(getTarget().getTriple().isSPIRV() &&
getTarget().getTriple().getVendor() == Triple::VendorType::AMD)) {
if (getLangOpts().OpenMPIsTargetDevice)
return EmitOpenMPDevicePrintfCallExpr(E);
if (getTarget().getTriple().isNVPTX())
return EmitNVPTXDevicePrintfCallExpr(E);
if (getTarget().getTriple().isAMDGCN() && getLangOpts().HIP)
if ((getTarget().getTriple().isAMDGCN() ||
getTarget().getTriple().isSPIRV()) &&
getLangOpts().HIP)
return EmitAMDGPUDevicePrintfCallExpr(E);
}

Expand Down
29 changes: 28 additions & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5751,8 +5751,35 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
else if (IsMustTail)
else if (IsMustTail) {
if (getTarget().getTriple().isPPC()) {
if (getTarget().getTriple().isOSAIX())
CGM.getDiags().Report(Loc, diag::err_aix_musttail_unsupported);
else if (!getTarget().hasFeature("pcrelative-memops")) {
if (getTarget().hasFeature("longcall"))
CGM.getDiags().Report(Loc, diag::err_ppc_impossible_musttail) << 0;
else if (Call->isIndirectCall())
CGM.getDiags().Report(Loc, diag::err_ppc_impossible_musttail) << 1;
else if (isa_and_nonnull<FunctionDecl>(TargetDecl)) {
if (!cast<FunctionDecl>(TargetDecl)->isDefined())
// The undefined callee may be a forward declaration. Without
// knowning all symbols in the module, we won't know the symbol is
// defined or not. Collect all these symbols for later diagnosing.
CGM.addUndefinedGlobalForTailCall(
{cast<FunctionDecl>(TargetDecl), Loc});
else {
llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(
GlobalDecl(cast<FunctionDecl>(TargetDecl)));
if (llvm::GlobalValue::isWeakForLinker(Linkage) ||
llvm::GlobalValue::isDiscardableIfUnused(Linkage))
CGM.getDiags().Report(Loc, diag::err_ppc_impossible_musttail)
<< 2;
}
}
}
}
Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
}
}

// Add metadata for calls to MSAllocator functions
Expand Down
17 changes: 2 additions & 15 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3141,21 +3141,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
return LV;
}

if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
LValue LV = EmitFunctionDeclLValue(*this, E, FD);

// Emit debuginfo for the function declaration if the target wants to.
if (getContext().getTargetInfo().allowDebugInfoForExternalRef()) {
if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) {
auto *Fn =
cast<llvm::Function>(LV.getPointer(*this)->stripPointerCasts());
if (!Fn->getSubprogram())
DI->EmitFunctionDecl(FD, FD->getLocation(), T, Fn);
}
}

return LV;
}
if (const auto *FD = dyn_cast<FunctionDecl>(ND))
return EmitFunctionDeclLValue(*this, E, FD);

// FIXME: While we're emitting a binding from an enclosing scope, all other
// DeclRefExprs we see should be implicitly treated as if they also refer to
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/CodeGen/CGGPUBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ RValue CodeGenFunction::EmitNVPTXDevicePrintfCallExpr(const CallExpr *E) {
}

RValue CodeGenFunction::EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E) {
assert(getTarget().getTriple().getArch() == llvm::Triple::amdgcn);
assert(getTarget().getTriple().isAMDGCN() ||
(getTarget().getTriple().isSPIRV() &&
getTarget().getTriple().getVendor() == llvm::Triple::AMD));
assert(E->getBuiltinCallee() == Builtin::BIprintf ||
E->getBuiltinCallee() == Builtin::BI__builtin_printf);
assert(E->getNumArgs() >= 1); // printf always has at least one arg.
Expand Down
41 changes: 30 additions & 11 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/IR/Constants.h"
Expand Down Expand Up @@ -8034,6 +8035,21 @@ class MappableExprsHandler {
MapCombinedInfoTy StructBaseCurInfo;
const Decl *D = Data.first;
const ValueDecl *VD = cast_or_null<ValueDecl>(D);
bool HasMapBasePtr = false;
bool HasMapArraySec = false;
if (VD && VD->getType()->isAnyPointerType()) {
for (const auto &M : Data.second) {
HasMapBasePtr = any_of(M, [](const MapInfo &L) {
return isa_and_present<DeclRefExpr>(L.VarRef);
});
HasMapArraySec = any_of(M, [](const MapInfo &L) {
return isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(
L.VarRef);
});
if (HasMapBasePtr && HasMapArraySec)
break;
}
}
for (const auto &M : Data.second) {
for (const MapInfo &L : M) {
assert(!L.Components.empty() &&
Expand All @@ -8050,7 +8066,8 @@ class MappableExprsHandler {
CurInfo, StructBaseCurInfo, PartialStruct,
/*IsFirstComponentList=*/false, L.IsImplicit,
/*GenerateAllInfoForClauses*/ true, L.Mapper, L.ForDeviceAddr, VD,
L.VarRef);
L.VarRef, /*OverlappedElements*/ std::nullopt,
HasMapBasePtr && HasMapArraySec);

// If this entry relates to a device pointer, set the relevant
// declaration and add the 'return pointer' flag.
Expand Down Expand Up @@ -10341,16 +10358,12 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
// Source location for the ident struct
llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());

llvm::Value *OffloadingArgs[] = {
RTLoc,
DeviceID,
PointerNum,
InputInfo.BasePointersArray.emitRawPointer(CGF),
InputInfo.PointersArray.emitRawPointer(CGF),
InputInfo.SizesArray.emitRawPointer(CGF),
MapTypesArray,
MapNamesArray,
InputInfo.MappersArray.emitRawPointer(CGF)};
SmallVector<llvm::Value *, 13> OffloadingArgs(
{RTLoc, DeviceID, PointerNum,
InputInfo.BasePointersArray.emitRawPointer(CGF),
InputInfo.PointersArray.emitRawPointer(CGF),
InputInfo.SizesArray.emitRawPointer(CGF), MapTypesArray, MapNamesArray,
InputInfo.MappersArray.emitRawPointer(CGF)});

// Select the right runtime function call for each standalone
// directive.
Expand Down Expand Up @@ -10439,6 +10452,12 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
llvm_unreachable("Unexpected standalone target data directive.");
break;
}
if (HasNowait) {
OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.Int32Ty));
OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.VoidPtrTy));
OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.Int32Ty));
OffloadingArgs.push_back(llvm::Constant::getNullValue(CGF.VoidPtrTy));
}
CGF.EmitRuntimeCall(
OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), RTLFn),
OffloadingArgs);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CodeGenAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ void BackendConsumer::CompleteTentativeDefinition(VarDecl *D) {
Gen->CompleteTentativeDefinition(D);
}

void BackendConsumer::CompleteExternalDeclaration(VarDecl *D) {
void BackendConsumer::CompleteExternalDeclaration(DeclaratorDecl *D) {
Gen->CompleteExternalDeclaration(D);
}

Expand Down
64 changes: 51 additions & 13 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1394,22 +1394,45 @@ void CodeGenModule::Release() {
// that might affect the DLL storage class or the visibility, and
// before anything that might act on these.
setVisibilityFromDLLStorageClass(LangOpts, getModule());

// Check the tail call symbols are truly undefined.
if (getTriple().isPPC() && !MustTailCallUndefinedGlobals.empty()) {
for (auto &I : MustTailCallUndefinedGlobals) {
if (!I.first->isDefined())
getDiags().Report(I.second, diag::err_ppc_impossible_musttail) << 2;
else {
StringRef MangledName = getMangledName(GlobalDecl(I.first));
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (!Entry || Entry->isWeakForLinker() ||
Entry->isDeclarationForLinker())
getDiags().Report(I.second, diag::err_ppc_impossible_musttail) << 2;
}
}
}
}

void CodeGenModule::EmitOpenCLMetadata() {
// SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the
// opencl.ocl.version named metadata node.
// C++ for OpenCL has a distinct mapping for versions compatibile with OpenCL.
auto Version = LangOpts.getOpenCLCompatibleVersion();
llvm::Metadata *OCLVerElts[] = {
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
Int32Ty, Version / 100)),
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
Int32Ty, (Version % 100) / 10))};
llvm::NamedMDNode *OCLVerMD =
TheModule.getOrInsertNamedMetadata("opencl.ocl.version");
llvm::LLVMContext &Ctx = TheModule.getContext();
OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts));
// C++ for OpenCL has a distinct mapping for versions compatible with OpenCL.
auto CLVersion = LangOpts.getOpenCLCompatibleVersion();

auto EmitVersion = [this](StringRef MDName, int Version) {
llvm::Metadata *OCLVerElts[] = {
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int32Ty, Version / 100)),
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int32Ty, (Version % 100) / 10))};
llvm::NamedMDNode *OCLVerMD = TheModule.getOrInsertNamedMetadata(MDName);
llvm::LLVMContext &Ctx = TheModule.getContext();
OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts));
};

EmitVersion("opencl.ocl.version", CLVersion);
if (LangOpts.OpenCLCPlusPlus) {
// In addition to the OpenCL compatible version, emit the C++ version.
EmitVersion("opencl.cxx.version", LangOpts.OpenCLCPlusPlusVersion);
}
}

void CodeGenModule::EmitBackendOptionsMetadata(
Expand Down Expand Up @@ -5177,8 +5200,11 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
EmitGlobalVarDefinition(D);
}

void CodeGenModule::EmitExternalDeclaration(const VarDecl *D) {
EmitExternalVarDeclaration(D);
void CodeGenModule::EmitExternalDeclaration(const DeclaratorDecl *D) {
if (auto const *V = dyn_cast<const VarDecl>(D))
EmitExternalVarDeclaration(V);
if (auto const *FD = dyn_cast<const FunctionDecl>(D))
EmitExternalFunctionDeclaration(FD);
}

CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
Expand Down Expand Up @@ -5614,6 +5640,18 @@ void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) {
}
}

void CodeGenModule::EmitExternalFunctionDeclaration(const FunctionDecl *FD) {
if (CGDebugInfo *DI = getModuleDebugInfo())
if (getCodeGenOpts().hasReducedDebugInfo()) {
auto *Ty = getTypes().ConvertType(FD->getType());
StringRef MangledName = getMangledName(FD);
auto *Fn = dyn_cast<llvm::Function>(
GetOrCreateLLVMFunction(MangledName, Ty, FD, /* ForVTable */ false));
if (!Fn->getSubprogram())
DI->EmitFunctionDecl(FD, FD->getLocation(), FD->getType(), Fn);
}
}

static bool isVarDeclStrongDefinition(const ASTContext &Context,
CodeGenModule &CGM, const VarDecl *D,
bool NoCommon) {
Expand Down
16 changes: 15 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,14 @@ class CodeGenModule : public CodeGenTypeCache {
typedef std::pair<OrderGlobalInitsOrStermFinalizers, llvm::Function *>
GlobalInitData;

// When a tail call is performed on an "undefined" symbol, on PPC without pc
// relative feature, the tail call is not allowed. In "EmitCall" for such
// tail calls, the "undefined" symbols may be forward declarations, their
// definitions are provided in the module after the callsites. For such tail
// calls, diagnose message should not be emitted.
llvm::SmallSetVector<std::pair<const FunctionDecl *, SourceLocation>, 4>
MustTailCallUndefinedGlobals;

struct GlobalInitPriorityCmp {
bool operator()(const GlobalInitData &LHS,
const GlobalInitData &RHS) const {
Expand Down Expand Up @@ -1338,7 +1346,7 @@ class CodeGenModule : public CodeGenTypeCache {

void EmitTentativeDefinition(const VarDecl *D);

void EmitExternalDeclaration(const VarDecl *D);
void EmitExternalDeclaration(const DeclaratorDecl *D);

void EmitVTable(CXXRecordDecl *Class);

Expand Down Expand Up @@ -1647,6 +1655,11 @@ class CodeGenModule : public CodeGenTypeCache {
return getTriple().isSPIRVLogical();
}

void addUndefinedGlobalForTailCall(
std::pair<const FunctionDecl *, SourceLocation> Global) {
MustTailCallUndefinedGlobals.insert(Global);
}

private:
bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const;

Expand Down Expand Up @@ -1690,6 +1703,7 @@ class CodeGenModule : public CodeGenTypeCache {

void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false);
void EmitExternalVarDeclaration(const VarDecl *D);
void EmitExternalFunctionDeclaration(const FunctionDecl *D);
void EmitAliasDefinition(GlobalDecl GD);
void emitIFuncDefinition(GlobalDecl GD);
void emitCPUDispatchDefinition(GlobalDecl GD);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/ModuleBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ namespace {
Builder->EmitTentativeDefinition(D);
}

void CompleteExternalDeclaration(VarDecl *D) override {
void CompleteExternalDeclaration(DeclaratorDecl *D) override {
Builder->EmitExternalDeclaration(D);
}

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions(
assert(DeviceOffloadingKind == Action::OFK_OpenMP &&
"Only OpenMP offloading kinds are supported.");

CC1Args.push_back("-fcuda-is-device");

if (DriverArgs.hasArg(options::OPT_nogpulib))
return;

Expand Down
94 changes: 19 additions & 75 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2500,6 +2500,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
// arg after parsing the '-I' arg.
bool TakeNextArg = false;

const llvm::Triple &Triple = C.getDefaultToolChain().getTriple();
bool Crel = false, ExperimentalCrel = false;
bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations();
bool UseNoExecStack = false;
const char *MipsTargetFeature = nullptr;
Expand Down Expand Up @@ -2623,6 +2625,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
Value == "-nocompress-debug-sections" ||
Value == "--nocompress-debug-sections") {
CmdArgs.push_back(Value.data());
} else if (Value == "--crel") {
Crel = true;
} else if (Value == "--no-crel") {
Crel = false;
} else if (Value == "--allow-experimental-crel") {
ExperimentalCrel = true;
} else if (Value == "-mrelax-relocations=yes" ||
Value == "--mrelax-relocations=yes") {
UseRelaxRelocations = true;
Expand Down Expand Up @@ -2688,6 +2696,16 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
}
if (ImplicitIt.size())
AddARMImplicitITArgs(Args, CmdArgs, ImplicitIt);
if (Crel) {
if (!ExperimentalCrel)
D.Diag(diag::err_drv_experimental_crel);
if (Triple.isOSBinFormatELF() && !Triple.isMIPS()) {
CmdArgs.push_back("--crel");
} else {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< "-Wa,--crel" << D.getTargetTriple();
}
}
if (!UseRelaxRelocations)
CmdArgs.push_back("-mrelax-relocations=no");
if (UseNoExecStack)
Expand Down Expand Up @@ -5909,81 +5927,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,

TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind());

if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
StringRef CM = A->getValue();
bool Ok = false;
if (Triple.isOSAIX() && CM == "medium")
CM = "large";
if (Triple.isAArch64(64)) {
Ok = CM == "tiny" || CM == "small" || CM == "large";
if (CM == "large" && !Triple.isOSBinFormatMachO() &&
RelocationModel != llvm::Reloc::Static)
D.Diag(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-fno-pic";
} else if (Triple.isLoongArch()) {
if (CM == "extreme" &&
Args.hasFlagNoClaim(options::OPT_fplt, options::OPT_fno_plt, false))
D.Diag(diag::err_drv_argument_not_allowed_with)
<< A->getAsString(Args) << "-fplt";
Ok = CM == "normal" || CM == "medium" || CM == "extreme";
// Convert to LLVM recognizable names.
if (Ok)
CM = llvm::StringSwitch<StringRef>(CM)
.Case("normal", "small")
.Case("extreme", "large")
.Default(CM);
} else if (Triple.isPPC64() || Triple.isOSAIX()) {
Ok = CM == "small" || CM == "medium" || CM == "large";
} else if (Triple.isRISCV()) {
if (CM == "medlow")
CM = "small";
else if (CM == "medany")
CM = "medium";
Ok = CM == "small" || CM == "medium";
} else if (Triple.getArch() == llvm::Triple::x86_64) {
Ok = llvm::is_contained({"small", "kernel", "medium", "large", "tiny"},
CM);
} else if (Triple.isNVPTX() || Triple.isAMDGPU() || Triple.isSPIRV()) {
// NVPTX/AMDGPU/SPIRV 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));
} else {
D.Diag(diag::err_drv_unsupported_option_argument_for_target)
<< A->getSpelling() << CM << TripleStr;
}
}

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

if (Arg *A = Args.getLastArg(options::OPT_mtls_size_EQ)) {
StringRef Value = A->getValue();
Expand Down
102 changes: 102 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,27 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,

addMachineOutlinerArgs(D, Args, CmdArgs, ToolChain.getEffectiveTriple(),
/*IsLTO=*/true, PluginOptPrefix);

for (const Arg *A : Args.filtered(options::OPT_Wa_COMMA)) {
bool Crel = false;
for (StringRef V : A->getValues()) {
if (V == "--crel")
Crel = true;
else if (V == "--no-crel")
Crel = false;
else
continue;
A->claim();
}
if (Crel) {
if (Triple.isOSBinFormatELF() && !Triple.isMIPS()) {
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + "-crel"));
} else {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< "-Wa,--crel" << D.getTargetTriple();
}
}
}
}

/// Adds the '-lcgpu' and '-lmgpu' libraries to the compilation to include the
Expand Down Expand Up @@ -2825,3 +2846,84 @@ void tools::addOffloadCompressArgs(const llvm::opt::ArgList &TCArgs,
CmdArgs.push_back(
TCArgs.MakeArgString(Twine("-compression-level=") + Arg->getValue()));
}

void tools::addMCModel(const Driver &D, const llvm::opt::ArgList &Args,
const llvm::Triple &Triple,
const llvm::Reloc::Model &RelocationModel,
llvm::opt::ArgStringList &CmdArgs) {
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
StringRef CM = A->getValue();
bool Ok = false;
if (Triple.isOSAIX() && CM == "medium")
CM = "large";
if (Triple.isAArch64(64)) {
Ok = CM == "tiny" || CM == "small" || CM == "large";
if (CM == "large" && !Triple.isOSBinFormatMachO() &&
RelocationModel != llvm::Reloc::Static)
D.Diag(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-fno-pic";
} else if (Triple.isLoongArch()) {
if (CM == "extreme" &&
Args.hasFlagNoClaim(options::OPT_fplt, options::OPT_fno_plt, false))
D.Diag(diag::err_drv_argument_not_allowed_with)
<< A->getAsString(Args) << "-fplt";
Ok = CM == "normal" || CM == "medium" || CM == "extreme";
// Convert to LLVM recognizable names.
if (Ok)
CM = llvm::StringSwitch<StringRef>(CM)
.Case("normal", "small")
.Case("extreme", "large")
.Default(CM);
} else if (Triple.isPPC64() || Triple.isOSAIX()) {
Ok = CM == "small" || CM == "medium" || CM == "large";
} else if (Triple.isRISCV()) {
if (CM == "medlow")
CM = "small";
else if (CM == "medany")
CM = "medium";
Ok = CM == "small" || CM == "medium";
} else if (Triple.getArch() == llvm::Triple::x86_64) {
Ok = llvm::is_contained({"small", "kernel", "medium", "large", "tiny"},
CM);
} else if (Triple.isNVPTX() || Triple.isAMDGPU() || Triple.isSPIRV()) {
// NVPTX/AMDGPU/SPIRV 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));
} else {
D.Diag(diag::err_drv_unsupported_option_argument_for_target)
<< A->getSpelling() << CM << Triple.getTriple();
}
}

if (Triple.getArch() == llvm::Triple::x86_64) {
bool IsMediumCM = false;
bool IsLargeCM = false;
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
IsMediumCM = StringRef(A->getValue()) == "medium";
IsLargeCM = StringRef(A->getValue()) == "large";
}
if (Arg *A = Args.getLastArg(options::OPT_mlarge_data_threshold_EQ)) {
if (!IsMediumCM && !IsLargeCM) {
D.Diag(diag::warn_drv_large_data_threshold_invalid_code_model)
<< A->getOption().getRenderName();
} else {
A->render(Args, CmdArgs);
}
} else if (IsMediumCM) {
CmdArgs.push_back("-mlarge-data-threshold=65536");
} else if (IsLargeCM) {
CmdArgs.push_back("-mlarge-data-threshold=0");
}
}
}
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ void addOutlineAtomicsArgs(const Driver &D, const ToolChain &TC,
const llvm::Triple &Triple);
void addOffloadCompressArgs(const llvm::opt::ArgList &TCArgs,
llvm::opt::ArgStringList &CmdArgs);
void addMCModel(const Driver &D, const llvm::opt::ArgList &Args,
const llvm::Triple &Triple,
const llvm::Reloc::Model &RelocationModel,
llvm::opt::ArgStringList &CmdArgs);

} // end namespace tools
} // end namespace driver
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3029,7 +3029,7 @@ void Darwin::addClangCC1ASTargetOptions(
std::string Arg;
llvm::raw_string_ostream OS(Arg);
OS << "-target-sdk-version=" << V;
CC1ASArgs.push_back(Args.MakeArgString(OS.str()));
CC1ASArgs.push_back(Args.MakeArgString(Arg));
};

if (isTargetMacCatalyst()) {
Expand All @@ -3052,7 +3052,7 @@ void Darwin::addClangCC1ASTargetOptions(
std::string Arg;
llvm::raw_string_ostream OS(Arg);
OS << "-darwin-target-variant-sdk-version=" << SDKInfo->getVersion();
CC1ASArgs.push_back(Args.MakeArgString(OS.str()));
CC1ASArgs.push_back(Args.MakeArgString(Arg));
} else if (const auto *MacOStoMacCatalystMapping =
SDKInfo->getVersionMapping(
DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
Expand All @@ -3063,7 +3063,7 @@ void Darwin::addClangCC1ASTargetOptions(
std::string Arg;
llvm::raw_string_ostream OS(Arg);
OS << "-darwin-target-variant-sdk-version=" << *SDKVersion;
CC1ASArgs.push_back(Args.MakeArgString(OS.str()));
CC1ASArgs.push_back(Args.MakeArgString(Arg));
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,11 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
// Add target args, features, etc.
addTargetOptions(Args, CmdArgs);

llvm::Reloc::Model RelocationModel =
std::get<0>(ParsePICArgs(getToolChain(), Args));
// Add MCModel information
addMCModel(D, Args, Triple, RelocationModel, CmdArgs);

// Add Codegen options
addCodegenOptions(Args, CmdArgs);

Expand Down
15 changes: 11 additions & 4 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3222,10 +3222,16 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
if (Trimmed.contains(RawStringTermination))
FormattingOff = false;

if (isClangFormatOff(Trimmed))
bool IsBlockComment = false;

if (isClangFormatOff(Trimmed)) {
FormattingOff = true;
else if (isClangFormatOn(Trimmed))
} else if (isClangFormatOn(Trimmed)) {
FormattingOff = false;
} else if (Trimmed.starts_with("/*")) {
IsBlockComment = true;
Pos = Code.find("*/", SearchFrom + 2);
}

const bool EmptyLineSkipped =
Trimmed.empty() &&
Expand All @@ -3235,9 +3241,10 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,

bool MergeWithNextLine = Trimmed.ends_with("\\");
if (!FormattingOff && !MergeWithNextLine) {
if (tooling::HeaderIncludes::IncludeRegex.match(Line, &Matches)) {
if (!IsBlockComment &&
tooling::HeaderIncludes::IncludeRegex.match(Trimmed, &Matches)) {
StringRef IncludeName = Matches[2];
if (Line.contains("/*") && !Line.contains("*/")) {
if (Trimmed.contains("/*") && !Trimmed.contains("*/")) {
// #include with a start of a block comment, but without the end.
// Need to keep all the lines until the end of the comment together.
// FIXME: This is somehow simplified check that probably does not work
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Frontend/MultiplexConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) {
Consumer->CompleteTentativeDefinition(D);
}

void MultiplexConsumer::CompleteExternalDeclaration(VarDecl *D) {
void MultiplexConsumer::CompleteExternalDeclaration(DeclaratorDecl *D) {
for (auto &Consumer : Consumers)
Consumer->CompleteExternalDeclaration(D);
}
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,9 @@ namespace {
std::string SStr;
llvm::raw_string_ostream S(SStr);
New->printPretty(S, nullptr, PrintingPolicy(LangOpts));
const std::string &Str = S.str();

// If replacement succeeded or warning disabled return with no warning.
if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) {
if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, SStr)) {
ReplacedNodes[Old] = New;
return;
}
Expand Down Expand Up @@ -2581,7 +2580,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
std::string prettyBufS;
llvm::raw_string_ostream prettyBuf(prettyBufS);
Exp->getString()->printPretty(prettyBuf, nullptr, PrintingPolicy(LangOpts));
Preamble += prettyBuf.str();
Preamble += prettyBufS;
Preamble += ",";
Preamble += utostr(Exp->getString()->getByteLength()) + "};\n";

Expand Down Expand Up @@ -4414,7 +4413,7 @@ void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
llvm::raw_string_ostream constructorExprBuf(SStr);
GlobalConstructionExp->printPretty(constructorExprBuf, nullptr,
PrintingPolicy(LangOpts));
globalBuf += constructorExprBuf.str();
globalBuf += SStr;
globalBuf += ";\n";
InsertText(FunLocStart, globalBuf);
GlobalConstructionExp = nullptr;
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Headers/float.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@
# endif
#endif

#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) || \
!defined(__STRICT_ANSI__)
# undef INFINITY
# undef NAN
#endif

/* Characteristics of floating point types, C99 5.2.4.2.2 */

#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
Expand Down Expand Up @@ -155,6 +161,13 @@
# define LDBL_HAS_SUBNORM __LDBL_HAS_DENORM__
#endif

#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) || \
!defined(__STRICT_ANSI__)
/* C23 5.2.5.3.3p29-30 */
# define INFINITY (__builtin_inf())
# define NAN (__builtin_nan(""))
#endif

#ifdef __STDC_WANT_IEC_60559_TYPES_EXT__
# define FLT16_MANT_DIG __FLT16_MANT_DIG__
# define FLT16_DECIMAL_DIG __FLT16_DECIMAL_DIG__
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
Stream << PV.second.getAsString();
});
Stream << " ]";
DB.AddString(Stream.str());
DB.AddString(PlatformAsString);
return DB;
}

Expand Down Expand Up @@ -91,7 +91,7 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
std::string VersionString;
raw_string_ostream OS(VersionString);
OS << Version;
DB.AddString(OS.str());
DB.AddString(VersionString);
return DB;
}

Expand All @@ -102,7 +102,7 @@ operator<<(const clang::DiagnosticBuilder &DB,
raw_string_ostream OS(IFAsString);

OS << LibAttr.getKey() << " [ " << LibAttr.getValue() << " ]";
DB.AddString(OS.str());
DB.AddString(IFAsString);
return DB;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Interpreter/IncrementalParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class IncrementalASTConsumer final : public ASTConsumer {
void CompleteTentativeDefinition(VarDecl *D) override final {
Consumer->CompleteTentativeDefinition(D);
}
void CompleteExternalDeclaration(VarDecl *D) override final {
void CompleteExternalDeclaration(DeclaratorDecl *D) override final {
Consumer->CompleteExternalDeclaration(D);
}
void AssignInheritanceModel(CXXRecordDecl *RD) override final {
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,10 +686,12 @@ class InterfaceKindVisitor
}

private:
// Force cast these types to uint64 to reduce the number of overloads of
// `__clang_Interpreter_SetValueNoAlloc`.
// Force cast these types to the uint that fits the register size. That way we
// reduce the number of overloads of `__clang_Interpreter_SetValueNoAlloc`.
void HandleIntegralOrEnumType(const Type *Ty) {
TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.UnsignedLongLongTy);
uint64_t PtrBits = Ctx.getTypeSize(Ctx.VoidPtrTy);
QualType UIntTy = Ctx.getBitIntType(/*Unsigned=*/true, PtrBits);
TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(UIntTy);
ExprResult CastedExpr =
S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
Expand Down
7 changes: 2 additions & 5 deletions clang/lib/Sema/SemaCodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2117,8 +2117,6 @@ static void AddOverrideResults(ResultBuilder &Results,
// Generates a new CodeCompletionResult by taking this function and
// converting it into an override declaration with only one chunk in the
// final CodeCompletionString as a TypedTextChunk.
std::string OverrideSignature;
llvm::raw_string_ostream OS(OverrideSignature);
CodeCompletionResult CCR(Method, 0);
PrintingPolicy Policy =
getCompletionPrintingPolicy(S.getASTContext(), S.getPreprocessor());
Expand Down Expand Up @@ -3186,7 +3184,6 @@ static void AddTemplateParameterChunks(
else if (const auto *TC = TTP->getTypeConstraint()) {
llvm::raw_string_ostream OS(PlaceholderStr);
TC->print(OS, Policy);
OS.flush();
} else
PlaceholderStr = "class";

Expand Down Expand Up @@ -4025,7 +4022,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
std::string Name;
llvm::raw_string_ostream OS(Name);
FDecl->getDeclName().print(OS, Policy);
Result.AddTextChunk(Result.getAllocator().CopyString(OS.str()));
Result.AddTextChunk(Result.getAllocator().CopyString(Name));
} else {
// Function without a declaration. Just give the return type.
Result.AddResultTypeChunk(Result.getAllocator().CopyString(
Expand Down Expand Up @@ -4343,7 +4340,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
std::string Str;
llvm::raw_string_ostream OS(Str);
NNS->print(OS, Policy);
Builder.AddTextChunk(Results.getAllocator().CopyString(OS.str()));
Builder.AddTextChunk(Results.getAllocator().CopyString(Str));
}
} else if (!InContext->Equals(Overridden->getDeclContext()))
continue;
Expand Down
82 changes: 31 additions & 51 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10818,6 +10818,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
break;
}

// Similar to no_builtin logic above, at this point of the code
// FunctionDecl::isThisDeclarationADefinition() always returns `false`
// because Sema::ActOnStartOfFunctionDef has not been called yet.
if (Context.getTargetInfo().allowDebugInfoForExternalRef() &&
!NewFD->isInvalidDecl() &&
D.getFunctionDefinitionKind() == FunctionDefinitionKind::Declaration)
ExternalDeclarations.push_back(NewFD);

return NewFD;
}

Expand Down Expand Up @@ -11201,6 +11209,10 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) {
// otherwise it is treated as a normal function.
if (TA && !TA->isDefaultVersion())
return false;
// The target_version attribute only causes Multiversioning if this
// declaration is NOT the default version.
if (TVA && TVA->isDefaultVersion())
return false;

if ((TA || TVA) && CheckMultiVersionValue(S, FD)) {
FD->setInvalidDecl();
Expand Down Expand Up @@ -11234,18 +11246,16 @@ static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) {

if (MVKindTo == MultiVersionKind::None &&
(MVKindFrom == MultiVersionKind::TargetVersion ||
MVKindFrom == MultiVersionKind::TargetClones)) {
To->setIsMultiVersion();
MVKindFrom == MultiVersionKind::TargetClones))
To->addAttr(TargetVersionAttr::CreateImplicit(
To->getASTContext(), "default", To->getSourceRange()));
}
}

static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
FunctionDecl *NewFD,
bool &Redeclaration,
NamedDecl *&OldDecl,
LookupResult &Previous) {
static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
FunctionDecl *NewFD,
bool &Redeclaration,
NamedDecl *&OldDecl,
LookupResult &Previous) {
assert(!OldFD->isMultiVersion() && "Unexpected MultiVersion");

// The definitions should be allowed in any order. If we have discovered
Expand All @@ -11256,13 +11266,16 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
const auto *NewTA = NewFD->getAttr<TargetAttr>();
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
const auto *OldTA = OldFD->getAttr<TargetAttr>();
const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>();

// If the old decl is NOT MultiVersioned yet, and we don't cause that
// to change, this is a simple redeclaration.
if ((NewTA && !NewTA->isDefaultVersion() &&
(!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) ||
(NewTVA && !NewTVA->isDefaultVersion() &&
(!OldTVA || OldTVA->getName() == NewTVA->getName())))
if (NewTA && !NewTA->isDefaultVersion() &&
(!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()))
return false;

// The target_version attribute only causes Multiversioning if this
// declaration is NOT the default version.
if (NewTVA && NewTVA->isDefaultVersion())
return false;

// Otherwise, this decl causes MultiVersioning.
Expand All @@ -11279,8 +11292,7 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
}

// If this is 'default', permit the forward declaration.
if ((NewTA && NewTA->isDefaultVersion() && !OldTA) ||
(NewTVA && NewTVA->isDefaultVersion() && !OldTVA)) {
if (NewTA && NewTA->isDefaultVersion() && !OldTA) {
Redeclaration = true;
OldDecl = OldFD;
OldFD->setIsMultiVersion();
Expand Down Expand Up @@ -11312,22 +11324,6 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
}
}

if (NewTVA) {
llvm::SmallVector<StringRef, 8> Feats;
OldTVA->getFeatures(Feats);
llvm::sort(Feats);
llvm::SmallVector<StringRef, 8> NewFeats;
NewTVA->getFeatures(NewFeats);
llvm::sort(NewFeats);

if (Feats == NewFeats) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
NewFD->setInvalidDecl();
return true;
}
}

for (const auto *FD : OldFD->redecls()) {
const auto *CurTA = FD->getAttr<TargetAttr>();
const auto *CurTVA = FD->getAttr<TargetVersionAttr>();
Expand Down Expand Up @@ -11683,24 +11679,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,

FunctionDecl *OldFD = OldDecl->getAsFunction();

if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) {
if (NewTVA || !OldFD->getAttr<TargetVersionAttr>())
return false;
if (!NewFD->getType()->getAs<FunctionProtoType>()) {
// Multiversion declaration doesn't have prototype.
S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto);
NewFD->setInvalidDecl();
} else {
// No "target_version" attribute is equivalent to "default" attribute.
NewFD->addAttr(TargetVersionAttr::CreateImplicit(
S.Context, "default", NewFD->getSourceRange()));
NewFD->setIsMultiVersion();
OldFD->setIsMultiVersion();
OldDecl = OldFD;
Redeclaration = true;
}
return true;
}
if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None)
return false;

// Multiversioned redeclarations aren't allowed to omit the attribute, except
// for target_clones and target_version.
Expand All @@ -11717,8 +11697,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
switch (MVKind) {
case MultiVersionKind::Target:
case MultiVersionKind::TargetVersion:
return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, Redeclaration,
OldDecl, Previous);
return CheckDeclarationCausesMultiVersioning(
S, OldFD, NewFD, Redeclaration, OldDecl, Previous);
case MultiVersionKind::TargetClones:
if (OldFD->isUsed(false)) {
NewFD->setInvalidDecl();
Expand Down
16 changes: 5 additions & 11 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3010,12 +3010,10 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
}

bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
StringRef &AttrStr, bool &isDefault) {
StringRef AttrStr) {
enum FirstParam { Unsupported };
enum SecondParam { None };
enum ThirdParam { Target, TargetClones, TargetVersion };
if (AttrStr.trim() == "default")
isDefault = true;
llvm::SmallVector<StringRef, 8> Features;
AttrStr.split(Features, "+");
for (auto &CurFeature : Features) {
Expand All @@ -3035,16 +3033,12 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation LiteralLoc;
bool isDefault = false;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
S.checkTargetVersionAttr(LiteralLoc, D, Str, isDefault))
S.checkTargetVersionAttr(LiteralLoc, D, Str))
return;
// Do not create default only target_version attribute
if (!isDefault) {
TargetVersionAttr *NewAttr =
::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
D->addAttr(NewAttr);
}
TargetVersionAttr *NewAttr =
::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
D->addAttr(NewAttr);
}

static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3719,8 +3719,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// The C++ standard bans deleting a pointer to a non-object type, which
// effectively bans deletion of "void*". However, most compilers support
// this, so we treat it as a warning unless we're in a SFINAE context.
Diag(StartLoc, diag::ext_delete_void_ptr_operand)
<< Type << Ex.get()->getSourceRange();
// But we still prohibit this since C++26.
Diag(StartLoc, LangOpts.CPlusPlus26 ? diag::err_delete_incomplete
: diag::ext_delete_void_ptr_operand)
<< (LangOpts.CPlusPlus26 ? Pointee : Type)
<< Ex.get()->getSourceRange();
} else if (Pointee->isFunctionType() || Pointee->isVoidType() ||
Pointee->isSizelessType()) {
return ExprError(Diag(StartLoc, diag::err_delete_operand)
Expand All @@ -3729,7 +3732,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// FIXME: This can result in errors if the definition was imported from a
// module but is hidden.
if (!RequireCompleteType(StartLoc, Pointee,
diag::warn_delete_incomplete, Ex.get())) {
LangOpts.CPlusPlus26
? diag::err_delete_incomplete
: diag::warn_delete_incomplete,
Ex.get())) {
if (const RecordType *RT = PointeeElem->getAs<RecordType>())
PointeeRD = cast<CXXRecordDecl>(RT->getDecl());
}
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9811,9 +9811,6 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// C++ [over.best.ics]p4:
// When [...] the constructor [...] is a candidate by
// - [over.match.copy] (in all cases)
// FIXME: The "second phase of [over.match.list] case can also
// theoretically happen here, but it's not clear whether we can
// ever have a parameter of the right type.
if (TD) {
SmallVector<Expr *, 8> TmpInits;
for (Expr *E : Inits)
Expand Down
613 changes: 175 additions & 438 deletions clang/lib/Sema/SemaOpenMP.cpp

Large diffs are not rendered by default.

36 changes: 29 additions & 7 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2743,7 +2743,7 @@ Expr *
buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
TypeAliasTemplateDecl *AliasTemplate,
ArrayRef<DeducedTemplateArgument> DeduceResults,
Expr *IsDeducible) {
unsigned FirstUndeducedParamIdx, Expr *IsDeducible) {
Expr *RC = F->getTemplateParameters()->getRequiresClause();
if (!RC)
return IsDeducible;
Expand Down Expand Up @@ -2803,8 +2803,22 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,

for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
const auto &D = DeduceResults[Index];
if (D.isNull())
if (D.isNull()) { // non-deduced template parameters of f
NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
// Rebuild the template parameter with updated depth and index.
NamedDecl *NewParam = transformTemplateParameter(
SemaRef, F->getDeclContext(), TP, Args,
/*NewIndex=*/FirstUndeducedParamIdx,
getTemplateParameterDepth(TP) + AdjustDepth);
FirstUndeducedParamIdx += 1;
assert(TemplateArgsForBuildingRC[Index].isNull());
TemplateArgsForBuildingRC[Index] = Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
continue;
}
TemplateArgumentLoc Input =
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
TemplateArgumentLoc Output;
Expand All @@ -2820,8 +2834,8 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
MultiLevelTemplateArgumentList ArgsForBuildingRC;
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
// For 2), if the underlying F is instantiated from a member template, we need
// the entire template argument list, as the constraint AST in the
// For 2), if the underlying deduction guide F is nested in a class template,
// we need the entire template argument list, as the constraint AST in the
// require-clause of F remains completely uninstantiated.
//
// For example:
Expand All @@ -2845,7 +2859,13 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
// We add the outer template arguments which is [int] to the multi-level arg
// list to ensure that the occurrence U in `C<U>` will be replaced with int
// during the substitution.
if (F->getInstantiatedFromMemberTemplate()) {
//
// NOTE: The underlying deduction guide F is instantiated -- either from an
// explicitly-written deduction guide member, or from a constructor.
// getInstantiatedFromMemberTemplate() can only handle the former case, so we
// check the DeclContext kind.
if (F->getLexicalDeclContext()->getDeclKind() ==
clang::Decl::ClassTemplateSpecialization) {
auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
F, F->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
Expand Down Expand Up @@ -3063,6 +3083,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
Context.getInjectedTemplateArg(NewParam));
TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
}
unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size();
// ...followed by the template parameters of f that were not deduced
// (including their default template arguments)
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
Expand Down Expand Up @@ -3131,8 +3152,9 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,

Expr *IsDeducible = buildIsDeducibleConstraint(
SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams);
Expr *RequiresClause = buildAssociatedConstraints(
SemaRef, F, AliasTemplate, DeduceResults, IsDeducible);
Expr *RequiresClause =
buildAssociatedConstraints(SemaRef, F, AliasTemplate, DeduceResults,
FirstUndeducedParamIdx, IsDeducible);

auto *FPrimeTemplateParamList = TemplateParameterList::Create(
Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4704,6 +4704,12 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
return;
}

// The noexcept specification could reference any lambda captures. Ensure
// those are added to the LocalInstantiationScope.
LambdaScopeForCallOperatorInstantiationRAII PushLambdaCaptures(
*this, Decl, TemplateArgs, Scope,
/*ShouldAddDeclsFromParentScope=*/false);

SubstExceptionSpec(Decl, Template->getType()->castAs<FunctionProtoType>(),
TemplateArgs);
}
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3194,8 +3194,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
break;
}
case DeclaratorContext::Member: {
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
D.isFunctionDeclarator())
if (D.isStaticMember() || D.isFunctionDeclarator())
break;
bool Cxx = SemaRef.getLangOpts().CPlusPlus;
if (isa<ObjCContainerDecl>(SemaRef.CurContext)) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -12919,7 +12919,7 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
}

ExprResult First;
if (E->getOperator() == OO_Amp)
if (E->getNumArgs() == 1 && E->getOperator() == OO_Amp)
First = getDerived().TransformAddressOfOperand(E->getArg(0));
else
First = getDerived().TransformExpr(E->getArg(0));
Expand Down
211 changes: 168 additions & 43 deletions clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//

#include "InterCheckerAPI.h"
#include "clang/AST/OperationKinds.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/CharInfo.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
Expand All @@ -22,10 +23,13 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
#include <optional>
Expand Down Expand Up @@ -304,6 +308,10 @@ class CStringChecker : public Checker< eval::Call,
// Re-usable checks
ProgramStateRef checkNonNull(CheckerContext &C, ProgramStateRef State,
AnyArgExpr Arg, SVal l) const;
// Check whether the origin region behind \p Element (like the actual array
// region \p Element is from) is initialized.
ProgramStateRef checkInit(CheckerContext &C, ProgramStateRef state,
AnyArgExpr Buffer, SVal Element, SVal Size) const;
ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
AccessKind Access,
Expand All @@ -329,7 +337,7 @@ class CStringChecker : public Checker< eval::Call,
const Stmt *S, StringRef WarningMsg) const;
void emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const;
void emitUninitializedReadBug(CheckerContext &C, ProgramStateRef State,
const Expr *E) const;
const Expr *E, StringRef Msg) const;
ProgramStateRef checkAdditionOverflow(CheckerContext &C,
ProgramStateRef state,
NonLoc left,
Expand All @@ -351,16 +359,16 @@ REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
// Individual checks and utility methods.
//===----------------------------------------------------------------------===//

std::pair<ProgramStateRef , ProgramStateRef >
CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
std::pair<ProgramStateRef, ProgramStateRef>
CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef State, SVal V,
QualType Ty) {
std::optional<DefinedSVal> val = V.getAs<DefinedSVal>();
if (!val)
return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
return std::pair<ProgramStateRef, ProgramStateRef>(State, State);

SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
return state->assume(svalBuilder.evalEQ(state, *val, zero));
return State->assume(svalBuilder.evalEQ(State, *val, zero));
}

ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
Expand Down Expand Up @@ -393,6 +401,149 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
return stateNonNull;
}

static std::optional<NonLoc> getIndex(ProgramStateRef State,
const ElementRegion *ER, CharKind CK) {
SValBuilder &SVB = State->getStateManager().getSValBuilder();
ASTContext &Ctx = SVB.getContext();

if (CK == CharKind::Regular) {
if (ER->getValueType() != Ctx.CharTy)
return {};
return ER->getIndex();
}

if (ER->getValueType() != Ctx.WideCharTy)
return {};

QualType SizeTy = Ctx.getSizeType();
NonLoc WideSize =
SVB.makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(),
SizeTy)
.castAs<NonLoc>();
SVal Offset =
SVB.evalBinOpNN(State, BO_Mul, ER->getIndex(), WideSize, SizeTy);
if (Offset.isUnknown())
return {};
return Offset.castAs<NonLoc>();
}

// Basically 1 -> 1st, 12 -> 12th, etc.
static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx) {
Os << Idx << llvm::getOrdinalSuffix(Idx);
}

ProgramStateRef CStringChecker::checkInit(CheckerContext &C,
ProgramStateRef State,
AnyArgExpr Buffer, SVal Element,
SVal Size) const {

// If a previous check has failed, propagate the failure.
if (!State)
return nullptr;

const MemRegion *R = Element.getAsRegion();
const auto *ER = dyn_cast_or_null<ElementRegion>(R);
if (!ER)
return State;

const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
if (!SuperR)
return State;

// FIXME: We ought to able to check objects as well. Maybe
// UninitializedObjectChecker could help?
if (!SuperR->getValueType()->isArrayType())
return State;

SValBuilder &SVB = C.getSValBuilder();
ASTContext &Ctx = SVB.getContext();

const QualType ElemTy = Ctx.getBaseElementType(SuperR->getValueType());
const NonLoc Zero = SVB.makeZeroArrayIndex();

std::optional<Loc> FirstElementVal =
State->getLValue(ElemTy, Zero, loc::MemRegionVal(SuperR)).getAs<Loc>();
if (!FirstElementVal)
return State;

// Ensure that we wouldn't read uninitialized value.
if (Filter.CheckCStringUninitializedRead &&
State->getSVal(*FirstElementVal).isUndef()) {
llvm::SmallString<258> Buf;
llvm::raw_svector_ostream OS(Buf);
OS << "The first element of the ";
printIdxWithOrdinalSuffix(OS, Buffer.ArgumentIndex + 1);
OS << " argument is undefined";
emitUninitializedReadBug(C, State, Buffer.Expression, OS.str());
return nullptr;
}

// We won't check whether the entire region is fully initialized -- lets just
// check that the first and the last element is. So, onto checking the last
// element:
const QualType IdxTy = SVB.getArrayIndexType();

NonLoc ElemSize =
SVB.makeIntVal(Ctx.getTypeSizeInChars(ElemTy).getQuantity(), IdxTy)
.castAs<NonLoc>();

// FIXME: Check that the size arg to the cstring function is divisible by
// size of the actual element type?

// The type of the argument to the cstring function is either char or wchar,
// but thats not the type of the original array (or memory region).
// Suppose the following:
// int t[5];
// memcpy(dst, t, sizeof(t) / sizeof(t[0]));
// When checking whether t is fully initialized, we see it as char array of
// size sizeof(int)*5. If we check the last element as a character, we read
// the last byte of an integer, which will be undefined. But just because
// that value is undefined, it doesn't mean that the element is uninitialized!
// For this reason, we need to retrieve the actual last element with the
// correct type.

// Divide the size argument to the cstring function by the actual element
// type. This value will be size of the array, or the index to the
// past-the-end element.
std::optional<NonLoc> Offset =
SVB.evalBinOpNN(State, clang::BO_Div, Size.castAs<NonLoc>(), ElemSize,
IdxTy)
.getAs<NonLoc>();

// Retrieve the index of the last element.
const NonLoc One = SVB.makeIntVal(1, IdxTy).castAs<NonLoc>();
SVal LastIdx = SVB.evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);

if (!Offset)
return State;

SVal LastElementVal =
State->getLValue(ElemTy, LastIdx, loc::MemRegionVal(SuperR));
if (!isa<Loc>(LastElementVal))
return State;

if (Filter.CheckCStringUninitializedRead &&
State->getSVal(LastElementVal.castAs<Loc>()).isUndef()) {
const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
// If we can't get emit a sensible last element index, just bail out --
// prefer to emit nothing in favour of emitting garbage quality reports.
if (!IdxInt) {
C.addSink();
return nullptr;
}
llvm::SmallString<258> Buf;
llvm::raw_svector_ostream OS(Buf);
OS << "The last accessed element (at index ";
OS << IdxInt->getExtValue();
OS << ") in the ";
printIdxWithOrdinalSuffix(OS, Buffer.ArgumentIndex + 1);
OS << " argument is undefined";
emitUninitializedReadBug(C, State, Buffer.Expression, OS.str());
return nullptr;
}
return State;
}

// FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor?
ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
ProgramStateRef state,
Expand All @@ -413,38 +564,17 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
if (!ER)
return state;

SValBuilder &svalBuilder = C.getSValBuilder();
ASTContext &Ctx = svalBuilder.getContext();

// Get the index of the accessed element.
NonLoc Idx = ER->getIndex();

if (CK == CharKind::Regular) {
if (ER->getValueType() != Ctx.CharTy)
return state;
} else {
if (ER->getValueType() != Ctx.WideCharTy)
return state;

QualType SizeTy = Ctx.getSizeType();
NonLoc WideSize =
svalBuilder
.makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(),
SizeTy)
.castAs<NonLoc>();
SVal Offset = svalBuilder.evalBinOpNN(state, BO_Mul, Idx, WideSize, SizeTy);
if (Offset.isUnknown())
return state;
Idx = Offset.castAs<NonLoc>();
}
std::optional<NonLoc> Idx = getIndex(state, ER, CK);
if (!Idx)
return state;

// Get the size of the array.
const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
DefinedOrUnknownSVal Size =
getDynamicExtent(state, superReg, C.getSValBuilder());

ProgramStateRef StInBound, StOutBound;
std::tie(StInBound, StOutBound) = state->assumeInBoundDual(Idx, Size);
auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
if (StOutBound && !StInBound) {
// These checks are either enabled by the CString out-of-bounds checker
// explicitly or implicitly by the Malloc checker.
Expand All @@ -459,15 +589,6 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
return nullptr;
}

// Ensure that we wouldn't read uninitialized value.
if (Access == AccessKind::read) {
if (Filter.CheckCStringUninitializedRead &&
StInBound->getSVal(ER).isUndef()) {
emitUninitializedReadBug(C, StInBound, Buffer.Expression);
return nullptr;
}
}

// Array bound check succeeded. From this point forward the array bound
// should always succeed.
return StInBound;
Expand Down Expand Up @@ -502,6 +623,7 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,

// Check if the first byte of the buffer is accessible.
State = CheckLocation(C, State, Buffer, BufStart, Access, CK);

if (!State)
return nullptr;

Expand All @@ -526,6 +648,8 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
SVal BufEnd =
svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
State = CheckLocation(C, State, Buffer, BufEnd, Access, CK);
if (Access == AccessKind::read)
State = checkInit(C, State, Buffer, BufEnd, *Length);

// If the buffer isn't large enough, abort.
if (!State)
Expand Down Expand Up @@ -694,16 +818,17 @@ void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State,

void CStringChecker::emitUninitializedReadBug(CheckerContext &C,
ProgramStateRef State,
const Expr *E) const {
const Expr *E,
StringRef Msg) const {
if (ExplodedNode *N = C.generateErrorNode(State)) {
const char *Msg =
"Bytes string function accesses uninitialized/garbage values";
if (!BT_UninitRead)
BT_UninitRead.reset(new BugType(Filter.CheckNameCStringUninitializedRead,
"Accessing unitialized/garbage values"));

auto Report =
std::make_unique<PathSensitiveBugReport>(*BT_UninitRead, Msg, N);
Report->addNote("Other elements might also be undefined",
Report->getLocation());
Report->addRange(E->getSourceRange());
bugreporter::trackExpressionValue(N, E, *Report);
C.emitReport(std::move(Report));
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/StaticAnalyzer/Core/MemRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,17 @@ bool MemRegion::canPrintPrettyAsExpr() const {
return false;
}

StringRef MemRegion::getKindStr() const {
switch (getKind()) {
#define REGION(Id, Parent) \
case Id##Kind: \
return #Id;
#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
#undef REGION
}
llvm_unreachable("Unkown kind!");
}

void MemRegion::printPretty(raw_ostream &os) const {
assert(canPrintPretty() && "This region cannot be printed pretty.");
os << "'";
Expand Down
10 changes: 10 additions & 0 deletions clang/test/AST/Interp/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1266,3 +1266,13 @@ static_assert(ReturnInStmtExpr() == 1, ""); // both-error {{not an integral cons
// both-note {{in call to}}

#endif

namespace ComparisonAgainstOnePastEnd {
int a, b;
static_assert(&a + 1 == &b, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against pointer '&a + 1' that points past the end of a complete object has unspecified value}}
static_assert(&a == &b + 1, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against pointer '&b + 1' that points past the end of a complete object has unspecified value}}

static_assert(&a + 1 == &b + 1, ""); // both-error {{static assertion failed}}
};
18 changes: 18 additions & 0 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,12 @@ namespace DeclRefs {
constexpr B b;
static_assert(b.a.m == 100, "");
static_assert(b.a.f == 100, "");

constexpr B b2;
static_assert(b2.a.m == 100, "");
static_assert(b2.a.f == 100, "");
static_assert(b2.a.f == 101, ""); // both-error {{failed}} \
// both-note {{evaluates to '100 == 101'}}
}

namespace PointerArith {
Expand Down Expand Up @@ -1482,3 +1488,15 @@ namespace FloatAPValue {
ClassTemplateArgRefTemplate<ClassTemplateArgObj.Arg> ClassTemplateArgRefObj;
}
#endif

namespace LocalWithThisPtrInit {
struct S {
int i;
int *p = &i;
};
constexpr int foo() {
S s{2};
return *s.p;
}
static_assert(foo() == 2, "");
}
27 changes: 27 additions & 0 deletions clang/test/AST/ast-dump-ctad-alias.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,33 @@ Out2<double>::AInner t(1.0);
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'double'
// CHECK-NEXT: | `-ParmVarDecl {{.*}} 'double'

// GH92596
template <typename T0>
struct Out3 {
template<class T1, typename T2>
struct Foo {
// Deduction guide:
// template <typename T1, typename T2, typename V>
// Foo(V, T1) -> Foo<T1, T2>;
template<class V> requires Concept<T0, V> // V in require clause of Foo deduction guide: depth 1, index: 2
Foo(V, T1);
};
};
template<class T3>
using AFoo3 = Out3<int>::Foo<T3, T3>;
AFoo3 afoo3{0, 1};
// Verify occurrence V in the require-clause is transformed (depth: 1 => 0, index: 2 => 1) correctly.

// CHECK: FunctionTemplateDecl {{.*}} implicit <deduction guide for AFoo3>
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 0 T3
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 1 V
// CHECK-NEXT: |-BinaryOperator {{.*}} '<dependent type>' '&&'
// CHECK-NEXT: | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue (no ADL) = 'Concept'
// CHECK-NEXT: | | |-TemplateArgument type 'int'
// CHECK-NEXT: | | | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-0-1'
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1

template <typename... T1>
struct Foo {
Foo(T1...);
Expand Down
119 changes: 96 additions & 23 deletions clang/test/Analysis/bstring_UninitRead.c
Original file line number Diff line number Diff line change
@@ -1,59 +1,132 @@
// RUN: %clang_analyze_cc1 -verify %s \
// RUN: -analyzer-checker=core,alpha.unix.cstring


// This file is generally for the alpha.unix.cstring.UninitializedRead Checker, the reason for putting it into
// the separate file because the checker is break the some existing test cases in bstring.c file , so we don't
// wanna mess up with some existing test case so it's better to create separate file for it, this file also include
// the broken test for the reference in future about the broken tests.

//===----------------------------------------------------------------------===//
// mempcpy() using character array. This is the easiest case, as memcpy
// intepretrs the dst and src buffers as character arrays (regardless of their
// actual type).
//===----------------------------------------------------------------------===//

typedef typeof(sizeof(int)) size_t;

void clang_analyzer_eval(int);

void *memcpy(void *restrict s1, const void *restrict s2, size_t n);

void top(char *dst) {
void memcpy_array_fully_uninit(char *dst) {
char buf[10];
memcpy(dst, buf, 10); // expected-warning{{The first element of the 2nd argument is undefined}}
// expected-note@-1{{Other elements might also be undefined}}
(void)buf;
}

void memcpy_array_partially_uninit(char *dst) {
char buf[10];
memcpy(dst, buf, 10); // expected-warning{{Bytes string function accesses uninitialized/garbage values}}
buf[0] = 'i';
memcpy(dst, buf, 10); // expected-warning{{The last accessed element (at index 9) in the 2nd argument is undefined}}
// expected-note@-1{{Other elements might also be undefined}}
(void)buf;
}

void memcpy_array_only_init_portion(char *dst) {
char buf[10];
buf[0] = 'i';
memcpy(dst, buf, 1);
(void)buf;
}

void memcpy_array_partially_init_error(char *dst) {
char buf[10];
buf[0] = 'i';
memcpy(dst, buf, 2); // expected-warning{{The last accessed element (at index 1) in the 2nd argument is undefined}}
// expected-note@-1{{Other elements might also be undefined}}
(void)buf;
}

// The interesting case here is that the portion we're copying is initialized,
// but not the whole matrix. We need to be careful to extract buf[1], and not
// buf when trying to peel region layers off from the source argument.
void memcpy_array_from_matrix(char *dst) {
char buf[2][2];
buf[1][0] = 'i';
buf[1][1] = 'j';
// FIXME: This is a FP -- we mistakenly retrieve the first element of buf,
// instead of the first element of buf[1]. getLValueElement simply peels off
// another ElementRegion layer, when in this case it really shouldn't.
memcpy(dst, buf[1], 2); // expected-warning{{The first element of the 2nd argument is undefined}}
// expected-note@-1{{Other elements might also be undefined}}
(void)buf;
}

//===----------------------------------------------------------------------===
// mempcpy()
//===----------------------------------------------------------------------===
//===----------------------------------------------------------------------===//
// mempcpy() using non-character arrays.
//===----------------------------------------------------------------------===//

void *mempcpy(void *restrict s1, const void *restrict s2, size_t n);

void mempcpy14() {
void memcpy_int_array_fully_init() {
int src[] = {1, 2, 3, 4};
int dst[5] = {0};
int *p;

p = mempcpy(dst, src, 4 * sizeof(int)); // expected-warning{{Bytes string function accesses uninitialized/garbage values}}
// FIXME: This behaviour is actually surprising and needs to be fixed,
// mempcpy seems to consider the very last byte of the src buffer uninitialized
// and returning undef unfortunately. It should have returned unknown or a conjured value instead.
p = mempcpy(dst, src, 4 * sizeof(int));
clang_analyzer_eval(p == &dst[4]);
}

clang_analyzer_eval(p == &dst[4]); // no-warning (above is fatal)
void memcpy_int_array_fully_init2(int *dest) {
int t[] = {1, 2, 3};
memcpy(dest, t, sizeof(t));
}

//===----------------------------------------------------------------------===//
// mempcpy() using nonarrays.
//===----------------------------------------------------------------------===//

struct st {
int i;
int j;
};


void mempcpy15() {
void mempcpy_struct_partially_uninit() {
struct st s1 = {0};
struct st s2;
struct st *p1;
struct st *p2;

p1 = (&s2) + 1;
p2 = mempcpy(&s2, &s1, sizeof(struct st)); // expected-warning{{Bytes string function accesses uninitialized/garbage values}}
// FIXME: It seems same as mempcpy14() case.

clang_analyzer_eval(p1 == p2); // no-warning (above is fatal)

// FIXME: Maybe ask UninitializedObjectChecker whether s1 is fully
// initialized?
p2 = mempcpy(&s2, &s1, sizeof(struct st));

clang_analyzer_eval(p1 == p2);
}

void mempcpy_struct_fully_uninit() {
struct st s1;
struct st s2;

// FIXME: Maybe ask UninitializedObjectChecker whether s1 is fully
// initialized?
mempcpy(&s2, &s1, sizeof(struct st));
}

// Creduced crash. In this case, an symbolicregion is wrapped in an
// elementregion for the src argument.
void *ga_copy_strings_from_0;
void *memmove();
void alloc();
void ga_copy_strings() {
int i = 0;
for (;; ++i)
memmove(alloc, ((char **)ga_copy_strings_from_0)[i], 1);
}

// Creduced crash. In this case, retrieving the Loc for the first element failed.
char mov_mdhd_language_map[][4] = {};
int ff_mov_lang_to_iso639_code;
char *ff_mov_lang_to_iso639_to;
void ff_mov_lang_to_iso639() {
memcpy(ff_mov_lang_to_iso639_to,
mov_mdhd_language_map[ff_mov_lang_to_iso639_code], 4);
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14

struct A {
template<int N>
static constexpr auto x = N;

template<>
constexpr auto x<1> = 1;

template<>
static constexpr auto x<2> = 2; // expected-warning{{explicit specialization cannot have a storage class}}
};
22 changes: 13 additions & 9 deletions clang/test/CXX/drs/cwg5xx.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// RUN: %clang_cc1 -std=c++98 %s -verify=expected,cxx98-11,cxx98-14,cxx98-17,cxx98 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx98-11,cxx98-14,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++14 %s -verify=expected,cxx98-14,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,since-cxx17,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx23,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++98 %s -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,cxx98 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++14 %s -verify=expected,cxx98-23,cxx98-14,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,cxx98-23,since-cxx17,cxx98-17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx98-23,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++23 %s -verify=expected,cxx98-23,since-cxx23,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx26,since-cxx23,since-cxx20,since-cxx17,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors

#if __cplusplus == 199711L
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
Expand Down Expand Up @@ -901,7 +902,8 @@ namespace cwg573 { // cwg573: no
void *d = reinterpret_cast<void*>(c);
// cxx98-error@-1 {{cast between pointer-to-function and pointer-to-object is an extension}}
void f() { delete a; }
// expected-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
int n = d - a;
// expected-error@-1 {{arithmetic on pointers to void}}
// FIXME: This is ill-formed.
Expand Down Expand Up @@ -1238,11 +1240,13 @@ namespace cwg599 { // cwg599: partial
struct V { operator int*(); operator Fn*(); };
void f(void *p, void (*q)(), S s, T t, U u, V v) {
delete p;
// expected-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
delete q;
// expected-error@-1 {{cannot delete expression of type 'void (*)()'}}
delete s;
// expected-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// cxx98-23-error@-1 {{cannot delete expression with pointer-to-'void' type 'void *'}}
// since-cxx26-error@-2 {{cannot delete pointer to incomplete type 'void'}}
delete t;
// expected-error@-1 {{cannot delete expression of type 'T'}}
// FIXME: This is valid, but is rejected due to a non-conforming GNU
Expand Down
Loading