137 changes: 55 additions & 82 deletions clang/lib/APINotes/APINotesReader.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4534,7 +4534,7 @@ unsigned FunctionDecl::getODRHash() {
}

class ODRHash Hash;
Hash.AddFunctionDecl(this, /*SkipBody=*/shouldSkipCheckingODR());
Hash.AddFunctionDecl(this);
setHasODRHash(true);
ODRHash = Hash.CalculateHash();
return ODRHash;
Expand Down
5 changes: 0 additions & 5 deletions clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1106,11 +1106,6 @@ bool Decl::isFromExplicitGlobalModule() const {
return getOwningModule() && getOwningModule()->isExplicitGlobalModule();
}

bool Decl::shouldSkipCheckingODR() const {
return getASTContext().getLangOpts().SkipODRCheckInGMF &&
isFromExplicitGlobalModule();
}

static Decl::Kind getKind(const Decl *D) { return D->getKind(); }
static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); }

Expand Down
41 changes: 34 additions & 7 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->discard(SubExpr);

std::optional<PrimType> FromT = classify(SubExpr->getType());
std::optional<PrimType> ToT = classifyPrim(CE->getType());
std::optional<PrimType> ToT = classify(CE->getType());
if (!FromT || !ToT)
return false;

Expand Down Expand Up @@ -1251,17 +1251,46 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(
return this->emitConst(Size.getQuantity(), E);
}

if (Kind == UETT_VectorElements) {
if (const auto *VT = E->getTypeOfArgument()->getAs<VectorType>())
return this->emitConst(VT->getNumElements(), E);

// FIXME: Apparently we need to catch the fact that a sizeless vector type
// has been passed and diagnose that (at run time).
assert(E->getTypeOfArgument()->isSizelessVectorType());
}

return false;
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
// 'Base.Member'
const Expr *Base = E->getBase();
const ValueDecl *Member = E->getMemberDecl();

if (DiscardResult)
return this->discard(Base);

// MemberExprs are almost always lvalues, in which case we don't need to
// do the load. But sometimes they aren't.
const auto maybeLoadValue = [&]() -> bool {
if (E->isGLValue())
return true;
if (std::optional<PrimType> T = classify(E))
return this->emitLoadPop(*T, E);
return false;
};

if (const auto *VD = dyn_cast<VarDecl>(Member)) {
// I am almost confident in saying that a var decl must be static
// and therefore registered as a global variable. But this will probably
// turn out to be wrong some time in the future, as always.
if (auto GlobalIndex = P.getGlobal(VD))
return this->emitGetPtrGlobal(*GlobalIndex, E) && maybeLoadValue();
return false;
}

if (Initializing) {
if (!this->delegate(Base))
return false;
Expand All @@ -1271,16 +1300,14 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
}

// Base above gives us a pointer on the stack.
// TODO: Implement non-FieldDecl members.
const ValueDecl *Member = E->getMemberDecl();
if (const auto *FD = dyn_cast<FieldDecl>(Member)) {
const RecordDecl *RD = FD->getParent();
const Record *R = getRecord(RD);
const Record::Field *F = R->getField(FD);
// Leave a pointer to the field on the stack.
if (F->Decl->getType()->isReferenceType())
return this->emitGetFieldPop(PT_Ptr, F->Offset, E);
return this->emitGetPtrField(F->Offset, E);
return this->emitGetFieldPop(PT_Ptr, F->Offset, E) && maybeLoadValue();
return this->emitGetPtrField(F->Offset, E) && maybeLoadValue();
}

return false;
Expand Down Expand Up @@ -1615,7 +1642,7 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
return false;
if (!this->emitLoad(*LT, E))
return false;
if (*LT != *LHSComputationT) {
if (LT != LHSComputationT) {
if (!this->emitCast(*LT, *LHSComputationT, E))
return false;
}
Expand Down Expand Up @@ -1671,7 +1698,7 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
}

// And now cast from LHSComputationT to ResultT.
if (*ResultT != *LHSComputationT) {
if (ResultT != LHSComputationT) {
if (!this->emitCast(*LHSComputationT, *ResultT, E))
return false;
}
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/AST/Interp/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
const Descriptor *Desc = G->block()->getDescriptor();
Pointer GP = getPtrGlobal(GI);

OS << GI << ": " << (void *)G->block() << " ";
OS << GI << ": " << (const void *)G->block() << " ";
{
ColorScope SC(OS, true,
GP.isInitialized()
Expand Down Expand Up @@ -264,3 +264,19 @@ LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
++I;
}
}

LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
{
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_BLUE, true});
OS << "Block " << (const void *)this << "\n";
}
unsigned NPointers = 0;
for (const Pointer *P = Pointers; P; P = P->Next) {
++NPointers;
}
OS << " Pointers: " << NPointers << "\n";
OS << " Dead: " << IsDead << "\n";
OS << " Static: " << IsStatic << "\n";
OS << " Extern: " << IsExtern << "\n";
OS << " Initialized: " << IsInitialized << "\n";
}
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/FunctionPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class FunctionPointer final {

const Function *getFunction() const { return Func; }
bool isZero() const { return !Func; }
bool isValid() const { return Valid; }
bool isWeak() const {
if (!Func || !Valid)
return false;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -2236,6 +2236,10 @@ inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
<< const_cast<Expr *>(E) << E->getSourceRange();
return false;
}

if (!FuncPtr.isValid())
return false;

assert(F);

// Check argument nullability state.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/InterpBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ class Block final {
IsInitialized = false;
}

void dump() const { dump(llvm::errs()); }
void dump(llvm::raw_ostream &OS) const;

protected:
friend class Pointer;
friend class DeadBlock;
Expand Down
118 changes: 118 additions & 0 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,117 @@ static bool interp__builtin_complex(InterpState &S, CodePtr OpPC,
return true;
}

/// __builtin_is_aligned()
/// __builtin_align_up()
/// __builtin_align_down()
/// The first parameter is either an integer or a pointer.
/// The second parameter is the requested alignment as an integer.
static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
unsigned BuiltinOp = Func->getBuiltinID();
unsigned CallSize = callArgSize(S, Call);

PrimType AlignmentT = *S.Ctx.classify(Call->getArg(1));
const APSInt &Alignment = peekToAPSInt(S.Stk, AlignmentT);

if (Alignment < 0 || !Alignment.isPowerOf2()) {
S.FFDiag(Call, diag::note_constexpr_invalid_alignment) << Alignment;
return false;
}
unsigned SrcWidth = S.getCtx().getIntWidth(Call->getArg(0)->getType());
APSInt MaxValue(APInt::getOneBitSet(SrcWidth, SrcWidth - 1));
if (APSInt::compareValues(Alignment, MaxValue) > 0) {
S.FFDiag(Call, diag::note_constexpr_alignment_too_big)
<< MaxValue << Call->getArg(0)->getType() << Alignment;
return false;
}

// The first parameter is either an integer or a pointer (but not a function
// pointer).
PrimType FirstArgT = *S.Ctx.classify(Call->getArg(0));

if (isIntegralType(FirstArgT)) {
const APSInt &Src = peekToAPSInt(S.Stk, FirstArgT, CallSize);
APSInt Align = Alignment.extOrTrunc(Src.getBitWidth());
if (BuiltinOp == Builtin::BI__builtin_align_up) {
APSInt AlignedVal =
APSInt((Src + (Align - 1)) & ~(Align - 1), Src.isUnsigned());
pushInteger(S, AlignedVal, Call->getType());
} else if (BuiltinOp == Builtin::BI__builtin_align_down) {
APSInt AlignedVal = APSInt(Src & ~(Align - 1), Src.isUnsigned());
pushInteger(S, AlignedVal, Call->getType());
} else {
assert(*S.Ctx.classify(Call->getType()) == PT_Bool);
S.Stk.push<Boolean>((Src & (Align - 1)) == 0);
}
return true;
}

assert(FirstArgT == PT_Ptr);
const Pointer &Ptr = S.Stk.peek<Pointer>(CallSize);

unsigned PtrOffset = Ptr.getByteOffset();
PtrOffset = Ptr.getIndex();
CharUnits BaseAlignment =
S.getCtx().getDeclAlign(Ptr.getDeclDesc()->asValueDecl());
CharUnits PtrAlign =
BaseAlignment.alignmentAtOffset(CharUnits::fromQuantity(PtrOffset));

if (BuiltinOp == Builtin::BI__builtin_is_aligned) {
if (PtrAlign.getQuantity() >= Alignment) {
S.Stk.push<Boolean>(true);
return true;
}
// If the alignment is not known to be sufficient, some cases could still
// be aligned at run time. However, if the requested alignment is less or
// equal to the base alignment and the offset is not aligned, we know that
// the run-time value can never be aligned.
if (BaseAlignment.getQuantity() >= Alignment &&
PtrAlign.getQuantity() < Alignment) {
S.Stk.push<Boolean>(false);
return true;
}

S.FFDiag(Call->getArg(0), diag::note_constexpr_alignment_compute)
<< Alignment;
return false;
}

assert(BuiltinOp == Builtin::BI__builtin_align_down ||
BuiltinOp == Builtin::BI__builtin_align_up);

// For align_up/align_down, we can return the same value if the alignment
// is known to be greater or equal to the requested value.
if (PtrAlign.getQuantity() >= Alignment) {
S.Stk.push<Pointer>(Ptr);
return true;
}

// The alignment could be greater than the minimum at run-time, so we cannot
// infer much about the resulting pointer value. One case is possible:
// For `_Alignas(32) char buf[N]; __builtin_align_down(&buf[idx], 32)` we
// can infer the correct index if the requested alignment is smaller than
// the base alignment so we can perform the computation on the offset.
if (BaseAlignment.getQuantity() >= Alignment) {
assert(Alignment.getBitWidth() <= 64 &&
"Cannot handle > 64-bit address-space");
uint64_t Alignment64 = Alignment.getZExtValue();
CharUnits NewOffset =
CharUnits::fromQuantity(BuiltinOp == Builtin::BI__builtin_align_down
? llvm::alignDown(PtrOffset, Alignment64)
: llvm::alignTo(PtrOffset, Alignment64));

S.Stk.push<Pointer>(Ptr.atIndex(NewOffset.getQuantity()));
return true;
}

// Otherwise, we cannot constant-evaluate the result.
S.FFDiag(Call->getArg(0), diag::note_constexpr_alignment_adjust) << Alignment;
return false;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
const InterpFrame *Frame = S.Current;
Expand Down Expand Up @@ -1291,6 +1402,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_is_aligned:
case Builtin::BI__builtin_align_up:
case Builtin::BI__builtin_align_down:
if (!interp__builtin_is_aligned_up_down(S, OpPC, Frame, F, Call))
return false;
break;

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/Interp/InterpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
}

void InterpFrame::describe(llvm::raw_ostream &OS) const {
// We create frames for builtin functions as well, but we can't reliably
// diagnose them. The 'in call to' diagnostics for them add no value to the
// user _and_ it doesn't generally work since the argument types don't always
// match the function prototype. Just ignore them.
if (const auto *F = getFunction(); F && F->isBuiltin())
return;

const FunctionDecl *F = getCallee();
if (const auto *M = dyn_cast<CXXMethodDecl>(F);
M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
Expand Down
5 changes: 1 addition & 4 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,10 @@ class Pointer {

/// Checks if the pointer is null.
bool isZero() const {
if (Offset != 0)
return false;

if (isBlockPointer())
return asBlockPointer().Pointee == nullptr;
assert(isIntegralPointer());
return asIntPointer().Value == 0;
return asIntPointer().Value == 0 && Offset == 0;
}
/// Checks if the pointer is live.
bool isLive() const {
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/Interp/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ void State::addCallStack(unsigned Limit) {
SmallString<128> Buffer;
llvm::raw_svector_ostream Out(Buffer);
F->describe(Out);
addDiag(CallRange.getBegin(), diag::note_constexpr_call_here)
<< Out.str() << CallRange;
if (!Buffer.empty())
addDiag(CallRange.getBegin(), diag::note_constexpr_call_here)
<< Out.str() << CallRange;
}
}
22 changes: 20 additions & 2 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2071,13 +2071,31 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
}

CXXRecordDecl *Lambda = S->getLambdaClass();
ID.AddInteger(Lambda->getODRHash());

for (const auto &Capture : Lambda->captures()) {
ID.AddInteger(Capture.getCaptureKind());
if (Capture.capturesVariable())
VisitDecl(Capture.getCapturedVar());
}

// Profiling the body of the lambda may be dangerous during deserialization.
// So we'd like only to profile the signature here.
ODRHash Hasher;
// FIXME: We can't get the operator call easily by
// `CXXRecordDecl::getLambdaCallOperator()` if we're in deserialization.
// So we have to do something raw here.
for (auto *SubDecl : Lambda->decls()) {
FunctionDecl *Call = nullptr;
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(SubDecl))
Call = FTD->getTemplatedDecl();
else if (auto *FD = dyn_cast<FunctionDecl>(SubDecl))
Call = FD;

if (!Call)
continue;

Hasher.AddFunctionDecl(Call, /*SkipBody=*/true);
}
ID.AddInteger(Hasher.CalculateHash());
}

void
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,11 @@ class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {
isa<CXXStdInitializerListExpr>(E)) {
return;
}
if (auto *Op = dyn_cast<BinaryOperator>(E);
Op && Op->getOpcode() == BO_Cmp) {
// Builtin `<=>` returns a `std::strong_ordering` object.
return;
}

if (auto *InitList = dyn_cast<InitListExpr>(E)) {
if (!InitList->isSemanticForm())
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Basic/Targets/SPIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo {
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
"v96:128-v192:256-v256:256-v512:512-v1024:1024");
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
}

void getTargetDefines(const LangOptions &Opts,
Expand All @@ -276,7 +276,7 @@ class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo {
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
"v96:128-v192:256-v256:256-v512:512-v1024:1024");
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
}

void getTargetDefines(const LangOptions &Opts,
Expand Down Expand Up @@ -336,7 +336,7 @@ class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo {
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
"v96:128-v192:256-v256:256-v512:512-v1024:1024");
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
}

void getTargetDefines(const LangOptions &Opts,
Expand All @@ -357,7 +357,7 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo {
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-"
"v96:128-v192:256-v256:256-v512:512-v1024:1024");
"v96:128-v192:256-v256:256-v512:512-v1024:1024-G1");
}

