зеркало из https://github.com/microsoft/clang.git
Add the `pass_object_size` attribute to clang.
`pass_object_size` is our way of enabling `__builtin_object_size` to produce high quality results without requiring inlining to happen everywhere. A link to the design doc for this attribute is available at the Differential review link below. Differential Revision: http://reviews.llvm.org/D13263 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@254554 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
b08c74ee24
Коммит
7727f3dca1
|
@ -628,6 +628,16 @@ public:
|
|||
const FunctionDecl *Callee,
|
||||
ArrayRef<const Expr*> Args) const;
|
||||
|
||||
/// \brief If the current Expr is a pointer, this will try to statically
|
||||
/// determine the number of bytes available where the pointer is pointing.
|
||||
/// Returns true if all of the above holds and we were able to figure out the
|
||||
/// size, false otherwise.
|
||||
///
|
||||
/// \param Type - How to evaluate the size of the Expr, as defined by the
|
||||
/// "type" parameter of __builtin_object_size
|
||||
bool tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx,
|
||||
unsigned Type) const;
|
||||
|
||||
/// \brief Enumeration used to describe the kind of Null pointer constant
|
||||
/// returned from \c isNullPointerConstant().
|
||||
enum NullPointerConstantKind {
|
||||
|
|
|
@ -1012,6 +1012,15 @@ def ReturnsNonNull : InheritableAttr {
|
|||
let Documentation = [ReturnsNonNullDocs];
|
||||
}
|
||||
|
||||
// pass_object_size(N) indicates that the parameter should have
|
||||
// __builtin_object_size with Type=N evaluated on the parameter at the callsite.
|
||||
def PassObjectSize : InheritableParamAttr {
|
||||
let Spellings = [GNU<"pass_object_size">];
|
||||
let Args = [IntArgument<"Type">];
|
||||
let Subjects = SubjectList<[ParmVar]>;
|
||||
let Documentation = [PassObjectSizeDocs];
|
||||
}
|
||||
|
||||
// Nullability type attributes.
|
||||
def TypeNonNull : TypeAttr {
|
||||
let Spellings = [Keyword<"_Nonnull">];
|
||||
|
|
|
@ -263,6 +263,103 @@ Query for this feature with ``__has_attribute(enable_if)``.
|
|||
}];
|
||||
}
|
||||
|
||||
def PassObjectSizeDocs : Documentation {
|
||||
let Category = DocCatVariable; // Technically it's a parameter doc, but eh.
|
||||
let Content = [{
|
||||
.. Note:: The mangling of functions with parameters that are annotated with
|
||||
``pass_object_size`` is subject to change. You can get around this by
|
||||
using ``__asm__("foo")`` to explicitly name your functions, thus preserving
|
||||
your ABI; also, non-overloadable C functions with ``pass_object_size`` are
|
||||
not mangled.
|
||||
|
||||
The ``pass_object_size(Type)`` attribute can be placed on function parameters to
|
||||
instruct clang to call ``__builtin_object_size(param, Type)`` at each callsite
|
||||
of said function, and implicitly pass the result of this call in as an invisible
|
||||
argument of type ``size_t`` directly after the parameter annotated with
|
||||
``pass_object_size``. Clang will also replace any calls to
|
||||
``__builtin_object_size(param, Type)`` in the function by said implicit
|
||||
parameter.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int bzero1(char *const p __attribute__((pass_object_size(0))))
|
||||
__attribute__((noinline)) {
|
||||
int i = 0;
|
||||
for (/**/; i < (int)__builtin_object_size(p, 0); ++i) {
|
||||
p[i] = 0;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int main() {
|
||||
char chars[100];
|
||||
int n = bzero1(&chars[0]);
|
||||
assert(n == sizeof(chars));
|
||||
return 0;
|
||||
}
|
||||
|
||||
If successfully evaluating ``__builtin_object_size(param, Type)`` at the
|
||||
callsite is not possible, then the "failed" value is passed in. So, using the
|
||||
definition of ``bzero1`` from above, the following code would exit cleanly:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int main2(int argc, char *argv[]) {
|
||||
int n = bzero1(argv);
|
||||
assert(n == -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
``pass_object_size`` plays a part in overload resolution. If two overload
|
||||
candidates are otherwise equally good, then the overload with one or more
|
||||
parameters with ``pass_object_size`` is preferred. This implies that the choice
|
||||
between two identical overloads both with ``pass_object_size`` on one or more
|
||||
parameters will always be ambiguous; for this reason, having two such overloads
|
||||
is illegal. For example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#define PS(N) __attribute__((pass_object_size(N)))
|
||||
// OK
|
||||
void Foo(char *a, char *b); // Overload A
|
||||
// OK -- overload A has no parameters with pass_object_size.
|
||||
void Foo(char *a PS(0), char *b PS(0)); // Overload B
|
||||
// Error -- Same signature (sans pass_object_size) as overload B, and both
|
||||
// overloads have one or more parameters with the pass_object_size attribute.
|
||||
void Foo(void *a PS(0), void *b);
|
||||
|
||||
// OK
|
||||
void Bar(void *a PS(0)); // Overload C
|
||||
// OK
|
||||
void Bar(char *c PS(1)); // Overload D
|
||||
|
||||
void main() {
|
||||
char known[10], *unknown;
|
||||
Foo(unknown, unknown); // Calls overload B
|
||||
Foo(known, unknown); // Calls overload B
|
||||
Foo(unknown, known); // Calls overload B
|
||||
Foo(known, known); // Calls overload B
|
||||
|
||||
Bar(known); // Calls overload D
|
||||
Bar(unknown); // Calls overload D
|
||||
}
|
||||
|
||||
Currently, ``pass_object_size`` is a bit restricted in terms of its usage:
|
||||
|
||||
* Only one use of ``pass_object_size`` is allowed per parameter.
|
||||
|
||||
* It is an error to take the address of a function with ``pass_object_size`` on
|
||||
any of its parameters. If you wish to do this, you can create an overload
|
||||
without ``pass_object_size`` on any parameters.
|
||||
|
||||
* It is an error to apply the ``pass_object_size`` attribute to parameters that
|
||||
are not pointers. Additionally, any parameter that ``pass_object_size`` is
|
||||
applied to must be marked ``const`` at its function's definition.
|
||||
}];
|
||||
}
|
||||
|
||||
def OverloadableDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
|
|
@ -1567,8 +1567,7 @@ def err_init_conversion_failed : Error<
|
|||
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
|
||||
"volatile and restrict|const, volatile, and restrict}5 vs "
|
||||
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
|
||||
"volatile and restrict|const, volatile, and restrict}6)"
|
||||
"|: cannot take the address of a potentially disabled function}4">;
|
||||
"volatile and restrict|const, volatile, and restrict}6)}4">;
|
||||
|
||||
def err_lvalue_to_rvalue_ref : Error<"rvalue reference %diff{to type $ cannot "
|
||||
"bind to lvalue of type $|cannot bind to incompatible lvalue}0,1">;
|
||||
|
@ -2126,8 +2125,7 @@ def err_attribute_argument_type : Error<
|
|||
"%0 attribute requires %select{int or bool|an integer "
|
||||
"constant|a string|an identifier}1">;
|
||||
def err_attribute_argument_outof_range : Error<
|
||||
"init_priority attribute requires integer constant between "
|
||||
"101 and 65535 inclusive">;
|
||||
"%0 attribute requires integer constant between %1 and %2 inclusive">;
|
||||
def err_init_priority_object_attr : Error<
|
||||
"can only use 'init_priority' attribute on file-scope definitions "
|
||||
"of objects of class type">;
|
||||
|
@ -2135,10 +2133,12 @@ def err_attribute_argument_vec_type_hint : Error<
|
|||
"invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
|
||||
def err_attribute_argument_out_of_bounds : Error<
|
||||
"%0 attribute parameter %1 is out of bounds">;
|
||||
def err_attribute_only_once_per_parameter : Error<
|
||||
"%0 attribute can only be applied once per parameter">;
|
||||
def err_attribute_uuid_malformed_guid : Error<
|
||||
"uuid attribute contains a malformed GUID">;
|
||||
def warn_attribute_pointers_only : Warning<
|
||||
"%0 attribute only applies to pointer arguments">,
|
||||
"%0 attribute only applies to%select{| constant}1 pointer arguments">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def err_attribute_pointers_only : Error<warn_attribute_pointers_only.Text>;
|
||||
def warn_attribute_return_pointers_only : Warning<
|
||||
|
@ -3063,8 +3063,7 @@ def note_ovl_candidate : Note<"candidate "
|
|||
"%select{none|const|restrict|const and restrict|volatile|const and volatile"
|
||||
"|volatile and restrict|const, volatile, and restrict}3 but found "
|
||||
"%select{none|const|restrict|const and restrict|volatile|const and volatile"
|
||||
"|volatile and restrict|const, volatile, and restrict}4)"
|
||||
"| made ineligible by enable_if}2">;
|
||||
"|volatile and restrict|const, volatile, and restrict}4)}2">;
|
||||
|
||||
def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
|
||||
def note_ovl_candidate_illegal_constructor : Note<
|
||||
|
@ -3093,8 +3092,16 @@ def note_ovl_candidate_substitution_failure : Note<
|
|||
"candidate template ignored: substitution failure%0%1">;
|
||||
def note_ovl_candidate_disabled_by_enable_if : Note<
|
||||
"candidate template ignored: disabled by %0%1">;
|
||||
def note_ovl_candidate_has_pass_object_size_params: Note<
|
||||
"candidate address cannot be taken because parameter %0 has "
|
||||
"pass_object_size attribute">;
|
||||
def note_ovl_candidate_disabled_by_enable_if_attr : Note<
|
||||
"candidate disabled: %0">;
|
||||
def err_addrof_function_disabled_by_enable_if_attr : Error<
|
||||
"cannot take address of function %0 becuase it has one or more "
|
||||
"non-tautological enable_if conditions">;
|
||||
def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note<
|
||||
"candidate function made ineligible by enable_if">;
|
||||
def note_ovl_candidate_failed_overload_resolution : Note<
|
||||
"candidate template ignored: couldn't resolve reference to overloaded "
|
||||
"function %0">;
|
||||
|
@ -3105,7 +3112,7 @@ def note_ovl_candidate_non_deduced_mismatch : Note<
|
|||
// can handle that case properly.
|
||||
def note_ovl_candidate_non_deduced_mismatch_qualified : Note<
|
||||
"candidate template ignored: could not match %q0 against %q1">;
|
||||
|
||||
|
||||
// Note that we don't treat templates differently for this diagnostic.
|
||||
def note_ovl_candidate_arity : Note<"candidate "
|
||||
"%select{function|function|constructor|function|function|constructor|"
|
||||
|
@ -4245,6 +4252,8 @@ def err_dependent_tag_decl : Error<
|
|||
def err_tag_definition_of_typedef : Error<
|
||||
"definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">;
|
||||
def err_conflicting_types : Error<"conflicting types for %0">;
|
||||
def err_different_pass_object_size_params : Error<
|
||||
"conflicting pass_object_size attributes on parameters">;
|
||||
def err_nested_redefinition : Error<"nested redefinition of %0">;
|
||||
def err_use_with_wrong_tag : Error<
|
||||
"use of %0 with tag type that does not match previous declaration">;
|
||||
|
@ -5209,6 +5218,9 @@ def err_unqualified_pointer_member_function : Error<
|
|||
"must explicitly qualify name of member function when taking its address">;
|
||||
def err_invalid_form_pointer_member_function : Error<
|
||||
"cannot create a non-constant pointer to member function">;
|
||||
def err_address_of_function_with_pass_object_size_params: Error<
|
||||
"cannot take address of function %0 because parameter %1 has "
|
||||
"pass_object_size attribute">;
|
||||
def err_parens_pointer_member_function : Error<
|
||||
"cannot parenthesize the name of a method when forming a member pointer">;
|
||||
def err_typecheck_invalid_lvalue_addrof_addrof_function : Error<
|
||||
|
@ -5793,8 +5805,7 @@ def note_hidden_overloaded_virtual_declared_here : Note<
|
|||
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
|
||||
"volatile and restrict|const, volatile, and restrict}2 vs "
|
||||
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
|
||||
"volatile and restrict|const, volatile, and restrict}3)"
|
||||
"|: mismatch in enable_if attributes}1">;
|
||||
"volatile and restrict|const, volatile, and restrict}3)}1">;
|
||||
def warn_using_directive_in_header : Warning<
|
||||
"using namespace directive in global context in header">,
|
||||
InGroup<HeaderHygiene>, DefaultIgnore;
|
||||
|
@ -6031,8 +6042,7 @@ def err_typecheck_convert_incompatible : Error<
|
|||
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
|
||||
"volatile and restrict|const, volatile, and restrict}5 vs "
|
||||
"%select{none|const|restrict|const and restrict|volatile|const and volatile|"
|
||||
"volatile and restrict|const, volatile, and restrict}6)"
|
||||
"|: cannot take the address of a potentially disabled function}4">;
|
||||
"volatile and restrict|const, volatile, and restrict}6)}4">;
|
||||
def err_typecheck_missing_return_type_incompatible : Error<
|
||||
"%diff{return type $ must match previous return type $|"
|
||||
"return type must match previous return type}0,1 when %select{block "
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace llvm {
|
|||
namespace clang {
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
class CXXMethodDecl;
|
||||
class CodeGenOptions;
|
||||
class CoverageSourceInfo;
|
||||
class DiagnosticsEngine;
|
||||
|
@ -60,12 +61,13 @@ public:
|
|||
const CGFunctionInfo &arrangeObjCMessageSendSignature(
|
||||
const ObjCMethodDecl *MD,
|
||||
QualType receiverType);
|
||||
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);
|
||||
const CGFunctionInfo &arrangeFreeFunctionCall(CanQualType returnType,
|
||||
ArrayRef<CanQualType> argTypes,
|
||||
FunctionType::ExtInfo info,
|
||||
|
|
|
@ -828,6 +828,9 @@ public:
|
|||
/// \brief Initializer has a placeholder type which cannot be
|
||||
/// resolved by initialization.
|
||||
FK_PlaceholderType,
|
||||
/// \brief Trying to take the address of a function that doesn't support
|
||||
/// having its address taken.
|
||||
FK_AddressOfUnaddressableFunction,
|
||||
/// \brief List-copy-initialization chose an explicit constructor.
|
||||
FK_ExplicitConstructor
|
||||
};
|
||||
|
|
|
@ -145,6 +145,7 @@ namespace clang {
|
|||
class ObjCProtocolDecl;
|
||||
class OMPThreadPrivateDecl;
|
||||
class OMPClause;
|
||||
struct OverloadCandidate;
|
||||
class OverloadCandidateSet;
|
||||
class OverloadExpr;
|
||||
class ParenListExpr;
|
||||
|
@ -2475,6 +2476,14 @@ public:
|
|||
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
||||
bool MissingImplicitThis = false);
|
||||
|
||||
/// Returns whether the given function's address can be taken or not,
|
||||
/// optionally emitting a diagnostic if the address can't be taken.
|
||||
///
|
||||
/// Returns false if taking the address of the function is illegal.
|
||||
bool checkAddressOfFunctionIsAvailable(const FunctionDecl *Function,
|
||||
bool Complain = false,
|
||||
SourceLocation Loc = SourceLocation());
|
||||
|
||||
// [PossiblyAFunctionType] --> [Return]
|
||||
// NonFunctionType --> NonFunctionType
|
||||
// R (A) --> R(A)
|
||||
|
@ -8187,12 +8196,13 @@ public:
|
|||
|
||||
// DefaultFunctionArrayConversion - converts functions and arrays
|
||||
// to their respective pointers (C99 6.3.2.1).
|
||||
ExprResult DefaultFunctionArrayConversion(Expr *E);
|
||||
ExprResult DefaultFunctionArrayConversion(Expr *E, bool Diagnose = true);
|
||||
|
||||
// DefaultFunctionArrayLvalueConversion - converts functions and
|
||||
// arrays to their respective pointers and performs the
|
||||
// lvalue-to-rvalue conversion.
|
||||
ExprResult DefaultFunctionArrayLvalueConversion(Expr *E);
|
||||
ExprResult DefaultFunctionArrayLvalueConversion(Expr *E,
|
||||
bool Diagnose = true);
|
||||
|
||||
// DefaultLvalueConversion - performs lvalue-to-rvalue conversion on
|
||||
// the operand. This is DefaultFunctionArrayLvalueConversion,
|
||||
|
|
|
@ -236,7 +236,7 @@ struct TemplateSpecCandidate {
|
|||
}
|
||||
|
||||
/// Diagnose a template argument deduction failure.
|
||||
void NoteDeductionFailure(Sema &S);
|
||||
void NoteDeductionFailure(Sema &S, bool ForTakingAddress);
|
||||
};
|
||||
|
||||
/// TemplateSpecCandidateSet - A set of generalized overload candidates,
|
||||
|
@ -246,6 +246,10 @@ struct TemplateSpecCandidate {
|
|||
class TemplateSpecCandidateSet {
|
||||
SmallVector<TemplateSpecCandidate, 16> Candidates;
|
||||
SourceLocation Loc;
|
||||
// Stores whether we're taking the address of these candidates. This helps us
|
||||
// produce better error messages when dealing with the pass_object_size
|
||||
// attribute on parameters.
|
||||
bool ForTakingAddress;
|
||||
|
||||
TemplateSpecCandidateSet(
|
||||
const TemplateSpecCandidateSet &) = delete;
|
||||
|
@ -254,7 +258,8 @@ class TemplateSpecCandidateSet {
|
|||
void destroyCandidates();
|
||||
|
||||
public:
|
||||
TemplateSpecCandidateSet(SourceLocation Loc) : Loc(Loc) {}
|
||||
TemplateSpecCandidateSet(SourceLocation Loc, bool ForTakingAddress = false)
|
||||
: Loc(Loc), ForTakingAddress(ForTakingAddress) {}
|
||||
~TemplateSpecCandidateSet() { destroyCandidates(); }
|
||||
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -377,8 +377,8 @@ private:
|
|||
|
||||
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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -4228,4 +4241,3 @@ ItaniumMangleContext *
|
|||
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
|
||||
return new ItaniumMangleContextImpl(Context, Diags);
|
||||
}
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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) {
|
||||
|
@ -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");
|
||||
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.
|
||||
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}));
|
||||
// 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));
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 &
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 &
|
||||
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -914,6 +914,12 @@ private:
|
|||
/// 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;
|
||||
|
@ -3062,6 +3068,18 @@ private:
|
|||
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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
@ -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;
|
||||
|
|
|
@ -178,6 +178,14 @@ public:
|
|||
/// 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
|
||||
|
@ -264,11 +272,12 @@ public:
|
|||
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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
@ -9869,4 +9878,3 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
|
|||
<< ArgumentExpr->getSourceRange()
|
||||
<< TypeTagExpr->getSourceRange();
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
@ -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()) {
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -38,6 +38,11 @@
|
|||
using namespace clang;
|
||||
using namespace sema;
|
||||
|
||||
static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) {
|
||||
return std::any_of(FD->param_begin(), FD->param_end(),
|
||||
std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>));
|
||||
}
|
||||
|
||||
/// A convenience routine for creating a decayed reference to a function.
|
||||
static ExprResult
|
||||
CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
|
||||
|
@ -60,12 +65,8 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
|
|||
DRE->setHadMultipleCandidates(true);
|
||||
|
||||
S.MarkDeclRefReferenced(DRE);
|
||||
|
||||
ExprResult E = DRE;
|
||||
E = S.DefaultFunctionArrayConversion(E.get());
|
||||
if (E.isInvalid())
|
||||
return ExprError();
|
||||
return E;
|
||||
return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
|
||||
CK_FunctionToPointerDecay);
|
||||
}
|
||||
|
||||
static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
|
||||
|
@ -1062,6 +1063,14 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
|
|||
return true;
|
||||
}
|
||||
|
||||
// Though pass_object_size is placed on parameters and takes an argument, we
|
||||
// consider it to be a function-level modifier for the sake of function
|
||||
// identity. Either the function has one or more parameters with
|
||||
// pass_object_size or it doesn't.
|
||||
if (functionHasPassObjectSizeParams(New) !=
|
||||
functionHasPassObjectSizeParams(Old))
|
||||
return true;
|
||||
|
||||
// enable_if attributes are an order-sensitive part of the signature.
|
||||
for (specific_attr_iterator<EnableIfAttr>
|
||||
NewI = New->specific_attr_begin<EnableIfAttr>(),
|
||||
|
@ -1548,6 +1557,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
|
|||
// Function-to-pointer conversion (C++ 4.3).
|
||||
SCS.First = ICK_Function_To_Pointer;
|
||||
|
||||
if (auto *DRE = dyn_cast<DeclRefExpr>(From->IgnoreParenCasts()))
|
||||
if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()))
|
||||
if (!S.checkAddressOfFunctionIsAvailable(FD))
|
||||
return false;
|
||||
|
||||
// An lvalue of function type T can be converted to an rvalue of
|
||||
// type "pointer to T." The result is a pointer to the
|
||||
// function. (C++ 4.3p1).
|
||||
|
@ -2508,10 +2522,21 @@ enum {
|
|||
ft_parameter_arity,
|
||||
ft_parameter_mismatch,
|
||||
ft_return_type,
|
||||
ft_qualifer_mismatch,
|
||||
ft_addr_enable_if
|
||||
ft_qualifer_mismatch
|
||||
};
|
||||
|
||||
/// Attempts to get the FunctionProtoType from a Type. Handles
|
||||
/// MemberFunctionPointers properly.
|
||||
static const FunctionProtoType *tryGetFunctionProtoType(QualType FromType) {
|
||||
if (auto *FPT = FromType->getAs<FunctionProtoType>())
|
||||
return FPT;
|
||||
|
||||
if (auto *MPT = FromType->getAs<MemberPointerType>())
|
||||
return MPT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// HandleFunctionTypeMismatch - Gives diagnostic information for differeing
|
||||
/// function types. Catches different number of parameter, mismatch in
|
||||
/// parameter types, and different return types.
|
||||
|
@ -2558,8 +2583,8 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
|
|||
return;
|
||||
}
|
||||
|
||||
const FunctionProtoType *FromFunction = FromType->getAs<FunctionProtoType>(),
|
||||
*ToFunction = ToType->getAs<FunctionProtoType>();
|
||||
const FunctionProtoType *FromFunction = tryGetFunctionProtoType(FromType),
|
||||
*ToFunction = tryGetFunctionProtoType(ToType);
|
||||
|
||||
// Both types need to be function types.
|
||||
if (!FromFunction || !ToFunction) {
|
||||
|
@ -8572,7 +8597,11 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
|
|||
S.IdentifyCUDAPreference(Caller, Cand2.Function);
|
||||
}
|
||||
|
||||
return false;
|
||||
bool HasPS1 = Cand1.Function != nullptr &&
|
||||
functionHasPassObjectSizeParams(Cand1.Function);
|
||||
bool HasPS2 = Cand2.Function != nullptr &&
|
||||
functionHasPassObjectSizeParams(Cand2.Function);
|
||||
return HasPS1 != HasPS2 && HasPS1;
|
||||
}
|
||||
|
||||
/// Determine whether two declarations are "equivalent" for the purposes of
|
||||
|
@ -8642,9 +8671,6 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
|
|||
}
|
||||
}
|
||||
|
||||
static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
||||
unsigned NumArgs);
|
||||
|
||||
/// \brief Computes the best viable function (C++ 13.3.3)
|
||||
/// within an overload candidate set.
|
||||
///
|
||||
|
@ -8794,17 +8820,75 @@ static bool isFunctionAlwaysEnabled(const ASTContext &Ctx,
|
|||
return true;
|
||||
}
|
||||
|
||||
/// \brief Returns true if we can take the address of the function.
|
||||
///
|
||||
/// \param Complain - If true, we'll emit a diagnostic
|
||||
/// \param InOverloadResolution - For the purposes of emitting a diagnostic, are
|
||||
/// we in overload resolution?
|
||||
/// \param Loc - The location of the statement we're complaining about. Ignored
|
||||
/// if we're not complaining, or if we're in overload resolution.
|
||||
static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
|
||||
bool Complain,
|
||||
bool InOverloadResolution,
|
||||
SourceLocation Loc) {
|
||||
if (!isFunctionAlwaysEnabled(S.Context, FD)) {
|
||||
if (Complain) {
|
||||
// FIXME(gbiv): Both diagnostics below lack tests. We should add tests.
|
||||
if (InOverloadResolution)
|
||||
S.Diag(FD->getLocStart(),
|
||||
diag::note_addrof_ovl_candidate_disabled_by_enable_if_attr);
|
||||
else
|
||||
S.Diag(Loc, diag::err_addrof_function_disabled_by_enable_if_attr) << FD;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto I = std::find_if(FD->param_begin(), FD->param_end(),
|
||||
std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>));
|
||||
if (I == FD->param_end())
|
||||
return true;
|
||||
|
||||
if (Complain) {
|
||||
// Add one to ParamNo because it's user-facing
|
||||
unsigned ParamNo = std::distance(FD->param_begin(), I) + 1;
|
||||
if (InOverloadResolution)
|
||||
S.Diag(FD->getLocation(),
|
||||
diag::note_ovl_candidate_has_pass_object_size_params)
|
||||
<< ParamNo;
|
||||
else
|
||||
S.Diag(Loc, diag::err_address_of_function_with_pass_object_size_params)
|
||||
<< FD << ParamNo;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool checkAddressOfCandidateIsAvailable(Sema &S,
|
||||
const FunctionDecl *FD) {
|
||||
return checkAddressOfFunctionIsAvailable(S, FD, /*Complain=*/true,
|
||||
/*InOverloadResolution=*/true,
|
||||
/*Loc=*/SourceLocation());
|
||||
}
|
||||
|
||||
bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function,
|
||||
bool Complain,
|
||||
SourceLocation Loc) {
|
||||
return ::checkAddressOfFunctionIsAvailable(*this, Function, Complain,
|
||||
/*InOverloadResolution=*/false,
|
||||
Loc);
|
||||
}
|
||||
|
||||
// Notes the location of an overload candidate.
|
||||
void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType,
|
||||
bool TakingAddress) {
|
||||
if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn))
|
||||
return;
|
||||
|
||||
std::string FnDesc;
|
||||
OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc);
|
||||
PartialDiagnostic PD = PDiag(diag::note_ovl_candidate)
|
||||
<< (unsigned) K << FnDesc;
|
||||
if (TakingAddress && !isFunctionAlwaysEnabled(Context, Fn))
|
||||
PD << ft_addr_enable_if;
|
||||
else
|
||||
HandleFunctionTypeMismatch(PD, Fn->getType(), DestType);
|
||||
|
||||
HandleFunctionTypeMismatch(PD, Fn->getType(), DestType);
|
||||
Diag(Fn->getLocation(), PD);
|
||||
MaybeEmitInheritedConstructorNote(*this, Fn);
|
||||
}
|
||||
|
@ -8858,7 +8942,7 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion(
|
|||
}
|
||||
|
||||
static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
|
||||
unsigned I) {
|
||||
unsigned I, bool TakingCandidateAddress) {
|
||||
const ImplicitConversionSequence &Conv = Cand->Conversions[I];
|
||||
assert(Conv.isBad());
|
||||
assert(Cand->Function && "for now, candidate must be a function");
|
||||
|
@ -9056,7 +9140,11 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (TakingCandidateAddress &&
|
||||
!checkAddressOfCandidateIsAvailable(S, Cand->Function))
|
||||
return;
|
||||
|
||||
// Emit the generic diagnostic and, optionally, add the hints to it.
|
||||
PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv);
|
||||
FDiag << (unsigned) FnKind << FnDesc
|
||||
|
@ -9167,7 +9255,8 @@ static TemplateDecl *getDescribedTemplate(Decl *Templated) {
|
|||
/// Diagnose a failed template-argument deduction.
|
||||
static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
|
||||
DeductionFailureInfo &DeductionFailure,
|
||||
unsigned NumArgs) {
|
||||
unsigned NumArgs,
|
||||
bool TakingCandidateAddress) {
|
||||
TemplateParameter Param = DeductionFailure.getTemplateParameter();
|
||||
NamedDecl *ParamD;
|
||||
(ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
|
||||
|
@ -9335,6 +9424,11 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TakingCandidateAddress && isa<FunctionDecl>(Templated) &&
|
||||
!checkAddressOfCandidateIsAvailable(S, cast<FunctionDecl>(Templated)))
|
||||
return;
|
||||
|
||||
// FIXME: For generic lambda parameters, check if the function is a lambda
|
||||
// call operator, and if so, emit a prettier and more informative
|
||||
// diagnostic that mentions 'auto' and lambda in addition to
|
||||
|
@ -9355,14 +9449,15 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
|
|||
|
||||
/// Diagnose a failed template-argument deduction, for function calls.
|
||||
static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
|
||||
unsigned NumArgs) {
|
||||
unsigned NumArgs,
|
||||
bool TakingCandidateAddress) {
|
||||
unsigned TDK = Cand->DeductionFailure.Result;
|
||||
if (TDK == Sema::TDK_TooFewArguments || TDK == Sema::TDK_TooManyArguments) {
|
||||
if (CheckArityMismatch(S, Cand, NumArgs))
|
||||
return;
|
||||
}
|
||||
DiagnoseBadDeduction(S, Cand->Function, // pattern
|
||||
Cand->DeductionFailure, NumArgs);
|
||||
Cand->DeductionFailure, NumArgs, TakingCandidateAddress);
|
||||
}
|
||||
|
||||
/// CUDA: diagnose an invalid call across targets.
|
||||
|
@ -9443,7 +9538,8 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
|
|||
/// more richly for those diagnostic clients that cared, but we'd
|
||||
/// still have to be just as careful with the default diagnostics.
|
||||
static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
||||
unsigned NumArgs) {
|
||||
unsigned NumArgs,
|
||||
bool TakingCandidateAddress) {
|
||||
FunctionDecl *Fn = Cand->Function;
|
||||
|
||||
// Note deleted candidates, but only if they're viable.
|
||||
|
@ -9471,7 +9567,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
|||
return DiagnoseArityMismatch(S, Cand, NumArgs);
|
||||
|
||||
case ovl_fail_bad_deduction:
|
||||
return DiagnoseBadDeduction(S, Cand, NumArgs);
|
||||
return DiagnoseBadDeduction(S, Cand, NumArgs, TakingCandidateAddress);
|
||||
|
||||
case ovl_fail_illegal_constructor: {
|
||||
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor)
|
||||
|
@ -9489,7 +9585,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
|||
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
|
||||
for (unsigned N = Cand->NumConversions; I != N; ++I)
|
||||
if (Cand->Conversions[I].isBad())
|
||||
return DiagnoseBadConversion(S, Cand, I);
|
||||
return DiagnoseBadConversion(S, Cand, I, TakingCandidateAddress);
|
||||
|
||||
// FIXME: this currently happens when we're called from SemaInit
|
||||
// when user-conversion overload fails. Figure out how to handle
|
||||
|
@ -9860,7 +9956,8 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
|
|||
++CandsShown;
|
||||
|
||||
if (Cand->Function)
|
||||
NoteFunctionCandidate(S, Cand, Args.size());
|
||||
NoteFunctionCandidate(S, Cand, Args.size(),
|
||||
/*TakingCandidateAddress=*/false);
|
||||
else if (Cand->IsSurrogate)
|
||||
NoteSurrogateCandidate(S, Cand);
|
||||
else {
|
||||
|
@ -9928,9 +10025,10 @@ struct CompareTemplateSpecCandidatesForDisplay {
|
|||
/// Diagnose a template argument deduction failure.
|
||||
/// We are treating these failures as overload failures due to bad
|
||||
/// deductions.
|
||||
void TemplateSpecCandidate::NoteDeductionFailure(Sema &S) {
|
||||
void TemplateSpecCandidate::NoteDeductionFailure(Sema &S,
|
||||
bool ForTakingAddress) {
|
||||
DiagnoseBadDeduction(S, Specialization, // pattern
|
||||
DeductionFailure, /*NumArgs=*/0);
|
||||
DeductionFailure, /*NumArgs=*/0, ForTakingAddress);
|
||||
}
|
||||
|
||||
void TemplateSpecCandidateSet::destroyCandidates() {
|
||||
|
@ -9983,7 +10081,7 @@ void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) {
|
|||
|
||||
assert(Cand->Specialization &&
|
||||
"Non-matching built-in candidates are not added to Cands.");
|
||||
Cand->NoteDeductionFailure(S);
|
||||
Cand->NoteDeductionFailure(S, ForTakingAddress);
|
||||
}
|
||||
|
||||
if (I != E)
|
||||
|
@ -10048,7 +10146,7 @@ public:
|
|||
HasComplained(false),
|
||||
OvlExprInfo(OverloadExpr::find(SourceExpr)),
|
||||
OvlExpr(OvlExprInfo.Expression),
|
||||
FailedCandidates(OvlExpr->getNameLoc()) {
|
||||
FailedCandidates(OvlExpr->getNameLoc(), /*ForTakingAddress=*/true) {
|
||||
ExtractUnqualifiedFunctionTypeFromTargetType();
|
||||
|
||||
if (TargetFunctionType->isFunctionType()) {
|
||||
|
@ -10182,10 +10280,9 @@ private:
|
|||
Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl());
|
||||
assert(S.isSameOrCompatibleFunctionType(
|
||||
Context.getCanonicalType(Specialization->getType()),
|
||||
Context.getCanonicalType(TargetFunctionType)) ||
|
||||
(!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType()));
|
||||
Context.getCanonicalType(TargetFunctionType)));
|
||||
|
||||
if (!isFunctionAlwaysEnabled(S.Context, Specialization))
|
||||
if (!S.checkAddressOfFunctionIsAvailable(Specialization))
|
||||
return false;
|
||||
|
||||
Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
|
||||
|
@ -10218,7 +10315,7 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!isFunctionAlwaysEnabled(S.Context, FunDecl))
|
||||
if (!S.checkAddressOfFunctionIsAvailable(FunDecl))
|
||||
return false;
|
||||
|
||||
QualType ResultTy;
|
||||
|
@ -10341,8 +10438,9 @@ public:
|
|||
I != IEnd; ++I)
|
||||
if (FunctionDecl *Fun =
|
||||
dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
|
||||
S.NoteOverloadCandidate(Fun, TargetFunctionType,
|
||||
/*TakingAddress=*/true);
|
||||
if (!functionHasPassObjectSizeParams(Fun))
|
||||
S.NoteOverloadCandidate(Fun, TargetFunctionType,
|
||||
/*TakingAddress=*/true);
|
||||
FailedCandidates.NoteCandidates(S, OvlExpr->getLocStart());
|
||||
}
|
||||
}
|
||||
|
@ -11052,9 +11150,23 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
|
|||
if (!Recovery.isInvalid())
|
||||
return Recovery;
|
||||
|
||||
SemaRef.Diag(Fn->getLocStart(),
|
||||
diag::err_ovl_no_viable_function_in_call)
|
||||
<< ULE->getName() << Fn->getSourceRange();
|
||||
// If the user passes in a function that we can't take the address of, we
|
||||
// generally end up emitting really bad error messages. Here, we attempt to
|
||||
// emit better ones.
|
||||
for (const Expr *Arg : Args) {
|
||||
if (!Arg->getType()->isFunctionType())
|
||||
continue;
|
||||
if (auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenImpCasts())) {
|
||||
auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl());
|
||||
if (FD &&
|
||||
!SemaRef.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
|
||||
Arg->getExprLoc()))
|
||||
return ExprError();
|
||||
}
|
||||
}
|
||||
|
||||
SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_no_viable_function_in_call)
|
||||
<< ULE->getName() << Fn->getSourceRange();
|
||||
CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче