68 changes: 56 additions & 12 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,7 @@ static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info);
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result);

//===----------------------------------------------------------------------===//
// Misc utilities
Expand Down Expand Up @@ -6377,8 +6378,28 @@ static bool refersToCompleteObject(const LValue &LVal) {
return false;
}

bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,
unsigned Type) {
/// Tries to evaluate the __builtin_object_size for @p E. If successful, returns
/// true and stores the result in @p Size.
///
/// If @p WasError is non-null, this will report whether the failure to evaluate
/// is to be treated as an Error in IntExprEvaluator.
static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
EvalInfo &Info, uint64_t &Size,
bool *WasError = nullptr) {
if (WasError != nullptr)
*WasError = false;

auto Error = [&](const Expr *E) {
if (WasError != nullptr)
*WasError = true;
return false;
};

auto Success = [&](uint64_t S, const Expr *E) {
Size = S;
return true;
};

// Determine the denoted object.
LValue Base;
{
Expand All @@ -6387,8 +6408,15 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,
// ignore the side-effects.
SpeculativeEvaluationRAII SpeculativeEval(Info);
FoldOffsetRAII Fold(Info, Type & 1);
const Expr *Ptr = ignorePointerCastsAndParens(E->getArg(0));
if (!EvaluatePointer(Ptr, Base, Info))

if (E->isGLValue()) {
// It's possible for us to be given GLValues if we're called via
// Expr::tryEvaluateObjectSize.
APValue RVal;
if (!EvaluateAsRValue(Info, E, RVal))
return false;
Base.setFrom(Info.Ctx, RVal);
} else if (!EvaluatePointer(ignorePointerCastsAndParens(E), Base, Info))
return false;
}

Expand Down Expand Up @@ -6447,7 +6475,7 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,
End.Designator.Entries.size() == End.Designator.MostDerivedPathLength) {
// We got a pointer to an array. Step to its end.
AmountToAdd = End.Designator.MostDerivedArraySize -
End.Designator.Entries.back().ArrayIndex;
End.Designator.Entries.back().ArrayIndex;
} else if (End.Designator.isOnePastTheEnd()) {
// We're already pointing at the end of the object.
AmountToAdd = 0;
Expand Down Expand Up @@ -6484,7 +6512,18 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,
if (BaseOffset > EndOffset)
return Success(0, E);

return Success(EndOffset - BaseOffset, E);
return Success((EndOffset - BaseOffset).getQuantity(), E);
}

bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,
unsigned Type) {
uint64_t Size;
bool WasError;
if (::tryEvaluateBuiltinObjectSize(E->getArg(0), Type, Info, Size, &WasError))
return Success(Size, E);
if (WasError)
return Error(E);
return false;
}

bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
Expand All @@ -6501,12 +6540,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (TryEvaluateBuiltinObjectSize(E, Type))
return true;

// If evaluating the argument has side-effects, we can't determine the size
// of the object, and so we lower it to unknown now. CodeGen relies on us to
// handle all cases where the expression has side-effects.
// Likewise, if Type is 3, we must handle this because CodeGen cannot give a
// conservatively correct answer in that case.
if (E->getArg(0)->HasSideEffects(Info.Ctx) || Type == 3)
if (E->getArg(0)->HasSideEffects(Info.Ctx))
return Success((Type & 2) ? 0 : -1, E);

// Expression had no side effects, but we couldn't statically determine the
Expand Down Expand Up @@ -9483,3 +9517,13 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
Evaluate(ResultScratch, Info, E);
return Diags.empty();
}

bool Expr::tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx,
unsigned Type) const {
if (!getType()->isPointerType())
return false;

Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold);
return ::tryEvaluateBuiltinObjectSize(this, Type, Info, Result);
}
28 changes: 20 additions & 8 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,8 @@ class CXXNameMangler {

void mangleType(const TagType*);
void mangleType(TemplateName);
void mangleBareFunctionType(const FunctionType *T,
bool MangleReturnType);
void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType,
const FunctionDecl *FD = nullptr);
void mangleNeonVectorType(const VectorType *T);
void mangleAArch64NeonVectorType(const VectorType *T);

Expand Down Expand Up @@ -523,7 +523,7 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
}

mangleBareFunctionType(FD->getType()->getAs<FunctionType>(),
MangleReturnType);
MangleReturnType, FD);
}

static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
Expand Down Expand Up @@ -1282,7 +1282,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
Out << "Ul";
const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
getAs<FunctionProtoType>();
mangleBareFunctionType(Proto, /*MangleReturnType=*/false);
mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
Lambda->getLambdaStaticInvoker());
Out << "E";

// The number is omitted for the first closure type with a given
Expand Down Expand Up @@ -2171,7 +2172,8 @@ void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
}

void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
bool MangleReturnType) {
bool MangleReturnType,
const FunctionDecl *FD) {
// We should never be mangling something without a prototype.
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);

Expand All @@ -2194,8 +2196,19 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
return;
}

for (const auto &Arg : Proto->param_types())
mangleType(Context.getASTContext().getSignatureParameterType(Arg));
assert(!FD || FD->getNumParams() == Proto->getNumParams());
for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
const auto &ParamTy = Proto->getParamType(I);
mangleType(Context.getASTContext().getSignatureParameterType(ParamTy));

if (FD) {
if (auto *Attr = FD->getParamDecl(I)->getAttr<PassObjectSizeAttr>()) {
// Attr can only take 1 character, so we can hardcode the length below.
assert(Attr->getType() <= 9 && Attr->getType() >= 0);
Out << "U17pass_object_size" << Attr->getType();
}
}
}

FunctionTypeDepth.pop(saved);

Expand Down Expand Up @@ -4228,4 +4241,3 @@ ItaniumMangleContext *
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new ItaniumMangleContextImpl(Context, Diags);
}

16 changes: 14 additions & 2 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1841,8 +1841,20 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
Out << 'X';
} else {
// Happens for function pointer type arguments for example.
for (const QualType &Arg : Proto->param_types())
mangleArgumentType(Arg, Range);
for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
mangleArgumentType(Proto->getParamType(I), Range);
// Mangle each pass_object_size parameter as if it's a paramater of enum
// type passed directly after the parameter with the pass_object_size
// attribute. The aforementioned enum's name is __pass_object_size, and we
// pretend it resides in a top-level namespace called __clang.
//
// FIXME: Is there a defined extension notation for the MS ABI, or is it
// necessary to just cross our fingers and hope this type+namespace
// combination doesn't conflict with anything?
if (D)
if (auto *P = D->getParamDecl(I)->getAttr<PassObjectSizeAttr>())
Out << "W4__pass_object_size" << P->getType() << "@__clang@@";
}
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
Out << 'Z';
Expand Down
92 changes: 72 additions & 20 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,71 @@ Value *CodeGenFunction::EmitVAStartEnd(Value *ArgValue, bool IsStart) {
return Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue);
}

/// Checks if using the result of __builtin_object_size(p, @p From) in place of
/// __builtin_object_size(p, @p To) is correct
static bool areBOSTypesCompatible(int From, int To) {
// Note: Our __builtin_object_size implementation currently treats Type=0 and
// Type=2 identically. Encoding this implementation detail here may make
// improving __builtin_object_size difficult in the future, so it's omitted.
return From == To || (From == 0 && To == 1) || (From == 3 && To == 2);
}

static llvm::Value *
getDefaultBuiltinObjectSizeResult(unsigned Type, llvm::IntegerType *ResType) {
return ConstantInt::get(ResType, (Type & 2) ? 0 : -1, /*isSigned=*/true);
}

llvm::Value *
CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
llvm::IntegerType *ResType) {
uint64_t ObjectSize;
if (!E->tryEvaluateObjectSize(ObjectSize, getContext(), Type))
return emitBuiltinObjectSize(E, Type, ResType);
return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
}

/// Returns a Value corresponding to the size of the given expression.
/// This Value may be either of the following:
/// - A llvm::Argument (if E is a param with the pass_object_size attribute on
/// it)
/// - A call to the @llvm.objectsize intrinsic
llvm::Value *
CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
llvm::IntegerType *ResType) {
// We need to reference an argument if the pointer is a parameter with the
// pass_object_size attribute.
if (auto *D = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
auto *Param = dyn_cast<ParmVarDecl>(D->getDecl());
auto *PS = D->getDecl()->getAttr<PassObjectSizeAttr>();
if (Param != nullptr && PS != nullptr &&
areBOSTypesCompatible(PS->getType(), Type)) {
auto Iter = SizeArguments.find(Param);
assert(Iter != SizeArguments.end());

const ImplicitParamDecl *D = Iter->second;
auto DIter = LocalDeclMap.find(D);
assert(DIter != LocalDeclMap.end());

return EmitLoadOfScalar(DIter->second, /*volatile=*/false,
getContext().getSizeType(), E->getLocStart());
}
}

// LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't
// evaluate E for side-effects. In either case, we shouldn't lower to
// @llvm.objectsize.
if (Type == 3 || E->HasSideEffects(getContext()))
return getDefaultBuiltinObjectSizeResult(Type, ResType);

// LLVM only supports 0 and 2, make sure that we pass along that
// as a boolean.
auto *CI = ConstantInt::get(Builder.getInt1Ty(), (Type & 2) >> 1);
// FIXME: Get right address space.
llvm::Type *Tys[] = {ResType, Builder.getInt8PtrTy(0)};
Value *F = CGM.getIntrinsic(Intrinsic::objectsize, Tys);
return Builder.CreateCall(F, {EmitScalarExpr(E), CI});
}

RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue) {
Expand Down Expand Up @@ -586,26 +651,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F, ArgValue));
}
case Builtin::BI__builtin_object_size: {
// We rely on constant folding to deal with expressions with side effects.
assert(!E->getArg(0)->HasSideEffects(getContext()) &&
"should have been constant folded");

// We pass this builtin onto the optimizer so that it can
// figure out the object size in more complex cases.
llvm::Type *ResType = ConvertType(E->getType());

// LLVM only supports 0 and 2, make sure that we pass along that
// as a boolean.
Value *Ty = EmitScalarExpr(E->getArg(1));
ConstantInt *CI = dyn_cast<ConstantInt>(Ty);
assert(CI);
uint64_t val = CI->getZExtValue();
CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1);
// FIXME: Get right address space.
llvm::Type *Tys[] = { ResType, Builder.getInt8PtrTy(0) };
Value *F = CGM.getIntrinsic(Intrinsic::objectsize, Tys);
return RValue::get(
Builder.CreateCall(F, {EmitScalarExpr(E->getArg(0)), CI}));
unsigned Type =
E->getArg(1)->EvaluateKnownConstInt(getContext()).getZExtValue();
auto *ResType = cast<llvm::IntegerType>(ConvertType(E->getType()));

// We pass this builtin onto the optimizer so that it can figure out the
// object size in more complex cases.
return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType));
}
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT));
CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
return llvm::Constant::getNullValue(FTy->getPointerTo());
}

Expand Down
65 changes: 55 additions & 10 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,41 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
FTNP->getExtInfo(), RequiredArgs(0));
}

/// Adds the formal paramaters in FPT to the given prefix. If any parameter in
/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
static void appendParameterTypes(const CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &prefix,
const CanQual<FunctionProtoType> &FPT,
const FunctionDecl *FD) {
// Fast path: unknown target.
if (FD == nullptr) {
prefix.append(FPT->param_type_begin(), FPT->param_type_end());
return;
}

// In the vast majority cases, we'll have precisely FPT->getNumParams()
// parameters; the only thing that can change this is the presence of
// pass_object_size. So, we preallocate for the common case.
prefix.reserve(prefix.size() + FPT->getNumParams());

assert(FD->getNumParams() == FPT->getNumParams());
for (unsigned I = 0, E = FPT->getNumParams(); I != E; ++I) {
prefix.push_back(FPT->getParamType(I));
if (FD->getParamDecl(I)->hasAttr<PassObjectSizeAttr>())
prefix.push_back(CGT.getContext().getSizeType());
}
}

/// Arrange the LLVM function layout for a value of the given function
/// type, on top of any implicit parameters already stored.
static const CGFunctionInfo &
arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod,
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP) {
CanQual<FunctionProtoType> FTP,
const FunctionDecl *FD) {
RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, prefix.size());
// FIXME: Kill copy.
prefix.append(FTP->param_type_begin(), FTP->param_type_end());
appendParameterTypes(CGT, prefix, FTP, FD);
CanQualType resultType = FTP->getReturnType().getUnqualifiedType();
return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod,
/*chainCall=*/false, prefix,
Expand All @@ -110,10 +136,11 @@ arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod,
/// Arrange the argument and result information for a value of the
/// given freestanding function type.
const CGFunctionInfo &
CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> FTP) {
CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> FTP,
const FunctionDecl *FD) {
SmallVector<CanQualType, 16> argTypes;
return ::arrangeLLVMFunctionInfo(*this, /*instanceMethod=*/false, argTypes,
FTP);
FTP, FD);
}

static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
Expand Down Expand Up @@ -156,7 +183,8 @@ static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
/// constructor or destructor.
const CGFunctionInfo &
CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
const FunctionProtoType *FTP) {
const FunctionProtoType *FTP,
const CXXMethodDecl *MD) {
SmallVector<CanQualType, 16> argTypes;

// Add the 'this' pointer.
Expand All @@ -167,7 +195,7 @@ CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,

return ::arrangeLLVMFunctionInfo(
*this, true, argTypes,
FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>(), MD);
}

/// Arrange the argument and result information for a declaration or
Expand All @@ -184,10 +212,10 @@ CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) {
if (MD->isInstance()) {
// The abstract case is perfectly fine.
const CXXRecordDecl *ThisType = TheCXXABI.getThisArgumentTypeForMethod(MD);
return arrangeCXXMethodType(ThisType, prototype.getTypePtr());
return arrangeCXXMethodType(ThisType, prototype.getTypePtr(), MD);
}

return arrangeFreeFunctionType(prototype);
return arrangeFreeFunctionType(prototype, MD);
}

const CGFunctionInfo &
Expand All @@ -208,7 +236,7 @@ CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
CanQual<FunctionProtoType> FTP = GetFormalType(MD);

// Add the formal parameters.
argTypes.append(FTP->param_type_begin(), FTP->param_type_end());
appendParameterTypes(*this, argTypes, FTP, MD);

TheCXXABI.buildStructorSignature(MD, Type, argTypes);

Expand Down Expand Up @@ -274,7 +302,7 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) {
}

assert(isa<FunctionProtoType>(FTy));
return arrangeFreeFunctionType(FTy.getAs<FunctionProtoType>());
return arrangeFreeFunctionType(FTy.getAs<FunctionProtoType>(), FD);
}

/// Arrange the argument and result information for the declaration or
Expand Down Expand Up @@ -2803,6 +2831,21 @@ void CodeGenFunction::EmitCallArgs(
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
const FunctionDecl *CalleeDecl, unsigned ParamsToSkip) {
assert((int)ArgTypes.size() == (ArgRange.end() - ArgRange.begin()));

auto MaybeEmitImplicitObjectSize = [&](unsigned I, const Expr *Arg) {
if (CalleeDecl == nullptr || I >= CalleeDecl->getNumParams())
return;
auto *PS = CalleeDecl->getParamDecl(I)->getAttr<PassObjectSizeAttr>();
if (PS == nullptr)
return;

const auto &Context = getContext();
auto SizeTy = Context.getSizeType();
auto T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
llvm::Value *V = evaluateOrEmitBuiltinObjectSize(Arg, PS->getType(), T);
Args.add(RValue::get(V), SizeTy);
};

// We *have* to evaluate arguments from right to left in the MS C++ ABI,
// because arguments are destroyed left to right in the callee.
if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
Expand All @@ -2823,6 +2866,7 @@ void CodeGenFunction::EmitCallArgs(
EmitCallArg(Args, *Arg, ArgTypes[I]);
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], (*Arg)->getExprLoc(),
CalleeDecl, ParamsToSkip + I);
MaybeEmitImplicitObjectSize(I, *Arg);
}

// Un-reverse the arguments we just evaluated so they match up with the LLVM
Expand All @@ -2837,6 +2881,7 @@ void CodeGenFunction::EmitCallArgs(
EmitCallArg(Args, *Arg, ArgTypes[I]);
EmitNonNullArgCheck(Args.back().RV, ArgTypes[I], (*Arg)->getExprLoc(),
CalleeDecl, ParamsToSkip + I);
MaybeEmitImplicitObjectSize(I, *Arg);
}
}

Expand Down
10 changes: 6 additions & 4 deletions clang/lib/CodeGen/CodeGenABITypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ CodeGenABITypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
}

const CGFunctionInfo &
CodeGenABITypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty) {
return CGM->getTypes().arrangeFreeFunctionType(Ty);
CodeGenABITypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty,
const FunctionDecl *FD) {
return CGM->getTypes().arrangeFreeFunctionType(Ty, FD);
}

const CGFunctionInfo &
Expand All @@ -55,8 +56,9 @@ CodeGenABITypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty) {

const CGFunctionInfo &
CodeGenABITypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
const FunctionProtoType *FTP) {
return CGM->getTypes().arrangeCXXMethodType(RD, FTP);
const FunctionProtoType *FTP,
const CXXMethodDecl *MD) {
return CGM->getTypes().arrangeCXXMethodType(RD, FTP, MD);
}

const CGFunctionInfo &CodeGenABITypes::arrangeFreeFunctionCall(
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,18 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
CGM.getCXXABI().buildThisParam(*this, Args);
}

Args.append(FD->param_begin(), FD->param_end());
for (auto *Param : FD->params()) {
Args.push_back(Param);
if (!Param->hasAttr<PassObjectSizeAttr>())
continue;

IdentifierInfo *NoID = nullptr;
auto *Implicit = ImplicitParamDecl::Create(
getContext(), Param->getDeclContext(), Param->getLocation(), NoID,
getContext().getSizeType());
SizeArguments[Param] = Implicit;
Args.push_back(Implicit);
}

if (MD && (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)))
CGM.getCXXABI().addImplicitStructorParams(*this, ResTy, Args);
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,12 @@ class CodeGenFunction : public CodeGenTypeCache {
/// decls.
DeclMapTy LocalDeclMap;

/// SizeArguments - If a ParmVarDecl had the pass_object_size attribute, this
/// will contain a mapping from said ParmVarDecl to its implicit "object_size"
/// parameter.
llvm::SmallDenseMap<const ParmVarDecl *, const ImplicitParamDecl *, 2>
SizeArguments;

/// Track escaped local variables with auto storage. Used during SEH
/// outlining to produce a call to llvm.localescape.
llvm::DenseMap<llvm::AllocaInst *, int> EscapedLocals;
Expand Down Expand Up @@ -3062,6 +3068,18 @@ class CodeGenFunction : public CodeGenTypeCache {
std::string &ConstraintStr,
SourceLocation Loc);

/// \brief Attempts to statically evaluate the object size of E. If that
/// fails, emits code to figure the size of E out for us. This is
/// pass_object_size aware.
llvm::Value *evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
llvm::IntegerType *ResType);

/// \brief Emits the size of E, as required by __builtin_object_size. This
/// function is aware of pass_object_size parameters, and will act accordingly
/// if E is a parameter with the pass_object_size attribute.
llvm::Value *emitBuiltinObjectSize(const Expr *E, unsigned Type,
llvm::IntegerType *ResType);

public:
#ifndef NDEBUG
// Determine whether the given argument is an Objective-C method
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1830,8 +1830,11 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
bool DontDefer,
bool IsForDefinition) {
// If there was no specific requested type, just convert it now.
if (!Ty)
Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType());
if (!Ty) {
const auto *FD = cast<FunctionDecl>(GD.getDecl());
auto CanonTy = Context.getCanonicalType(FD->getType());
Ty = getTypes().ConvertFunctionType(CanonTy, FD);
}

StringRef MangledName = getMangledName(GD);
return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable, DontDefer,
Expand Down
140 changes: 72 additions & 68 deletions clang/lib/CodeGen/CodeGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,76 @@ static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
llvm_unreachable("Unknown float format!");
}

llvm::Type *CodeGenTypes::ConvertFunctionType(QualType QFT,
const FunctionDecl *FD) {
assert(QFT.isCanonical());
const Type *Ty = QFT.getTypePtr();
const FunctionType *FT = cast<FunctionType>(QFT.getTypePtr());
// First, check whether we can build the full function type. If the
// function type depends on an incomplete type (e.g. a struct or enum), we
// cannot lower the function type.
if (!isFuncTypeConvertible(FT)) {
// This function's type depends on an incomplete tag type.

// Force conversion of all the relevant record types, to make sure
// we re-convert the FunctionType when appropriate.
if (const RecordType *RT = FT->getReturnType()->getAs<RecordType>())
ConvertRecordDeclType(RT->getDecl());
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
for (unsigned i = 0, e = FPT->getNumParams(); i != e; i++)
if (const RecordType *RT = FPT->getParamType(i)->getAs<RecordType>())
ConvertRecordDeclType(RT->getDecl());

SkippedLayout = true;

// Return a placeholder type.
return llvm::StructType::get(getLLVMContext());
}

// While we're converting the parameter types for a function, we don't want
// to recursively convert any pointed-to structs. Converting directly-used
// structs is ok though.
if (!RecordsBeingLaidOut.insert(Ty).second) {
SkippedLayout = true;
return llvm::StructType::get(getLLVMContext());
}

// The function type can be built; call the appropriate routines to
// build it.
const CGFunctionInfo *FI;
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
FI = &arrangeFreeFunctionType(
CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)), FD);
} else {
const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(FT);
FI = &arrangeFreeFunctionType(
CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
}

llvm::Type *ResultType = nullptr;
// If there is something higher level prodding our CGFunctionInfo, then
// don't recurse into it again.
if (FunctionsBeingProcessed.count(FI)) {

ResultType = llvm::StructType::get(getLLVMContext());
SkippedLayout = true;
} else {

// Otherwise, we're good to go, go ahead and convert it.
ResultType = GetFunctionType(*FI);
}

RecordsBeingLaidOut.erase(Ty);

if (SkippedLayout)
TypeCache.clear();

if (RecordsBeingLaidOut.empty())
while (!DeferredRecords.empty())
ConvertRecordDeclType(DeferredRecords.pop_back_val());
return ResultType;
}

/// ConvertType - Convert the specified type to its LLVM form.
llvm::Type *CodeGenTypes::ConvertType(QualType T) {
T = Context.getCanonicalType(T);
Expand Down Expand Up @@ -485,75 +555,9 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
break;
}
case Type::FunctionNoProto:
case Type::FunctionProto: {
const FunctionType *FT = cast<FunctionType>(Ty);
// First, check whether we can build the full function type. If the
// function type depends on an incomplete type (e.g. a struct or enum), we
// cannot lower the function type.
if (!isFuncTypeConvertible(FT)) {
// This function's type depends on an incomplete tag type.

// Force conversion of all the relevant record types, to make sure
// we re-convert the FunctionType when appropriate.
if (const RecordType *RT = FT->getReturnType()->getAs<RecordType>())
ConvertRecordDeclType(RT->getDecl());
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
for (unsigned i = 0, e = FPT->getNumParams(); i != e; i++)
if (const RecordType *RT = FPT->getParamType(i)->getAs<RecordType>())
ConvertRecordDeclType(RT->getDecl());

// Return a placeholder type.
ResultType = llvm::StructType::get(getLLVMContext());

SkippedLayout = true;
break;
}

// While we're converting the parameter types for a function, we don't want
// to recursively convert any pointed-to structs. Converting directly-used
// structs is ok though.
if (!RecordsBeingLaidOut.insert(Ty).second) {
ResultType = llvm::StructType::get(getLLVMContext());

SkippedLayout = true;
break;
}

// The function type can be built; call the appropriate routines to
// build it.
const CGFunctionInfo *FI;
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
FI = &arrangeFreeFunctionType(
CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)));
} else {
const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(FT);
FI = &arrangeFreeFunctionType(
CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
}

// If there is something higher level prodding our CGFunctionInfo, then
// don't recurse into it again.
if (FunctionsBeingProcessed.count(FI)) {

ResultType = llvm::StructType::get(getLLVMContext());
SkippedLayout = true;
} else {

// Otherwise, we're good to go, go ahead and convert it.
ResultType = GetFunctionType(*FI);
}

RecordsBeingLaidOut.erase(Ty);

if (SkippedLayout)
TypeCache.clear();

if (RecordsBeingLaidOut.empty())
while (!DeferredRecords.empty())
ConvertRecordDeclType(DeferredRecords.pop_back_val());
case Type::FunctionProto:
ResultType = ConvertFunctionType(T);
break;
}

case Type::ObjCObject:
ResultType = ConvertType(cast<ObjCObjectType>(Ty)->getBaseType());
break;
Expand Down
15 changes: 12 additions & 3 deletions clang/lib/CodeGen/CodeGenTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ class CodeGenTypes {
/// ConvertType - Convert type T into a llvm::Type.
llvm::Type *ConvertType(QualType T);

/// \brief Converts the GlobalDecl into an llvm::Type. This should be used
/// when we know the target of the function we want to convert. This is
/// because some functions (explicitly, those with pass_object_size
/// parameters) may not have the same signature as their type portrays, and
/// can only be called directly.
llvm::Type *ConvertFunctionType(QualType FT,
const FunctionDecl *FD = nullptr);

/// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from
/// ConvertType in that it is used to convert to the memory representation for
/// a type. For example, the scalar representation for _Bool is i1, but the
Expand Down Expand Up @@ -264,11 +272,12 @@ class CodeGenTypes {
const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD,
CXXCtorType CT);

const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty);
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty,
const FunctionDecl *FD);
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty);
const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD,
const FunctionProtoType *FTP);
const FunctionProtoType *FTP,
const CXXMethodDecl *MD);

/// "Arrange" the LLVM information for a call or type with the given
/// signature. This is largely an internal method; other clients
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,9 +534,8 @@ llvm::Value *ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());

llvm::FunctionType *FTy =
CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT));
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));

llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(CGM.PtrDiffTy, 1);

Expand Down
5 changes: 2 additions & 3 deletions clang/lib/CodeGen/MicrosoftCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3225,9 +3225,8 @@ llvm::Value *MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(
const FunctionProtoType *FPT =
MPT->getPointeeType()->castAs<FunctionProtoType>();
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
llvm::FunctionType *FTy =
CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT));
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
CGBuilderTy &Builder = CGF.Builder;

MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8419,6 +8419,15 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P,
}
}
}

// Parameters with the pass_object_size attribute only need to be marked
// constant at function definitions. Because we lack information about
// whether we're on a declaration or definition when we're instantiating the
// attribute, we need to check for constness here.
if (const auto *Attr = Param->getAttr<PassObjectSizeAttr>())
if (!Param->getType().isConstQualified())
Diag(Param->getLocation(), diag::err_attribute_pointers_only)
<< Attr->getSpelling() << 1;
}

return HasInvalidParm;
Expand Down Expand Up @@ -9869,4 +9878,3 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
<< ArgumentExpr->getSourceRange()
<< TypeTagExpr->getSourceRange();
}

27 changes: 26 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2621,6 +2621,21 @@ static bool checkUsingShadowRedecl(Sema &S, UsingShadowDecl *OldS,
return false;
}

static bool hasIdenticalPassObjectSizeAttrs(const FunctionDecl *A,
const FunctionDecl *B) {
assert(A->getNumParams() == B->getNumParams());

auto AttrEq = [](const ParmVarDecl *A, const ParmVarDecl *B) {
const auto *AttrA = A->getAttr<PassObjectSizeAttr>();
const auto *AttrB = B->getAttr<PassObjectSizeAttr>();
if (AttrA == AttrB)
return true;
return AttrA && AttrB && AttrA->getType() == AttrB->getType();
};

return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq);
}

/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
Expand Down Expand Up @@ -2799,7 +2814,17 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
Old->isInlined() && !Old->hasAttr<GNUInlineAttr>()) {
UndefinedButUsed.erase(Old->getCanonicalDecl());
}


// If pass_object_size params don't match up perfectly, this isn't a valid
// redeclaration.
if (Old->getNumParams() > 0 && Old->getNumParams() == New->getNumParams() &&
!hasIdenticalPassObjectSizeAttrs(Old, New)) {
Diag(New->getLocation(), diag::err_different_pass_object_size_params)
<< New->getDeclName();
Diag(OldLocation, PrevDiag) << Old << Old->getType();
return true;
}

if (getLangOpts().CPlusPlus) {
// (C++98 13.1p2):
// Certain function declarations cannot be overloaded:
Expand Down
54 changes: 48 additions & 6 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,43 @@ static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}

static void handlePassObjectSizeAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (D->hasAttr<PassObjectSizeAttr>()) {
S.Diag(D->getLocStart(), diag::err_attribute_only_once_per_parameter)
<< Attr.getName();
return;
}

Expr *E = Attr.getArgAsExpr(0);
uint32_t Type;
if (!checkUInt32Argument(S, Attr, E, Type, /*Idx=*/1))
return;

// pass_object_size's argument is passed in as the second argument of
// __builtin_object_size. So, it has the same constraints as that second
// argument; namely, it must be in the range [0, 3].
if (Type > 3) {
S.Diag(E->getLocStart(), diag::err_attribute_argument_outof_range)
<< Attr.getName() << 0 << 3 << E->getSourceRange();
return;
}

// pass_object_size is only supported on constant pointer parameters; as a
// kindness to users, we allow the parameter to be non-const for declarations.
// At this point, we have no clue if `D` belongs to a function declaration or
// definition, so we defer the constness check until later.
if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) {
S.Diag(D->getLocStart(), diag::err_attribute_pointers_only)
<< Attr.getName() << 1;
return;
}

D->addAttr(::new (S.Context)
PassObjectSizeAttr(Attr.getRange(), S.Context, (int)Type,
Attr.getAttributeSpellingListIndex()));
}

static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
ConsumableAttr::ConsumedState DefaultState;

Expand Down Expand Up @@ -1162,10 +1199,12 @@ static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr,
SourceRange TypeRange,
bool isReturnValue = false) {
if (!S.isValidPointerAttrType(T)) {
S.Diag(Attr.getLoc(), isReturnValue
? diag::warn_attribute_return_pointers_only
: diag::warn_attribute_pointers_only)
<< Attr.getName() << AttrParmRange << TypeRange;
if (isReturnValue)
S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only)
<< Attr.getName() << AttrParmRange << TypeRange;
else
S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only)
<< Attr.getName() << AttrParmRange << TypeRange << 0;
return false;
}
return true;
Expand Down Expand Up @@ -2724,7 +2763,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,

if (prioritynum < 101 || prioritynum > 65535) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_outof_range)
<< E->getSourceRange();
<< E->getSourceRange() << Attr.getName() << 101 << 65535;
Attr.setInvalid();
return;
}
Expand Down Expand Up @@ -3862,7 +3901,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx);
if (!BufferTy->isPointerType()) {
S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only)
<< Attr.getName();
<< Attr.getName() << 0;
}
}

Expand Down Expand Up @@ -4972,6 +5011,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_CUDAConstant:
handleSimpleAttribute<CUDAConstantAttr>(S, D, Attr);
break;
case AttributeList::AT_PassObjectSize:
handlePassObjectSizeAttr(S, D, Attr);
break;
case AttributeList::AT_Constructor:
handleConstructorAttr(S, D, Attr);
break;
Expand Down
48 changes: 43 additions & 5 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ SourceRange Sema::getExprRange(Expr *E) const {
//===----------------------------------------------------------------------===//

/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4).
ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) {
ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) {
// Handle any placeholder expressions which made it here.
if (E->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
Expand All @@ -511,9 +511,16 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) {
// If we are here, we are not calling a function but taking
// its address (which is not allowed in OpenCL v1.0 s6.8.a.3).
if (getLangOpts().OpenCL) {
Diag(E->getExprLoc(), diag::err_opencl_taking_function_address);
if (Diagnose)
Diag(E->getExprLoc(), diag::err_opencl_taking_function_address);
return ExprError();
}

if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()))
if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc()))
return ExprError();

E = ImpCastExprToType(E, Context.getPointerType(Ty),
CK_FunctionToPointerDecay).get();
} else if (Ty->isArrayType()) {
Expand Down Expand Up @@ -706,8 +713,8 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
return Res;
}

ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) {
ExprResult Res = DefaultFunctionArrayConversion(E);
ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E, bool Diagnose) {
ExprResult Res = DefaultFunctionArrayConversion(E, Diagnose);
if (Res.isInvalid())
return ExprError();
Res = DefaultLvalueConversion(Res.get());
Expand Down Expand Up @@ -7338,7 +7345,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
// Suppress this for references: C++ 8.5.3p5.
if (!LHSType->isReferenceType()) {
// FIXME: We potentially allocate here even if ConvertRHS is false.
RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose);
if (RHS.isInvalid())
return Incompatible;
}
Expand Down Expand Up @@ -9882,6 +9889,12 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
// expressions here, but the result of one is always an lvalue anyway.
}
ValueDecl *dcl = getPrimaryDecl(op);

if (auto *FD = dyn_cast_or_null<FunctionDecl>(dcl))
if (!checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
op->getLocStart()))
return QualType();

Expr::LValueClassification lval = op->ClassifyLValue(Context);
unsigned AddressOfError = AO_No_Error;

Expand Down Expand Up @@ -11831,6 +11844,25 @@ Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp) {
return true;
}

static bool maybeDiagnoseAssignmentToFunction(Sema &S, QualType DstType,
const Expr *SrcExpr) {
if (!DstType->isFunctionPointerType() ||
!SrcExpr->getType()->isFunctionType())
return false;

auto *DRE = dyn_cast<DeclRefExpr>(SrcExpr->IgnoreParenImpCasts());
if (!DRE)
return false;

auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl());
if (!FD)
return false;

return !S.checkAddressOfFunctionIsAvailable(FD,
/*Complain=*/true,
SrcExpr->getLocStart());
}

bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
SourceLocation Loc,
QualType DstType, QualType SrcType,
Expand Down Expand Up @@ -11963,6 +11995,12 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
DiagKind = diag::err_arc_weak_unavailable_assign;
break;
case Incompatible:
if (maybeDiagnoseAssignmentToFunction(*this, DstType, SrcExpr)) {
if (Complained)
*Complained = true;
return true;
}

DiagKind = diag::err_typecheck_convert_incompatible;
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
MayHaveConvFixit = true;
Expand Down
28 changes: 27 additions & 1 deletion clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3011,6 +3011,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_VariableLengthArrayHasInitializer:
case FK_PlaceholderType:
case FK_ExplicitConstructor:
case FK_AddressOfUnaddressableFunction:
return false;

case FK_ReferenceInitOverloadFailed:
Expand Down Expand Up @@ -4801,6 +4802,17 @@ InitializationSequence::InitializationSequence(Sema &S,
InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList);
}

/// Tries to get a FunctionDecl out of `E`. If it succeeds and we can take the
/// address of that function, this returns true. Otherwise, it returns false.
static bool isExprAnUnaddressableFunction(Sema &S, const Expr *E) {
auto *DRE = dyn_cast<DeclRefExpr>(E);
if (!DRE || !isa<FunctionDecl>(DRE->getDecl()))
return false;

return !S.checkAddressOfFunctionIsAvailable(
cast<FunctionDecl>(DRE->getDecl()));
}

void InitializationSequence::InitializeFrom(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expand Down Expand Up @@ -4982,7 +4994,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
}

assert(S.getLangOpts().CPlusPlus);