void getTargetDefines(const LangOptions &Opts,
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18194,7 +18194,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
/*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
Intrinsic::dx_any, ArrayRef<Value *>{Op0}, nullptr, "dx.any");
CGM.getHLSLRuntime().getAnyIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
"hlsl.any");
}
case Builtin::BI__builtin_hlsl_elementwise_clamp: {
Value *OpX = EmitScalarExpr(E->getArg(0));
Expand Down
13 changes: 7 additions & 6 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4694,11 +4694,11 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
AggValueSlot Slot = args.isUsingInAlloca()
? createPlaceholderSlot(*this, type) : CreateAggTemp(type, "agg.tmp");

bool DestroyedInCallee = true, NeedsEHCleanup = true;
bool DestroyedInCallee = true, NeedsCleanup = true;
if (const auto *RD = type->getAsCXXRecordDecl())
DestroyedInCallee = RD->hasNonTrivialDestructor();
else
NeedsEHCleanup = needsEHCleanup(type.isDestructedType());
NeedsCleanup = type.isDestructedType();

if (DestroyedInCallee)
Slot.setExternallyDestructed();
Expand All @@ -4707,14 +4707,15 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
RValue RV = Slot.asRValue();
args.add(RV, type);

if (DestroyedInCallee && NeedsEHCleanup) {
if (DestroyedInCallee && NeedsCleanup) {
// Create a no-op GEP between the placeholder and the cleanup so we can
// RAUW it successfully. It also serves as a marker of the first
// instruction where the cleanup is active.
pushFullExprCleanup<DestroyUnpassedArg>(EHCleanup, Slot.getAddress(),
type);
pushFullExprCleanup<DestroyUnpassedArg>(NormalAndEHCleanup,
Slot.getAddress(), type);
// This unreachable is a temporary marker which will be removed later.
llvm::Instruction *IsActive = Builder.CreateUnreachable();
llvm::Instruction *IsActive =
Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
args.addArgCleanupDeactivation(EHStack.stable_begin(), IsActive);
}
return;
Expand Down
37 changes: 23 additions & 14 deletions clang/lib/CodeGen/CGCleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,12 +634,19 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
/// Pops a cleanup block. If the block includes a normal cleanup, the
/// current insertion point is threaded through the cleanup, as are
/// any branch fixups on the cleanup.
void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough,
bool ForDeactivation) {
assert(!EHStack.empty() && "cleanup stack is empty!");
assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!");
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups());

// If we are deactivating a normal cleanup, we need to pretend that the
// fallthrough is unreachable. We restore this IP before returning.
CGBuilderTy::InsertPoint NormalDeactivateOrigIP;
if (ForDeactivation && (Scope.isNormalCleanup() || !getLangOpts().EHAsynch)) {
NormalDeactivateOrigIP = Builder.saveAndClearIP();
}
// Remember activation information.
bool IsActive = Scope.isActive();
Address NormalActiveFlag =
Expand Down Expand Up @@ -729,6 +736,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EHStack.popCleanup(); // safe because there are no fixups
assert(EHStack.getNumBranchFixups() == 0 ||
EHStack.hasNormalCleanups());
if (NormalDeactivateOrigIP.isSet())
Builder.restoreIP(NormalDeactivateOrigIP);
return;
}

Expand Down Expand Up @@ -765,9 +774,16 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
if (!RequiresNormalCleanup) {
// Mark CPP scope end for passed-by-value Arg temp
// per Windows ABI which is "normally" Cleanup in callee
if (IsEHa && getInvokeDest() && Builder.GetInsertBlock()) {
if (Personality.isMSVCXXPersonality())
if (IsEHa && getInvokeDest()) {
// If we are deactivating a normal cleanup then we don't have a
// fallthrough. Restore original IP to emit CPP scope ends in the correct
// block.
if (NormalDeactivateOrigIP.isSet())
Builder.restoreIP(NormalDeactivateOrigIP);
if (Personality.isMSVCXXPersonality() && Builder.GetInsertBlock())
EmitSehCppScopeEnd();
if (NormalDeactivateOrigIP.isSet())
NormalDeactivateOrigIP = Builder.saveAndClearIP();
}
destroyOptimisticNormalEntry(*this, Scope);
Scope.MarkEmitted();
Expand Down Expand Up @@ -992,6 +1008,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}
}

if (NormalDeactivateOrigIP.isSet())
Builder.restoreIP(NormalDeactivateOrigIP);
assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0);

// Emit the EH cleanup if required.
Expand Down Expand Up @@ -1281,17 +1299,8 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C,
// to the current RunCleanupsScope.
if (C == EHStack.stable_begin() &&
CurrentCleanupScopeDepth.strictlyEncloses(C)) {
// Per comment below, checking EHAsynch is not really necessary
// it's there to assure zero-impact w/o EHAsynch option
if (!Scope.isNormalCleanup() && getLangOpts().EHAsynch) {
PopCleanupBlock();
} else {
// If it's a normal cleanup, we need to pretend that the
// fallthrough is unreachable.
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
PopCleanupBlock();
Builder.restoreIP(SavedIP);
}
PopCleanupBlock(/*FallthroughIsBranchThrough=*/false,
/*ForDeactivation=*/true);
return;
}

Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2216,8 +2216,11 @@ void CodeGenFunction::pushDestroyAndDeferDeactivation(
void CodeGenFunction::pushDestroyAndDeferDeactivation(
CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray) {
pushCleanupAndDeferDeactivation<DestroyObject>(
cleanupKind, addr, type, destroyer, useEHCleanupForArray);
llvm::Instruction *DominatingIP =
Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
pushDestroy(cleanupKind, addr, type, destroyer, useEHCleanupForArray);
DeferredDeactivationCleanupStack.push_back(
{EHStack.stable_begin(), DominatingIP});
}

void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class CGHLSLRuntime {
//===----------------------------------------------------------------------===//

GENERATE_HLSL_INTRINSIC_FUNCTION(All, all)
GENERATE_HLSL_INTRINSIC_FUNCTION(Any, any)
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)

//===----------------------------------------------------------------------===//
Expand Down
84 changes: 44 additions & 40 deletions clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ namespace {
/// contains enough information to determine where the runs break. Microsoft
/// and Itanium follow different rules and use different codepaths.
/// * It is desired that, when possible, bitfields use the appropriate iN type
/// when lowered to llvm types. For example unsigned x : 24 gets lowered to
/// when lowered to llvm types. For example unsigned x : 24 gets lowered to
/// i24. This isn't always possible because i24 has storage size of 32 bit
/// and if it is possible to use that extra byte of padding we must use
/// [i8 x 3] instead of i24. The function clipTailPadding does this.
/// and if it is possible to use that extra byte of padding we must use [i8 x
/// 3] instead of i24. This is computed when accumulating bitfields in
/// accumulateBitfields.
/// C++ examples that require clipping:
/// struct { int a : 24; char b; }; // a must be clipped, b goes at offset 3
/// struct A { int a : 24; ~A(); }; // a must be clipped because:
Expand All @@ -62,11 +63,7 @@ namespace {
/// that the tail padding is not used in the complete class.) However,
/// because LLVM reads from the complete type it can generate incorrect code
/// if we do not clip the tail padding off of the bitfield in the complete
/// layout. This introduces a somewhat awkward extra unnecessary clip stage.
/// The location of the clip is stored internally as a sentinel of type
/// SCISSOR. If LLVM were updated to read base types (which it probably
/// should because locations of things such as VBases are bogus in the llvm
/// type anyway) then we could eliminate the SCISSOR.
/// layout.
/// * Itanium allows nearly empty primary virtual bases. These bases don't get
/// get their own storage because they're laid out as part of another base
/// or at the beginning of the structure. Determining if a VBase actually
Expand Down Expand Up @@ -200,9 +197,7 @@ struct CGRecordLowering {
const CXXRecordDecl *Query) const;
void calculateZeroInit();
CharUnits calculateTailClippingOffset(bool isNonVirtualBaseType) const;
/// Lowers bitfield storage types to I8 arrays for bitfields with tail
/// padding that is or can potentially be used.
void clipTailPadding();
void checkBitfieldClipping() const;
/// Determines if we need a packed llvm struct.
void determinePacked(bool NVBaseType);
/// Inserts padding everywhere it's needed.
Expand Down Expand Up @@ -305,7 +300,7 @@ void CGRecordLowering::lower(bool NVBaseType) {
}
llvm::stable_sort(Members);
Members.push_back(StorageInfo(Size, getIntNType(8)));
clipTailPadding();
checkBitfieldClipping();
determinePacked(NVBaseType);
insertPadding();
Members.pop_back();
Expand Down Expand Up @@ -531,6 +526,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// available padding characters.
RecordDecl::field_iterator BestEnd = Begin;
CharUnits BestEndOffset;
bool BestClipped; // Whether the representation must be in a byte array.

for (;;) {
// AtAlignedBoundary is true iff Field is the (potential) start of a new
Expand Down Expand Up @@ -593,10 +589,9 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// this is the best seen so far.
BestEnd = Field;
BestEndOffset = BeginOffset + AccessSize;
if (Types.getCodeGenOpts().FineGrainedBitfieldAccesses)
// Fine-grained access, so no merging of spans.
InstallBest = true;
else if (!BitSizeSinceBegin)
// Assume clipped until proven not below.
BestClipped = true;
if (!BitSizeSinceBegin)
// A zero-sized initial span -- this will install nothing and reset
// for another.
InstallBest = true;
Expand Down Expand Up @@ -624,6 +619,12 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// The access unit is not at a naturally aligned offset within the
// structure.
InstallBest = true;

if (InstallBest && BestEnd == Field)
// We're installing the first span, whose clipping was presumed
// above. Compute it correctly.
if (getSize(Type) == AccessSize)
BestClipped = false;
}

if (!InstallBest) {
Expand Down Expand Up @@ -656,11 +657,15 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// access unit.
BestEndOffset = BeginOffset + TypeSize;
BestEnd = Field;
BestClipped = false;
}

if (Barrier)
// The next field is a barrier that we cannot merge across.
InstallBest = true;
else if (Types.getCodeGenOpts().FineGrainedBitfieldAccesses)
// Fine-grained access, so no merging of spans.
InstallBest = true;
else
// Otherwise, we're not installing. Update the bit size
// of the current span to go all the way to LimitOffset, which is
Expand All @@ -679,7 +684,17 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
// Add the storage member for the access unit to the record. The
// bitfields get the offset of their storage but come afterward and
// remain there after a stable sort.
llvm::Type *Type = getIntNType(Context.toBits(AccessSize));
llvm::Type *Type;
if (BestClipped) {
assert(getSize(getIntNType(Context.toBits(AccessSize))) >
AccessSize &&
"Clipped access need not be clipped");
Type = getByteArrayType(AccessSize);
} else {
Type = getIntNType(Context.toBits(AccessSize));
assert(getSize(Type) == AccessSize &&
"Unclipped access must be clipped");
}
Members.push_back(StorageInfo(BeginOffset, Type));
for (; Begin != BestEnd; ++Begin)
if (!Begin->isZeroLengthBitField(Context))
Expand Down Expand Up @@ -934,32 +949,21 @@ void CGRecordLowering::calculateZeroInit() {
}
}

void CGRecordLowering::clipTailPadding() {
std::vector<MemberInfo>::iterator Prior = Members.begin();
CharUnits Tail = getSize(Prior->Data);
for (std::vector<MemberInfo>::iterator Member = Prior + 1,
MemberEnd = Members.end();
Member != MemberEnd; ++Member) {
// Verify accumulateBitfields computed the correct storage representations.
void CGRecordLowering::checkBitfieldClipping() const {
#ifndef NDEBUG
auto Tail = CharUnits::Zero();
for (const auto &M : Members) {
// Only members with data and the scissor can cut into tail padding.
if (!Member->Data && Member->Kind != MemberInfo::Scissor)
if (!M.Data && M.Kind != MemberInfo::Scissor)
continue;
if (Member->Offset < Tail) {
assert(Prior->Kind == MemberInfo::Field &&
"Only storage fields have tail padding!");
if (!Prior->FD || Prior->FD->isBitField())
Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo(
cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8)));
else {
assert(Prior->FD->hasAttr<NoUniqueAddressAttr>() &&
"should not have reused this field's tail padding");
Prior->Data = getByteArrayType(
Context.getTypeInfoDataSizeInChars(Prior->FD->getType()).Width);
}
}
if (Member->Data)
Prior = Member;
Tail = Prior->Offset + getSize(Prior->Data);

assert(M.Offset >= Tail && "Bitfield access unit is not clipped");
Tail = M.Offset;
if (M.Data)
Tail += getSize(M.Data);
}
#endif
}

void CGRecordLowering::determinePacked(bool NVBaseType) {
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,8 @@ class CodeGenFunction : public CodeGenTypeCache {

/// PopCleanupBlock - Will pop the cleanup entry on the stack and
/// process all branch fixups.
void PopCleanupBlock(bool FallThroughIsBranchThrough = false);
void PopCleanupBlock(bool FallThroughIsBranchThrough = false,
bool ForDeactivation = false);

/// DeactivateCleanupBlock - Deactivates the given cleanup block.
/// The block cannot be reactivated. Pops it if it's the top of the
Expand Down
17 changes: 14 additions & 3 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3952,9 +3952,20 @@ bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
// behavior may break ABI compatibility of the current unit.
if (const Module *M = F->getOwningModule();
M && M->getTopLevelModule()->isNamedModule() &&
getContext().getCurrentNamedModule() != M->getTopLevelModule() &&
!F->hasAttr<AlwaysInlineAttr>())
return false;
getContext().getCurrentNamedModule() != M->getTopLevelModule()) {
// There are practices to mark template member function as always-inline
// and mark the template as extern explicit instantiation but not give
// the definition for member function. So we have to emit the function
// from explicitly instantiation with always-inline.
//
// See https://github.com/llvm/llvm-project/issues/86893 for details.
//
// TODO: Maybe it is better to give it a warning if we call a non-inline
// function from other module units which is marked as always-inline.
if (!F->isTemplateInstantiation() || !F->hasAttr<AlwaysInlineAttr>()) {
return false;
}
}

if (F->hasAttr<NoInlineAttr>())
return false;
Expand Down
28 changes: 20 additions & 8 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,14 @@ static bool addExceptionArgs(const ArgList &Args, types::ID InputType,
bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
false);

bool EHa = Args.hasFlag(options::OPT_fasync_exceptions,
options::OPT_fno_async_exceptions, false);
if (EHa) {
CmdArgs.push_back("-fasync-exceptions");
EH = true;
// Async exceptions are Windows MSVC only.
if (Triple.isWindowsMSVCEnvironment()) {
bool EHa = Args.hasFlag(options::OPT_fasync_exceptions,
options::OPT_fno_async_exceptions, false);
if (EHa) {
CmdArgs.push_back("-fasync-exceptions");
EH = true;
}
}

// Obj-C exceptions are enabled by default, regardless of -fexceptions. This
Expand Down Expand Up @@ -8102,7 +8105,8 @@ struct EHFlags {
/// The 'a' modifier is unimplemented and fundamentally hard in LLVM IR.
/// - c: Assume that extern "C" functions are implicitly nounwind.
/// The default is /EHs-c-, meaning cleanups are disabled.
static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args,
bool isWindowsMSVC) {
EHFlags EH;

std::vector<std::string> EHArgs =
Expand All @@ -8112,8 +8116,15 @@ static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
switch (EHVal[I]) {
case 'a':
EH.Asynch = maybeConsumeDash(EHVal, I);
if (EH.Asynch)
if (EH.Asynch) {
// Async exceptions are Windows MSVC only.
if (!isWindowsMSVC) {
EH.Asynch = false;
D.Diag(clang::diag::warn_drv_unused_argument) << "/EHa" << EHVal;
continue;
}
EH.Synch = false;
}
continue;
case 'c':
EH.NoUnwindC = maybeConsumeDash(EHVal, I);
Expand Down Expand Up @@ -8177,7 +8188,8 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,

const Driver &D = getToolChain().getDriver();

EHFlags EH = parseClangCLEHFlags(D, Args);
bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment();
EHFlags EH = parseClangCLEHFlags(D, Args, IsWindowsMSVC);
if (!isNVPTX && (EH.Synch || EH.Asynch)) {
if (types::isCXX(InputType))
CmdArgs.push_back("-fcxx-exceptions");
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Index/USRGeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,13 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
Out << '>';
}

QualType CanonicalType = D->getType().getCanonicalType();
// Mangle in type information for the arguments.
for (auto *PD : D->parameters()) {
Out << '#';
VisitType(PD->getType());
if (const auto *FPT = CanonicalType->getAs<FunctionProtoType>()) {
for (QualType PT : FPT->param_types()) {
Out << '#';
VisitType(PT);
}
}
if (D->isVariadic())
Out << '.';
Expand Down
4 changes: 0 additions & 4 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2380,10 +2380,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
if (getLangOpts().CPlusPlus23) {
auto &LastRecord = Actions.ExprEvalContexts.back();
LastRecord.InLifetimeExtendingContext = true;

// Materialize non-`cv void` prvalue temporaries in discarded
// expressions. These materialized temporaries may be lifetime-extented.
LastRecord.InMaterializeTemporaryObjectContext = true;
}

if (getLangOpts().OpenMP)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
Core
Demangle
FrontendHLSL
FrontendOpenMP
MC
Expand Down
44 changes: 33 additions & 11 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/IR/Assumptions.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/Error.h"
Expand Down Expand Up @@ -1983,6 +1984,36 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL));
}

// Mark alias/ifunc target as used. Due to name mangling, we look up the
// demangled name ignoring parameters (not supported by microsoftDemangle
// https://github.com/llvm/llvm-project/issues/88825). This should handle the
// majority of use cases while leaving namespace scope names unmarked.
static void markUsedForAliasOrIfunc(Sema &S, Decl *D, const ParsedAttr &AL,
StringRef Str) {
std::unique_ptr<char, llvm::FreeDeleter> Demangled;
if (S.getASTContext().getCXXABIKind() != TargetCXXABI::Microsoft)
Demangled.reset(llvm::itaniumDemangle(Str, /*ParseParams=*/false));
std::unique_ptr<MangleContext> MC(S.Context.createMangleContext());
SmallString<256> Name;

const DeclarationNameInfo Target(
&S.Context.Idents.get(Demangled ? Demangled.get() : Str), AL.getLoc());
LookupResult LR(S, Target, Sema::LookupOrdinaryName);
if (S.LookupName(LR, S.TUScope)) {
for (NamedDecl *ND : LR) {
if (MC->shouldMangleDeclName(ND)) {
llvm::raw_svector_ostream Out(Name);
Name.clear();
MC->mangleName(GlobalDecl(ND), Out);
} else {
Name = ND->getIdentifier()->getName();
}
if (Name == Str)
ND->markUsed(S.Context);
}
}
}

static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
Expand All @@ -1995,6 +2026,7 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}

markUsedForAliasOrIfunc(S, D, AL, Str);
D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
}

Expand Down Expand Up @@ -2029,17 +2061,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}

// Mark target used to prevent unneeded-internal-declaration warnings.
if (!S.LangOpts.CPlusPlus) {
// FIXME: demangle Str for C++, as the attribute refers to the mangled
// linkage name, not the pre-mangled identifier.
const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc());
LookupResult LR(S, target, Sema::LookupOrdinaryName);
if (S.LookupQualifiedName(LR, S.getCurLexicalContext()))
for (NamedDecl *ND : LR)
ND->markUsed(S.Context);
}

markUsedForAliasOrIfunc(S, D, AL, Str);
D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
}

Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6314,7 +6314,6 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
// Pass down lifetime extending flag, and collect temporaries in
// CreateMaterializeTemporaryExpr when we rewrite the call argument.
keepInLifetimeExtendingContext();
keepInMaterializeTemporaryObjectContext();
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
ExprResult Res;
runWithSufficientStackSpace(CallLoc, [&] {
Expand Down Expand Up @@ -7740,7 +7739,8 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
}

if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl))
if (Method->isImplicitObjectMemberFunction())
if (!isa<RequiresExprBodyDecl>(CurContext) &&
Method->isImplicitObjectMemberFunction())
return ExprError(Diag(LParenLoc, diag::err_member_call_without_object)
<< Fn->getSourceRange() << 0);

Expand Down Expand Up @@ -18679,9 +18679,9 @@ void Sema::PopExpressionEvaluationContext() {
// Append the collected materialized temporaries into previous context before
// exit if the previous also is a lifetime extending context.
auto &PrevRecord = ExprEvalContexts[ExprEvalContexts.size() - 2];
if (getLangOpts().CPlusPlus23 && isInLifetimeExtendingContext() &&
PrevRecord.InLifetimeExtendingContext && !ExprEvalContexts.empty()) {
auto &PrevRecord = ExprEvalContexts[ExprEvalContexts.size() - 2];
if (getLangOpts().CPlusPlus23 && Rec.InLifetimeExtendingContext &&
PrevRecord.InLifetimeExtendingContext &&
!Rec.ForRangeLifetimeExtendTemps.empty()) {
PrevRecord.ForRangeLifetimeExtendTemps.append(
Rec.ForRangeLifetimeExtendTemps);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8429,7 +8429,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// unnecessary temporary objects. If we skip this step, IR generation is
// able to synthesize the storage for itself in the aggregate case, and
// adding the extra node to the AST is just clutter.
if (isInMaterializeTemporaryObjectContext() && getLangOpts().CPlusPlus17 &&
if (isInLifetimeExtendingContext() && getLangOpts().CPlusPlus17 &&
E->isPRValue() && !E->getType()->isVoidType()) {
ExprResult Res = TemporaryMaterializationConversion(E);
if (Res.isInvalid())
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14395,9 +14395,16 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
ArrayRef<Expr *> ArgsArray(Args, NumArgs);

if (Input->isTypeDependent()) {
ExprValueKind VK = ExprValueKind::VK_PRValue;
// [C++26][expr.unary.op][expr.pre.incr]
// The * operator yields an lvalue of type
// The pre/post increment operators yied an lvalue.
if (Opc == UO_PreDec || Opc == UO_PreInc || Opc == UO_Deref)
VK = VK_LValue;

if (Fns.empty())
return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy,
VK_PRValue, OK_Ordinary, OpLoc, false,
return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy, VK,
OK_Ordinary, OpLoc, false,
CurFPFeatureOverrides());

CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
Expand All @@ -14406,7 +14413,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
if (Fn.isInvalid())
return ExprError();
return CXXOperatorCallExpr::Create(Context, Op, Fn.get(), ArgsArray,
Context.DependentTy, VK_PRValue, OpLoc,
Context.DependentTy, VK, OpLoc,
CurFPFeatureOverrides());
}

Expand Down
1 change: 0 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5483,7 +5483,6 @@ void Sema::InstantiateVariableInitializer(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);

keepInLifetimeExtendingContext();
keepInMaterializeTemporaryObjectContext();
// Instantiate the initializer.
ExprResult Init;

Expand Down
5 changes: 0 additions & 5 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -4177,7 +4177,6 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
getSema(), EnterExpressionEvaluationContext::InitList,
Construct->isListInitialization());

getSema().keepInLifetimeExtendingContext();
getSema().keepInLifetimeExtendingContext();
SmallVector<Expr*, 8> NewArgs;
bool ArgChanged = false;
Expand Down Expand Up @@ -8752,10 +8751,6 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
if (getSema().getLangOpts().CPlusPlus23) {
auto &LastRecord = getSema().ExprEvalContexts.back();
LastRecord.InLifetimeExtendingContext = true;

// Materialize non-`cv void` prvalue temporaries in discarded
// expressions. These materialized temporaries may be lifetime-extented.
LastRecord.InMaterializeTemporaryObjectContext = true;
}
StmtResult Init =
S->getInit() ? getDerived().TransformStmt(S->getInit()) : StmtResult();
Expand Down
89 changes: 38 additions & 51 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,10 +915,9 @@ ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
using namespace llvm::support;

SelectorTable &SelTable = Reader.getContext().Selectors;
unsigned N =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
unsigned N = endian::readNext<uint16_t, llvm::endianness::little>(d);
const IdentifierInfo *FirstII = Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d));
F, endian::readNext<uint32_t, llvm::endianness::little>(d));
if (N == 0)
return SelTable.getNullarySelector(FirstII);
else if (N == 1)
Expand All @@ -928,7 +927,7 @@ ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
Args.push_back(FirstII);
for (unsigned I = 1; I != N; ++I)
Args.push_back(Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)));
F, endian::readNext<uint32_t, llvm::endianness::little>(d)));

return SelTable.getSelector(N, Args.data());
}
Expand All @@ -941,11 +940,11 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
data_type Result;

Result.ID = Reader.getGlobalSelectorID(
F, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d));
F, endian::readNext<uint32_t, llvm::endianness::little>(d));
unsigned FullInstanceBits =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint16_t, llvm::endianness::little>(d);
unsigned FullFactoryBits =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint16_t, llvm::endianness::little>(d);
Result.InstanceBits = FullInstanceBits & 0x3;
Result.InstanceHasMoreThanOneDecl = (FullInstanceBits >> 2) & 0x1;
Result.FactoryBits = FullFactoryBits & 0x3;
Expand All @@ -956,16 +955,14 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
// Load instance methods
for (unsigned I = 0; I != NumInstanceMethods; ++I) {
if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
F,
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)))
F, endian::readNext<uint32_t, llvm::endianness::little>(d)))
Result.Instance.push_back(Method);
}

// Load factory methods
for (unsigned I = 0; I != NumFactoryMethods; ++I) {
if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
F,
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)))
F, endian::readNext<uint32_t, llvm::endianness::little>(d)))
Result.Factory.push_back(Method);
}

Expand Down Expand Up @@ -1009,8 +1006,7 @@ static bool readBit(unsigned &Bits) {
IdentID ASTIdentifierLookupTrait::ReadIdentifierID(const unsigned char *d) {
using namespace llvm::support;

unsigned RawID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
unsigned RawID = endian::readNext<uint32_t, llvm::endianness::little>(d);
return Reader.getGlobalIdentifierID(F, RawID >> 1);
}

Expand All @@ -1028,8 +1024,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
unsigned DataLen) {
using namespace llvm::support;

unsigned RawID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
unsigned RawID = endian::readNext<uint32_t, llvm::endianness::little>(d);
bool IsInteresting = RawID & 0x01;

// Wipe out the "is interesting" bit.
Expand All @@ -1053,9 +1048,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
}

unsigned ObjCOrBuiltinID =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
unsigned Bits =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint16_t, llvm::endianness::little>(d);
unsigned Bits = endian::readNext<uint16_t, llvm::endianness::little>(d);
bool CPlusPlusOperatorKeyword = readBit(Bits);
bool HasRevertedTokenIDToIdentifier = readBit(Bits);
bool Poisoned = readBit(Bits);
Expand Down Expand Up @@ -1084,7 +1078,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// definition.
if (HadMacroDefinition) {
uint32_t MacroDirectivesOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint32_t, llvm::endianness::little>(d);
DataLen -= 4;

Reader.addPendingMacro(II, &F, MacroDirectivesOffset);
Expand All @@ -1098,8 +1092,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
SmallVector<uint32_t, 4> DeclIDs;
for (; DataLen > 0; DataLen -= 4)
DeclIDs.push_back(Reader.getGlobalDeclID(
F,
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)));
F, endian::readNext<uint32_t, llvm::endianness::little>(d)));
Reader.SetGloballyVisibleDecls(II, DeclIDs);
}