// - If the destination type is a (possibly cv-qualified) class type:
if (DestType->isRecordType()) {
// - If the initialization is direct-initialization, or if it is
Expand Down Expand Up @@ -5079,6 +5091,9 @@ void InitializationSequence::InitializeFrom(Sema &S,
!S.ResolveAddressOfOverloadedFunction(Initializer, DestType,
false, dap))
SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else if (Initializer->getType()->isFunctionType() &&
isExprAnUnaddressableFunction(S, Initializer))
SetFailed(InitializationSequence::FK_AddressOfUnaddressableFunction);
else
SetFailed(InitializationSequence::FK_ConversionFailed);
} else {
Expand Down Expand Up @@ -6926,6 +6941,13 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}

case FK_AddressOfUnaddressableFunction: {
auto *FD = cast<FunctionDecl>(cast<DeclRefExpr>(Args[0])->getDecl());
S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
Args[0]->getLocStart());
break;
}

case FK_ReferenceInitOverloadFailed:
case FK_UserConversionOverloadFailed:
switch (FailedOverloadResult) {
Expand Down Expand Up @@ -7248,6 +7270,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "array requires initializer list";
break;

case FK_AddressOfUnaddressableFunction:
OS << "address of unaddressable function was taken";
break;

case FK_ArrayNeedsInitListOrStringLiteral:
OS << "array requires initializer list or string literal";
break;
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1141,6 +1141,12 @@ static void addFunctionPointerConversion(Sema &S,
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
// This conversion is explicitly disabled if the lambda's function has
// pass_object_size attributes on any of its parameters.
if (std::any_of(CallOperator->param_begin(), CallOperator->param_end(),
std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)))
return;

// Add the conversion to function pointer.
const FunctionProtoType *CallOpProto =
CallOperator->getType()->getAs<FunctionProtoType>();
Expand Down
192 changes: 152 additions & 40 deletions clang/lib/Sema/SemaOverload.cpp

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2748,7 +2748,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
typedef PartialSpecMatchResult MatchResult;
SmallVector<MatchResult, 4> Matched;
SourceLocation PointOfInstantiation = TemplateNameLoc;
TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation,
/*ForTakingAddress=*/false);

// 1. Attempt to find the closest partial specialization that this
// specializes, if any.
Expand Down Expand Up @@ -6822,7 +6823,8 @@ bool Sema::CheckFunctionTemplateSpecialization(
// The set of function template specializations that could match this
// explicit function template specialization.
UnresolvedSet<8> Candidates;
TemplateSpecCandidateSet FailedCandidates(FD->getLocation());
TemplateSpecCandidateSet FailedCandidates(FD->getLocation(),
/*ForTakingAddress=*/false);

llvm::SmallDenseMap<FunctionDecl *, TemplateArgumentListInfo, 8>
ConvertedTemplateArgs;
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5483,9 +5483,12 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
// Pointer type qualifiers can only operate on pointer types, but not
// pointer-to-member types.
if (!isa<PointerType>(Desugared)) {
S.Diag(Attr.getLoc(), Type->isMemberPointerType() ?
diag::err_attribute_no_member_pointers :
diag::err_attribute_pointers_only) << Attr.getName();
if (Type->isMemberPointerType())
S.Diag(Attr.getLoc(), diag::err_attribute_no_member_pointers)
<< Attr.getName();
else
S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only)
<< Attr.getName() << 0;
return true;
}

Expand Down
19 changes: 19 additions & 0 deletions clang/test/CodeGenCXX/mangle-ms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,3 +418,22 @@ void f(S::T6) {}
// X64-DAG: @"\01?f@UnnamedType@@YAXUT5@S@1@@Z"
// X64-DAG: @"\01?f@UnnamedType@@YAXPEAU<unnamed-type-T6>@S@1@@Z"
}

namespace PassObjectSize {
// NOTE: This mangling is subject to change.
// Reiterating from the comment in MicrosoftMangle, the scheme is pretend a
// parameter of type __clang::__pass_object_sizeN exists after each pass object
// size param P, where N is the Type of the pass_object_size attribute on P.
//
// e.g. we want to mangle:
// void foo(void *const __attribute__((pass_object_size(0))));
// as if it were
// namespace __clang { enum __pass_object_size0 : size_t {}; }
// void foo(void *const, __clang::__pass_object_size0);
// where __clang is a top-level namespace.

// CHECK-DAG: define i32 @"\01?foo@PassObjectSize@@YAHQAHW4__pass_object_size0@__clang@@@Z"
int foo(int *const i __attribute__((pass_object_size(0)))) { return 0; }
// CHECK-DAG: define i32 @"\01?bar@PassObjectSize@@YAHQAHW4__pass_object_size1@__clang@@@Z"
int bar(int *const i __attribute__((pass_object_size(1)))) { return 0; }
}
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/init-priority-attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Two foo __attribute__((init_priority(101))) ( 5, 6 );

Two goo __attribute__((init_priority(2,3))) ( 5, 6 ); // expected-error {{'init_priority' attribute takes one argument}}

Two coo[2] __attribute__((init_priority(3))); // expected-error {{init_priority attribute requires integer constant between 101 and 65535 inclusive}}
Two coo[2] __attribute__((init_priority(3))); // expected-error {{'init_priority' attribute requires integer constant between 101 and 65535 inclusive}}

Two koo[4] __attribute__((init_priority(1.13))); // expected-error {{'init_priority' attribute requires an integer constant}}

Expand Down