Expand Down Expand Up @@ -1169,7 +1162,7 @@ ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) {
using namespace llvm::support;

uint32_t ModuleFileID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint32_t, llvm::endianness::little>(d);
return Reader.getLocalModuleFile(F, ModuleFileID);
}

Expand All @@ -1189,18 +1182,15 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) {
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXDeductionGuideName:
Data = (uint64_t)Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d));
F, endian::readNext<uint32_t, llvm::endianness::little>(d));
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
Data =
(uint64_t)Reader
.getLocalSelector(
F,
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(
d))
.getAsOpaquePtr();
Data = (uint64_t)Reader
.getLocalSelector(
F, endian::readNext<uint32_t, llvm::endianness::little>(d))
.getAsOpaquePtr();
break;
case DeclarationName::CXXOperatorName:
Data = *d++; // OverloadedOperatorKind
Expand All @@ -1223,8 +1213,7 @@ void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type,
using namespace llvm::support;

for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) {
uint32_t LocalID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
uint32_t LocalID = endian::readNext<uint32_t, llvm::endianness::little>(d);
Val.insert(Reader.getGlobalDeclID(F, LocalID));
}
}
Expand Down Expand Up @@ -2033,10 +2022,9 @@ HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
using namespace llvm::support;

internal_key_type ikey;
ikey.Size =
off_t(endian::readNext<uint64_t, llvm::endianness::little, unaligned>(d));
ikey.ModTime = time_t(
endian::readNext<uint64_t, llvm::endianness::little, unaligned>(d));
ikey.Size = off_t(endian::readNext<uint64_t, llvm::endianness::little>(d));
ikey.ModTime =
time_t(endian::readNext<uint64_t, llvm::endianness::little>(d));
ikey.Filename = (const char *)d;
ikey.Imported = true;
return ikey;
Expand Down Expand Up @@ -2064,9 +2052,9 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
HFI.DirInfo = (Flags >> 1) & 0x07;
HFI.IndexHeaderMapHeader = Flags & 0x01;
HFI.ControllingMacroID = Reader.getGlobalIdentifierID(
M, endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d));
M, endian::readNext<uint32_t, llvm::endianness::little>(d));
if (unsigned FrameworkOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d)) {
endian::readNext<uint32_t, llvm::endianness::little>(d)) {
// The framework offset is 1 greater than the actual offset,
// since 0 is used as an indicator for "no framework name".
StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
Expand All @@ -2077,7 +2065,7 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
"Wrong data length in HeaderFileInfo deserialization");
while (d != End) {
uint32_t LocalSMID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
endian::readNext<uint32_t, llvm::endianness::little>(d);
auto HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>(LocalSMID & 7);
LocalSMID >>= 3;

Expand Down Expand Up @@ -4085,9 +4073,8 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
// how it goes...
using namespace llvm::support;
ModuleKind Kind = static_cast<ModuleKind>(
endian::readNext<uint8_t, llvm::endianness::little, unaligned>(Data));
uint16_t Len =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint8_t, llvm::endianness::little>(Data));
uint16_t Len = endian::readNext<uint16_t, llvm::endianness::little>(Data);
StringRef Name = StringRef((const char*)Data, Len);
Data += Len;
ModuleFile *OM = (Kind == MK_PrebuiltModule || Kind == MK_ExplicitModule ||
Expand All @@ -4103,21 +4090,21 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
}

SourceLocation::UIntTy SLocOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t IdentifierIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t MacroIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t PreprocessedEntityIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t SubmoduleIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t SelectorIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t DeclIDOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);
uint32_t TypeIndexOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Data);
endian::readNext<uint32_t, llvm::endianness::little>(Data);

auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset,
RemapBuilder &Remap) {
Expand Down Expand Up @@ -9798,7 +9785,7 @@ void ASTReader::finishPendingActions() {
!NonConstDefn->isLateTemplateParsed() &&
// We only perform ODR checks for decls not in the explicit
// global module fragment.
!FD->shouldSkipCheckingODR() &&
!shouldSkipCheckingODR(FD) &&
FD->getODRHash() != NonConstDefn->getODRHash()) {
if (!isa<CXXMethodDecl>(FD)) {
PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn);
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
Reader.mergeDefinitionVisibility(OldDef, ED);
// We don't want to check the ODR hash value for declarations from global
// module fragment.
if (!ED->shouldSkipCheckingODR() &&
if (!shouldSkipCheckingODR(ED) &&
OldDef->getODRHash() != ED->getODRHash())
Reader.PendingEnumOdrMergeFailures[OldDef].push_back(ED);
} else {
Expand Down Expand Up @@ -868,7 +868,7 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
VisitRecordDeclImpl(RD);
// We should only reach here if we're in C/Objective-C. There is no
// global module fragment.
assert(!RD->shouldSkipCheckingODR());
assert(!shouldSkipCheckingODR(RD));
RD->setODRHash(Record.readInt());

// Maintain the invariant of a redeclaration chain containing only
Expand Down Expand Up @@ -2155,7 +2155,7 @@ void ASTDeclReader::MergeDefinitionData(
}

// We don't want to check ODR for decls in the global module fragment.
if (MergeDD.Definition->shouldSkipCheckingODR())
if (shouldSkipCheckingODR(MergeDD.Definition))
return;

if (D->getODRHash() != MergeDD.ODRHash) {
Expand Down Expand Up @@ -3530,7 +3530,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
// same template specialization into the same CXXRecordDecl.
auto MergedDCIt = Reader.MergedDeclContexts.find(D->getLexicalDeclContext());
if (MergedDCIt != Reader.MergedDeclContexts.end() &&
!D->shouldSkipCheckingODR() && MergedDCIt->second == D->getDeclContext())
!shouldSkipCheckingODR(D) && MergedDCIt->second == D->getDeclContext())
Reader.PendingOdrMergeChecks.push_back(D);

return FindExistingResult(Reader, D, /*Existing=*/nullptr,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6188,7 +6188,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {

BitsPacker DefinitionBits;

bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
DefinitionBits.addBit(ShouldSkipCheckingODR);

#define FIELD(Name, Width, Merge) \
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
BitsPacker EnumDeclBits;
EnumDeclBits.addBits(D->getNumPositiveBits(), /*BitWidth=*/8);
EnumDeclBits.addBits(D->getNumNegativeBits(), /*BitWidth=*/8);
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
EnumDeclBits.addBit(ShouldSkipCheckingODR);
EnumDeclBits.addBit(D->isScoped());
EnumDeclBits.addBit(D->isScopedUsingClassTag());
Expand All @@ -552,7 +552,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!D->isTopLevelDeclInObjCContainer() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
!D->getIntegerTypeSourceInfo() && !D->getMemberSpecializationInfo() &&
!needsAnonymousDeclarationNumber(D) && !D->shouldSkipCheckingODR() &&
!needsAnonymousDeclarationNumber(D) && !shouldSkipCheckingODR(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclEnumAbbrev();

Expand Down Expand Up @@ -718,7 +718,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// FIXME: stable encoding
FunctionDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()), 3);
FunctionDeclBits.addBits((uint32_t)D->getStorageClass(), /*BitWidth=*/3);
bool ShouldSkipCheckingODR = D->shouldSkipCheckingODR();
bool ShouldSkipCheckingODR = shouldSkipCheckingODR(D);
FunctionDeclBits.addBit(ShouldSkipCheckingODR);
FunctionDeclBits.addBit(D->isInlineSpecified());
FunctionDeclBits.addBit(D->isInlined());
Expand Down Expand Up @@ -1559,7 +1559,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() &&
!D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->shouldSkipCheckingODR() && !D->hasExtInfo() &&
!shouldSkipCheckingODR(D) && !D->hasExtInfo() &&
!D->isExplicitlyDefaulted()) {
if (D->getTemplatedKind() == FunctionDecl::TK_NonTemplate ||
D->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate ||
Expand Down
12 changes: 4 additions & 8 deletions clang/lib/Serialization/GlobalModuleIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,8 @@ class IdentifierIndexReaderTrait {
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d) {
using namespace llvm::support;
unsigned KeyLen =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
unsigned DataLen =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(d);
unsigned KeyLen = endian::readNext<uint16_t, llvm::endianness::little>(d);
unsigned DataLen = endian::readNext<uint16_t, llvm::endianness::little>(d);
return std::make_pair(KeyLen, DataLen);
}

Expand All @@ -113,8 +111,7 @@ class IdentifierIndexReaderTrait {

data_type Result;
while (DataLen > 0) {
unsigned ID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
unsigned ID = endian::readNext<uint32_t, llvm::endianness::little>(d);
Result.push_back(ID);
DataLen -= 4;
}
Expand Down Expand Up @@ -514,8 +511,7 @@ namespace {
// The first bit indicates whether this identifier is interesting.
// That's all we care about.
using namespace llvm::support;
unsigned RawID =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(d);
unsigned RawID = endian::readNext<uint32_t, llvm::endianness::little>(d);
bool IsInteresting = RawID & 0x01;
return std::make_pair(k, IsInteresting);
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Serialization/MultiOnDiskHashTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,11 @@ template<typename Info> class MultiOnDiskHashTable {
storage_type Ptr = Data;

uint32_t BucketOffset =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Ptr);
endian::readNext<uint32_t, llvm::endianness::little>(Ptr);

// Read the list of overridden files.
uint32_t NumFiles =
endian::readNext<uint32_t, llvm::endianness::little, unaligned>(Ptr);
endian::readNext<uint32_t, llvm::endianness::little>(Ptr);
// FIXME: Add a reserve() to TinyPtrVector so that we don't need to make
// an additional copy.
llvm::SmallVector<file_type, 16> OverriddenFiles;
Expand Down
25 changes: 5 additions & 20 deletions clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
//
//===----------------------------------------------------------------------===//
//
// This checker evaluates clang builtin functions.
// This checker evaluates "standalone" clang builtin functions that are not
// just special-cased variants of well-known non-builtin functions.
// Builtin functions like __builtin_memcpy and __builtin_alloca should be
// evaluated by the same checker that handles their non-builtin variant to
// ensure that the two variants are handled consistently.
//
//===----------------------------------------------------------------------===//

Expand Down Expand Up @@ -80,25 +84,6 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
return true;
}

case Builtin::BI__builtin_alloca_with_align:
case Builtin::BI__builtin_alloca: {
SValBuilder &SVB = C.getSValBuilder();
const loc::MemRegionVal R =
SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount());

// Set the extent of the region in bytes. This enables us to use the SVal
// of the argument directly. If we saved the extent in bits, it'd be more
// difficult to reason about values like symbol*8.
auto Size = Call.getArgSVal(0);
if (auto DefSize = Size.getAs<DefinedOrUnknownSVal>()) {
// This `getAs()` is mostly paranoia, because core.CallAndMessage reports
// undefined function arguments (unless it's disabled somehow).
state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB);
}
C.addTransition(state->BindExpr(CE, LCtx, R));
return true;
}

case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size:
case Builtin::BI__builtin_constant_p: {
Expand Down
89 changes: 49 additions & 40 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,11 @@ class MallocChecker
};

const CallDescriptionMap<CheckFn> FreeingMemFnMap{
{{{"free"}, 1}, &MallocChecker::checkFree},
{{{"if_freenameindex"}, 1}, &MallocChecker::checkIfFreeNameIndex},
{{{"kfree"}, 1}, &MallocChecker::checkFree},
{{{"g_free"}, 1}, &MallocChecker::checkFree},
{{CDM::CLibrary, {"free"}, 1}, &MallocChecker::checkFree},
{{CDM::CLibrary, {"if_freenameindex"}, 1},
&MallocChecker::checkIfFreeNameIndex},
{{CDM::CLibrary, {"kfree"}, 1}, &MallocChecker::checkFree},
{{CDM::CLibrary, {"g_free"}, 1}, &MallocChecker::checkFree},
};

bool isFreeingCall(const CallEvent &Call) const;
Expand All @@ -413,41 +414,46 @@ class MallocChecker
friend class NoOwnershipChangeVisitor;

CallDescriptionMap<CheckFn> AllocatingMemFnMap{
{{{"alloca"}, 1}, &MallocChecker::checkAlloca},
{{{"_alloca"}, 1}, &MallocChecker::checkAlloca},
{{{"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{{"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
{{{"calloc"}, 2}, &MallocChecker::checkCalloc},
{{{"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"alloca"}, 1}, &MallocChecker::checkAlloca},
{{CDM::CLibrary, {"_alloca"}, 1}, &MallocChecker::checkAlloca},
// The line for "alloca" also covers "__builtin_alloca", but the
// _with_align variant must be listed separately because it takes an
// extra argument:
{{CDM::CLibrary, {"__builtin_alloca_with_align"}, 2},
&MallocChecker::checkAlloca},
{{CDM::CLibrary, {"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
{{CDM::CLibrary, {"calloc"}, 2}, &MallocChecker::checkCalloc},
{{CDM::CLibrary, {"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup},
{{{"_strdup"}, 1}, &MallocChecker::checkStrdup},
{{{"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
{{{"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
{{CDM::CLibrary, {"_strdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
{{CDM::CLibrary, {"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
{{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
{{{"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{{"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{{"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{{"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{{"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
{{{"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
{{{"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
{{{"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
{{{"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
{{CDM::CLibrary, {"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{CDM::CLibrary, {"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
{{CDM::CLibrary, {"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
{{CDM::CLibrary, {"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
{{CDM::CLibrary, {"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
{{CDM::CLibrary, {"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
{{CDM::CLibrary, {"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
{{CDM::CLibrary, {"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
};

CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
{{{"realloc"}, 2},
{{CDM::CLibrary, {"realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
{{{"reallocf"}, 2},
{{CDM::CLibrary, {"reallocf"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, true)},
{{{"g_realloc"}, 2},
{{CDM::CLibrary, {"g_realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
{{{"g_try_realloc"}, 2},
{{CDM::CLibrary, {"g_try_realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
{{{"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
{{{"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
{{CDM::CLibrary, {"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
{{CDM::CLibrary, {"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},

// NOTE: the following CallDescription also matches the C++ standard
// library function std::getline(); the callback will filter it out.
Expand Down Expand Up @@ -1259,9 +1265,6 @@ static bool isStandardRealloc(const CallEvent &Call) {
assert(FD);
ASTContext &AC = FD->getASTContext();

if (isa<CXXMethodDecl>(FD))
return false;

return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy &&
FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy &&
FD->getParamDecl(1)->getType().getDesugaredType(AC) ==
Expand All @@ -1273,9 +1276,6 @@ static bool isGRealloc(const CallEvent &Call) {
assert(FD);
ASTContext &AC = FD->getASTContext();

if (isa<CXXMethodDecl>(FD))
return false;

return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy &&
FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy &&
FD->getParamDecl(1)->getType().getDesugaredType(AC) ==
Expand All @@ -1284,14 +1284,14 @@ static bool isGRealloc(const CallEvent &Call) {

void MallocChecker::checkRealloc(const CallEvent &Call, CheckerContext &C,
bool ShouldFreeOnFail) const {
// HACK: CallDescription currently recognizes non-standard realloc functions
// as standard because it doesn't check the type, or wether its a non-method
// function. This should be solved by making CallDescription smarter.
// Mind that this came from a bug report, and all other functions suffer from
// this.
// https://bugs.llvm.org/show_bug.cgi?id=46253
// Ignore calls to functions whose type does not match the expected type of
// either the standard realloc or g_realloc from GLib.
// FIXME: Should we perform this kind of checking consistently for each
// function? If yes, then perhaps extend the `CallDescription` interface to
// handle this.
if (!isStandardRealloc(Call) && !isGRealloc(Call))
return;

ProgramStateRef State = C.getState();
State = ReallocMemAux(C, Call, ShouldFreeOnFail, State, AF_Malloc);
State = ProcessZeroAllocCheck(Call, 1, State);
Expand Down Expand Up @@ -1842,9 +1842,18 @@ static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
return nullptr;

SymbolRef Sym = RetVal->getAsLocSymbol();

// This is a return value of a function that was not inlined, such as malloc()
// or new(). We've checked that in the caller. Therefore, it must be a symbol.
assert(Sym);
// FIXME: In theory this assertion should fail for `alloca()` calls (because
// `AllocaRegion`s are not symbolic); but in practice this does not happen.
// As the current code appears to work correctly, I'm not touching this issue
// now, but it would be good to investigate and clarify this.
// Also note that perhaps the special `AllocaRegion` should be replaced by
// `SymbolicRegion` (or turned into a subclass of `SymbolicRegion`) to enable
// proper tracking of memory allocated by `alloca()` -- and after that change
// this assertion would become valid again.

// Set the symbol's state to Allocated.
return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
Expand Down
36 changes: 24 additions & 12 deletions clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,26 @@ void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI,
}
}

void dependencies::resetBenignCodeGenOptions(frontend::ActionKind ProgramAction,
const LangOptions &LangOpts,
CodeGenOptions &CGOpts) {
// TODO: Figure out better way to set options to their default value.
if (ProgramAction == frontend::GenerateModule) {
CGOpts.MainFileName.clear();
CGOpts.DwarfDebugFlags.clear();
}
if (ProgramAction == frontend::GeneratePCH ||
(ProgramAction == frontend::GenerateModule && !LangOpts.ModulesCodegen)) {
CGOpts.DebugCompilationDir.clear();
CGOpts.CoverageCompilationDir.clear();
CGOpts.CoverageDataFile.clear();
CGOpts.CoverageNotesFile.clear();
CGOpts.ProfileInstrumentUsePath.clear();
CGOpts.SampleProfileFile.clear();
CGOpts.ProfileRemappingFile.clear();
}
}

static CowCompilerInvocation
makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
CI.resetNonModularOptions();
Expand All @@ -167,18 +187,8 @@ makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
// LLVM options are not going to affect the AST
CI.getFrontendOpts().LLVMArgs.clear();

// TODO: Figure out better way to set options to their default value.
CI.getCodeGenOpts().MainFileName.clear();
CI.getCodeGenOpts().DwarfDebugFlags.clear();
if (!CI.getLangOpts().ModulesCodegen) {
CI.getCodeGenOpts().DebugCompilationDir.clear();
CI.getCodeGenOpts().CoverageCompilationDir.clear();
CI.getCodeGenOpts().CoverageDataFile.clear();
CI.getCodeGenOpts().CoverageNotesFile.clear();
CI.getCodeGenOpts().ProfileInstrumentUsePath.clear();
CI.getCodeGenOpts().SampleProfileFile.clear();
CI.getCodeGenOpts().ProfileRemappingFile.clear();
}
resetBenignCodeGenOptions(frontend::GenerateModule, CI.getLangOpts(),
CI.getCodeGenOpts());

// Map output paths that affect behaviour to "-" so their existence is in the
// context hash. The final path will be computed in addOutputPaths.
Expand Down Expand Up @@ -342,6 +352,8 @@ static bool needsModules(FrontendInputFile FIF) {

void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
CI.clearImplicitModuleBuildOptions();
resetBenignCodeGenOptions(CI.getFrontendOpts().ProgramAction,
CI.getLangOpts(), CI.getCodeGenOpts());

if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
Preprocessor &PP = ScanInstance.getPreprocessor();
Expand Down
258 changes: 258 additions & 0 deletions clang/test/AST/Interp/builtin-align-cxx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
// C++-specific checks for the alignment builtins
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 %s -fsyntax-only -verify=expected,both -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 %s -fsyntax-only -verify=ref,both


/// This is just a copy of the one from test/SemaCXX/ with some of the
/// diagnostic output adapted.
/// Also, align32array has an initializer now, which means it's not just
/// a dummy pointer for us and we do actually have type information for it.
/// In the future, we need to retain type information for dummy pointers as
/// well, so here is a test that will break once we do that:
namespace {
_Alignas(32) char heh[4];
static_assert(!__builtin_is_aligned(&heh[1], 4), ""); // expected-error {{failed}}
}


// Check that we don't crash when using dependent types in __builtin_align:
template <typename a, a b>
void *c(void *d) { // both-note{{candidate template ignored}}
return __builtin_align_down(d, b);
}

struct x {};
x foo;
void test(void *value) {
c<int, 16>(value);
c<struct x, foo>(value); // both-error{{no matching function for call to 'c'}}
}

template <typename T, long Alignment, long ArraySize = 16>
void test_templated_arguments() {
T array[ArraySize]; // both-error{{variable has incomplete type 'fwddecl'}}
static_assert(__is_same(decltype(__builtin_align_up(array, Alignment)), T *), // both-error{{requested alignment is not a power of 2}}
"return type should be the decayed array type");
static_assert(__is_same(decltype(__builtin_align_down(array, Alignment)), T *),
"return type should be the decayed array type");
static_assert(__is_same(decltype(__builtin_is_aligned(array, Alignment)), bool),
"return type should be bool");
T *x1 = __builtin_align_up(array, Alignment);
T *x2 = __builtin_align_down(array, Alignment);
bool x3 = __builtin_align_up(array, Alignment);
}

void test() {
test_templated_arguments<int, 32>(); // fine
test_templated_arguments<struct fwddecl, 16>();
// both-note@-1{{in instantiation of function template specialization 'test_templated_arguments<fwddecl, 16L, 16L>'}}
// both-note@-2{{forward declaration of 'fwddecl'}}
test_templated_arguments<int, 7>(); // invalid alignment value
// both-note@-1{{in instantiation of function template specialization 'test_templated_arguments<int, 7L, 16L>'}}
}

template <typename T, long ArraySize>
void test_incorrect_alignment_without_instatiation(T value) {
int array[32];
static_assert(__is_same(decltype(__builtin_align_up(array, 31)), int *), // both-error{{requested alignment is not a power of 2}}
"return type should be the decayed array type");
static_assert(__is_same(decltype(__builtin_align_down(array, 7)), int *), // both-error{{requested alignment is not a power of 2}}
"return type should be the decayed array type");
static_assert(__is_same(decltype(__builtin_is_aligned(array, -1)), bool), // both-error{{requested alignment must be 1 or greater}}
"return type should be bool");
__builtin_align_up(array); // both-error{{too few arguments to function call, expected 2, have 1}}
__builtin_align_up(array, 31); // both-error{{requested alignment is not a power of 2}}
__builtin_align_down(array, 31); // both-error{{requested alignment is not a power of 2}}
__builtin_align_up(array, 31); // both-error{{requested alignment is not a power of 2}}
__builtin_align_up(value, 31); // This shouldn't want since the type is dependent
__builtin_align_up(value); // Same here

__builtin_align_up(array, sizeof(sizeof(value)) - 1); // both-error{{requested alignment is not a power of 2}}
__builtin_align_up(array, value); // no diagnostic as the alignment is value dependent.
(void)__builtin_align_up(array, ArraySize); // The same above here
}

// The original fix for the issue above broke some legitimate code.
// Here is a regression test:
typedef __SIZE_TYPE__ size_t;
void *allocate_impl(size_t size);
template <typename T>
T *allocate() {
constexpr size_t allocation_size =
__builtin_align_up(sizeof(T), sizeof(void *));
return static_cast<T *>(
__builtin_assume_aligned(allocate_impl(allocation_size), sizeof(void *)));
}
struct Foo {
int value;
};
void *test2() {
return allocate<struct Foo>();
}

// Check that pointers-to-members cannot be used:
class MemPtr {
public:
int data;
void func();
virtual void vfunc();
};
void test_member_ptr() {
__builtin_align_up(&MemPtr::data, 64); // both-error{{operand of type 'int MemPtr::*' where arithmetic or pointer type is required}}
__builtin_align_down(&MemPtr::func, 64); // both-error{{operand of type 'void (MemPtr::*)()' where arithmetic or pointer type is required}}
__builtin_is_aligned(&MemPtr::vfunc, 64); // both-error{{operand of type 'void (MemPtr::*)()' where arithmetic or pointer type is required}}
}

void test_references(Foo &i) {
// Check that the builtins look at the referenced type rather than the reference itself.
(void)__builtin_align_up(i, 64); // both-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(static_cast<Foo &>(i), 64); // both-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(static_cast<const Foo &>(i), 64); // both-error{{operand of type 'const Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(static_cast<Foo &&>(i), 64); // both-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(static_cast<const Foo &&>(i), 64); // both-error{{operand of type 'const Foo' where arithmetic or pointer type is required}}
(void)__builtin_align_up(&i, 64);
}

// Check that constexpr wrapper functions can be constant-evaluated.
template <typename T>
constexpr bool wrap_is_aligned(T ptr, long align) {
return __builtin_is_aligned(ptr, align);
// both-note@-1{{requested alignment -3 is not a positive power of two}}
// both-note@-2{{requested alignment 19 is not a positive power of two}}
// both-note@-3{{requested alignment must be 128 or less for type 'char'; 4194304 is invalid}}
}
template <typename T>
constexpr T wrap_align_up(T ptr, long align) {
return __builtin_align_up(ptr, align);
// both-note@-1{{requested alignment -2 is not a positive power of two}}
// both-note@-2{{requested alignment 18 is not a positive power of two}}
// both-note@-3{{requested alignment must be 2147483648 or less for type 'int'; 8589934592 is invalid}}
// both-error@-4{{operand of type 'bool' where arithmetic or pointer type is required}}
}

template <typename T>
constexpr T wrap_align_down(T ptr, long align) {
return __builtin_align_down(ptr, align);
// both-note@-1{{requested alignment -1 is not a positive power of two}}
// both-note@-2{{requested alignment 17 is not a positive power of two}}
// both-note@-3{{requested alignment must be 32768 or less for type 'short'; 1048576 is invalid}}
}

constexpr int a1 = wrap_align_up(22, 32);
static_assert(a1 == 32, "");
constexpr int a2 = wrap_align_down(22, 16);
static_assert(a2 == 16, "");
constexpr bool a3 = wrap_is_aligned(22, 32);
static_assert(!a3, "");
static_assert(wrap_align_down(wrap_align_up(22, 16), 32) == 32, "");
static_assert(wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 32), "");
static_assert(!wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 64), "");

constexpr long const_value(long l) { return l; }
// Check some invalid values during constant-evaluation
static_assert(wrap_align_down(1, const_value(-1)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_align_up(1, const_value(-2)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_is_aligned(1, const_value(-3)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_align_down(1, const_value(17)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_align_up(1, const_value(18)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_is_aligned(1, const_value(19)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}

// Check invalid values for smaller types:
static_assert(wrap_align_down(static_cast<short>(1), const_value(1 << 20)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to }}
// Check invalid boolean type
static_assert(wrap_align_up(static_cast<int>(1), const_value(1ull << 33)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}
static_assert(wrap_is_aligned(static_cast<char>(1), const_value(1 << 22)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in call to}}

// Check invalid boolean type
static_assert(wrap_align_up(static_cast<bool>(1), const_value(1 << 21)), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{in instantiation of function template specialization 'wrap_align_up<bool>' requested here}}

// Check constant evaluation for pointers:
_Alignas(32) char align32array[128] = {};
static_assert(&align32array[0] == &align32array[0], "");
// __builtin_align_up/down can be constant evaluated as a no-op for values
// that are known to have greater alignment:
static_assert(__builtin_align_up(&align32array[0], 32) == &align32array[0], "");
static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[0], 4) == __builtin_align_up(&align32array[0], 8), "");
// But it can not be evaluated if the alignment is greater than the minimum
// known alignment, since in that case the value might be the same if it happens
// to actually be aligned to 64 bytes at run time.
static_assert(&align32array[0] == __builtin_align_up(&align32array[0], 64), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}
static_assert(__builtin_align_up(&align32array[0], 64) == __builtin_align_up(&align32array[0], 64), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}

// However, we can compute in case the requested alignment is less than the
// base alignment:
static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");
static_assert(__builtin_align_up(&align32array[1], 4) == &align32array[4], "");
static_assert(__builtin_align_up(&align32array[2], 4) == &align32array[4], "");
static_assert(__builtin_align_up(&align32array[3], 4) == &align32array[4], "");
static_assert(__builtin_align_up(&align32array[4], 4) == &align32array[4], "");
static_assert(__builtin_align_up(&align32array[5], 4) == &align32array[8], "");
static_assert(__builtin_align_up(&align32array[6], 4) == &align32array[8], "");
static_assert(__builtin_align_up(&align32array[7], 4) == &align32array[8], "");
static_assert(__builtin_align_up(&align32array[8], 4) == &align32array[8], "");

static_assert(__builtin_align_down(&align32array[0], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[2], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[3], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[4], 4) == &align32array[4], "");
static_assert(__builtin_align_down(&align32array[5], 4) == &align32array[4], "");
static_assert(__builtin_align_down(&align32array[6], 4) == &align32array[4], "");
static_assert(__builtin_align_down(&align32array[7], 4) == &align32array[4], "");
static_assert(__builtin_align_down(&align32array[8], 4) == &align32array[8], "");

// Achieving the same thing using casts to uintptr_t is not allowed:
static_assert((char *)((__UINTPTR_TYPE__)&align32array[7] & ~3) == &align32array[4], ""); // both-error{{not an integral constant expression}} \
// expected-note {{cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression}}

static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], "");
static_assert(__builtin_align_down(&align32array[1], 64) == &align32array[0], ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}

// Add some checks for __builtin_is_aligned:
static_assert(__builtin_is_aligned(&align32array[0], 32), "");
static_assert(__builtin_is_aligned(&align32array[4], 4), "");
// We cannot constant evaluate whether the array is aligned to > 32 since this
// may well be true at run time.
static_assert(!__builtin_is_aligned(&align32array[0], 64), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate whether run-time alignment is at least 64}}

// However, if the alignment being checked is less than the minimum alignment of
// the base object we can check the low bits of the alignment:
static_assert(__builtin_is_aligned(&align32array[0], 4), "");
static_assert(!__builtin_is_aligned(&align32array[1], 4), "");
static_assert(!__builtin_is_aligned(&align32array[2], 4), "");
static_assert(!__builtin_is_aligned(&align32array[3], 4), "");
static_assert(__builtin_is_aligned(&align32array[4], 4), "");

// TODO: this should evaluate to true even though we can't evaluate the result
// of __builtin_align_up() to a concrete value
static_assert(__builtin_is_aligned(__builtin_align_up(&align32array[0], 64), 64), ""); // both-error{{not an integral constant expression}}
// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}

// Check different source and alignment type widths are handled correctly.
static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<signed short>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<signed short>(7), static_cast<signed long>(4)), "");
// Also check signed -- unsigned mismatch.
static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<signed long>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), static_cast<unsigned long>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<unsigned long>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), static_cast<signed long>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<unsigned short>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<unsigned short>(7), static_cast<signed long>(4)), "");

// Check the diagnostic message
_Alignas(void) char align_void_array[1]; // both-error {{invalid application of '_Alignas' to an incomplete type 'void'}}
24 changes: 8 additions & 16 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,13 @@ namespace strcmp {
static_assert(__builtin_strcmp("abab", "abab\0banana") == 0, "");
static_assert(__builtin_strcmp("abab\0banana", "abab\0canada") == 0, "");
static_assert(__builtin_strcmp(0, "abab") == 0, ""); // both-error {{not an integral constant}} \
// both-note {{dereferenced null}} \
// expected-note {{in call to}}
// both-note {{dereferenced null}}
static_assert(__builtin_strcmp("abab", 0) == 0, ""); // both-error {{not an integral constant}} \
// both-note {{dereferenced null}} \
// expected-note {{in call to}}
// both-note {{dereferenced null}}

static_assert(__builtin_strcmp(kFoobar, kFoobazfoobar) == -1, "");
static_assert(__builtin_strcmp(kFoobar, kFoobazfoobar + 6) == 0, ""); // both-error {{not an integral constant}} \
// both-note {{dereferenced one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{dereferenced one-past-the-end}}

/// Used to assert because we're passing a dummy pointer to
/// __builtin_strcmp() when evaluating the return statement.
Expand Down Expand Up @@ -72,14 +69,11 @@ constexpr const char *a = "foo\0quux";
static_assert(check(c), "");

constexpr int over1 = __builtin_strlen(a + 9); // both-error {{constant expression}} \
// both-note {{one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{one-past-the-end}}
constexpr int over2 = __builtin_strlen(b + 9); // both-error {{constant expression}} \
// both-note {{one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{one-past-the-end}}
constexpr int over3 = __builtin_strlen(c + 9); // both-error {{constant expression}} \
// both-note {{one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{one-past-the-end}}

constexpr int under1 = __builtin_strlen(a - 1); // both-error {{constant expression}} \
// both-note {{cannot refer to element -1}}
Expand All @@ -90,8 +84,7 @@ constexpr const char *a = "foo\0quux";

constexpr char d[] = { 'f', 'o', 'o' }; // no nul terminator.
constexpr int bad = __builtin_strlen(d); // both-error {{constant expression}} \
// both-note {{one-past-the-end}} \
// expected-note {{in call to}}
// both-note {{one-past-the-end}}
}

namespace nan {
Expand All @@ -114,8 +107,7 @@ namespace nan {
/// FIXME: Current interpreter misses diagnostics.
constexpr char f2[] = {'0', 'x', 'A', 'E'}; /// No trailing 0 byte.
constexpr double NaN7 = __builtin_nan(f2); // both-error {{must be initialized by a constant expression}} \
// expected-note {{read of dereferenced one-past-the-end pointer}} \
// expected-note {{in call to}}
// expected-note {{read of dereferenced one-past-the-end pointer}}
static_assert(!__builtin_issignaling(__builtin_nan("")), "");
static_assert(__builtin_issignaling(__builtin_nans("")), "");
}
Expand Down
14 changes: 14 additions & 0 deletions clang/test/AST/Interp/cxx03.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,17 @@ namespace NonInitializingMemberExpr {
// both-note {{required by}} \
// both-note {{subexpression not valid}}
}


namespace NonLValueMemberExpr {
struct PODType {
int value;
};

#define ATTR __attribute__((require_constant_initialization))
struct TT1 {
ATTR static const int &subobj_init;
};

const int &TT1::subobj_init = PODType().value;
}
15 changes: 13 additions & 2 deletions clang/test/AST/Interp/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,9 +584,20 @@ namespace VariadicOperator {
namespace WeakCompare {
[[gnu::weak]]void weak_method();
static_assert(weak_method != nullptr, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}

constexpr auto A = &weak_method;
static_assert(A != nullptr, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}
// both-note {{comparison against address of weak declaration '&weak_method' can only be performed at runtim}}
}

namespace FromIntegral {
#if __cplusplus >= 202002L
typedef double (*DoubleFn)();
int a[(int)DoubleFn((void*)-1)()]; // both-error {{not allowed at file scope}} \
// both-warning {{variable length arrays}}
int b[(int)DoubleFn((void*)(-1 + 1))()]; // both-error {{not allowed at file scope}} \
// expected-note {{evaluates to a null function pointer}} \
// both-warning {{variable length arrays}}
#endif
}
8 changes: 8 additions & 0 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,3 +1309,11 @@ namespace pr18633 {
func2<int>();
}
}

namespace {
struct F {
static constexpr int Z = 12;
};
F f;
static_assert(f.Z == 12, "");
}
10 changes: 9 additions & 1 deletion clang/test/AST/Interp/vectors.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -verify=ref,both %s

// both-no-diagnostics
// ref-no-diagnostics

typedef int __attribute__((vector_size(16))) VI4;
constexpr VI4 A = {1,2,3,4};
Expand All @@ -13,10 +13,18 @@ namespace Vector {
return VI4 { n * 3, n + 4, n - 5, n / 6 };
}
constexpr auto v1 = f(10);
static_assert(__builtin_vectorelements(v1) == (16 / sizeof(int)), "");

typedef double __attribute__((vector_size(32))) VD4;
constexpr VD4 g(int n) {
return (VD4) { n / 2.0, n + 1.5, n - 5.4, n * 0.9 };
}
constexpr auto v2 = g(4);
static_assert(__builtin_vectorelements(v2) == (32 / sizeof(double)), "");
}

/// FIXME: We need to support BitCasts between vector types.
namespace {
typedef float __attribute__((vector_size(16))) VI42;
constexpr VI42 A2 = A; // expected-error {{must be initialized by a constant expression}}
}
1 change: 1 addition & 0 deletions clang/test/AST/ast-dump-attr-json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ __thread __attribute__ ((tls_model ("local-exec"))) int tls_model_var;
// CHECK-NEXT: "tokLen": 11
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "isUsed": true,
// CHECK-NEXT: "name": "global_decl",
// CHECK-NEXT: "mangledName": "global_decl",
// CHECK-NEXT: "type": {
Expand Down
6 changes: 4 additions & 2 deletions clang/test/Analysis/Inputs/system-header-simulator-cxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,7 @@ using ostream = basic_ostream<char>;
extern std::ostream cout;

ostream &operator<<(ostream &, const string &);

#if __cplusplus >= 202002L
template <class T>
ostream &operator<<(ostream &, const std::unique_ptr<T> &);
Expand All @@ -1122,11 +1123,12 @@ istream &getline(istream &, string &, char);
istream &getline(istream &, string &);
} // namespace std

#ifdef TEST_INLINABLE_ALLOCATORS
namespace std {
void *malloc(size_t);
void free(void *);
}
} // namespace std

#ifdef TEST_INLINABLE_ALLOCATORS
void* operator new(std::size_t size, const std::nothrow_t&) throw() { return std::malloc(size); }
void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return std::malloc(size); }
void operator delete(void* ptr, const std::nothrow_t&) throw() { std::free(ptr); }
Expand Down
24 changes: 16 additions & 8 deletions clang/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,optin.cplusplus.UninitializedObject \
// RUN: -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
// RUN: -analyzer-config optin.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
// RUN: -std=c++11 -verify %s

// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,optin.cplusplus.UninitializedObject \
// RUN: -analyzer-config optin.cplusplus.UninitializedObject:CheckPointeeInitialization=true \
// RUN: -std=c++11 -verify %s

Expand Down Expand Up @@ -316,7 +316,10 @@ void fCyclicPointerTest2() {

// Void pointer tests are mainly no-crash tests.

void *malloc(int size);
typedef __typeof(sizeof(int)) size_t;

void *calloc(size_t nmemb, size_t size);
void free(void *p);

class VoidPointerTest1 {
void *vptr;
Expand All @@ -328,8 +331,9 @@ class VoidPointerTest1 {
};

void fVoidPointerTest1() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerTest1(vptr, char());
free(vptr);
}

class VoidPointerTest2 {
Expand All @@ -342,8 +346,9 @@ class VoidPointerTest2 {
};

void fVoidPointerTest2() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerTest2(&vptr, char());
free(vptr);
}

class VoidPointerRRefTest1 {
Expand All @@ -359,8 +364,9 @@ upon returning to the caller. This will be a dangling reference}}
};

void fVoidPointerRRefTest1() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerRRefTest1(vptr, char());
free(vptr);
}

class VoidPointerRRefTest2 {
Expand All @@ -376,8 +382,9 @@ upon returning to the caller. This will be a dangling reference}}
};

void fVoidPointerRRefTest2() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerRRefTest2(&vptr, char());
free(vptr);
}

class VoidPointerLRefTest {
Expand All @@ -393,8 +400,9 @@ upon returning to the caller. This will be a dangling reference}}
};

void fVoidPointerLRefTest() {
void *vptr = malloc(sizeof(int));
void *vptr = calloc(1, sizeof(int));
VoidPointerLRefTest(vptr, char());
free(vptr);
}

struct CyclicVoidPointerTest {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Analysis/exercise-ps.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_analyze_cc1 %s -verify -Wno-error=implicit-function-declaration \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=core,unix.Malloc \
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
//
// Just exercise the analyzer on code that has at one point caused issues
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Analysis/explain-svals.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -verify %s \
// RUN: -analyzer-checker=core.builtin \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-checker=unix.cstring \
// RUN: -analyzer-checker=unix.Malloc \
// RUN: -analyzer-config display-checker-name=false

typedef unsigned long size_t;
Expand Down
24 changes: 24 additions & 0 deletions clang/test/Analysis/malloc-std-namespace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify -analyzer-output=text %s

// This file tests that unix.Malloc can handle C++ code where e.g. malloc and
// free are declared within the namespace 'std' by the header <cstdlib>.

#include "Inputs/system-header-simulator-cxx.h"

void leak() {
int *p = static_cast<int*>(std::malloc(sizeof(int))); // expected-note{{Memory is allocated}}
} // expected-warning{{Potential leak of memory pointed to by 'p'}}
// expected-note@-1{{Potential leak of memory pointed to by 'p'}}

void no_leak() {
int *p = static_cast<int*>(std::malloc(sizeof(int)));
std::free(p); // no-warning
}

void invalid_free() {
int i;
int *p = &i;
//expected-note@+2{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
//expected-warning@+1{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
std::free(p);
}
11 changes: 11 additions & 0 deletions clang/test/Analysis/malloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,17 @@ void allocaFree(void) {
free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
}

void allocaFreeBuiltin(void) {
int *p = __builtin_alloca(sizeof(int));
free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
}

void allocaFreeBuiltinAlign(void) {
int *p = __builtin_alloca_with_align(sizeof(int), 64);
free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
}


int* mallocEscapeRet(void) {
int *p = malloc(12);
return p; // no warning
Expand Down
Loading