https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/78035
>From 33af5fc0a2e1ec2168a1609508cb119034801908 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Sat, 13 Jan 2024 10:48:21 +0000 Subject: [PATCH] [SemaCXX] Make __builtin_addressof more like std::addressof Properly disable __builtin_addressof(f) where f is an overloaded function and __builtin_addressof(temporary). __builtin_addressof(E) should now only work if E is bindable to an lvalue reference with the same type. --- clang/include/clang/Sema/Sema.h | 3 ++- clang/lib/Sema/SemaChecking.cpp | 3 ++- clang/lib/Sema/SemaExpr.cpp | 26 +++++++++++++++------- clang/test/SemaCXX/builtins.cpp | 38 ++++++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b55f7584913b46..67627a338a6268 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5802,7 +5802,8 @@ class Sema final { const Expr *Op, const CXXMethodDecl *MD); - QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc); + QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc, + bool IsBuiltinAddressof = false); bool CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ace3e386988f00..31f60b10e09f96 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -242,7 +242,8 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { return true; ExprResult Arg(TheCall->getArg(0)); - QualType ResultType = S.CheckAddressOfOperand(Arg, TheCall->getBeginLoc()); + QualType ResultType = S.CheckAddressOfOperand(Arg, TheCall->getBeginLoc(), + /*IsBuiltinAddressof=*/true); if (ResultType.isNull()) return true; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2aa192c3909cbe..13c00c9bf970ed 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15015,9 +15015,15 @@ bool Sema::CheckUseOfCXXMethodAsAddressOfOperand(SourceLocation OpLoc, /// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. /// In C++, the operand might be an overloaded function name, in which case /// we allow the '&' but retain the overloaded-function type. -QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { +/// If IsBuiltinAddressof is true, this is spelt __builtin_addressof(E) +/// instead of &E. +QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc, + bool IsBuiltinAddressof) { if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){ if (PTy->getKind() == BuiltinType::Overload) { + if (IsBuiltinAddressof) + return QualType(); + Expr *E = OrigOp.get()->IgnoreParens(); if (!isa<OverloadExpr>(E)) { assert(cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf); @@ -15071,7 +15077,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { } } - if (getLangOpts().C99) { + if (!IsBuiltinAddressof && getLangOpts().C99) { // Implement C99-only parts of addressof rules. if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) { if (uOp->getOpcode() == UO_Deref) @@ -15093,11 +15099,11 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { unsigned AddressOfError = AO_No_Error; if (lval == Expr::LV_ClassTemporary || lval == Expr::LV_ArrayTemporary) { - bool sfinae = (bool)isSFINAEContext(); - Diag(OpLoc, isSFINAEContext() ? diag::err_typecheck_addrof_temporary - : diag::ext_typecheck_addrof_temporary) - << op->getType() << op->getSourceRange(); - if (sfinae) + bool AllowTemporaryAddress = !isSFINAEContext() && !IsBuiltinAddressof; + Diag(OpLoc, AllowTemporaryAddress ? diag::ext_typecheck_addrof_temporary + : diag::err_typecheck_addrof_temporary) + << op->getType() << op->getSourceRange(); + if (!AllowTemporaryAddress) return QualType(); // Materialize the temporary as an lvalue so that we can take its address. OrigOp = op = @@ -15107,6 +15113,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { } else if (lval == Expr::LV_MemberFunction) { // If it's an instance method, make a member pointer. // The expression must have exactly the form &A::foo. + if (IsBuiltinAddressof) + return QualType(); // If the underlying expression isn't a decl ref, give up. if (!isa<DeclRefExpr>(op)) { @@ -15164,12 +15172,14 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { } else if (isa<MSPropertyDecl>(dcl)) { AddressOfError = AO_Property_Expansion; } else if (isa<FunctionTemplateDecl>(dcl)) { - return Context.OverloadTy; + return IsBuiltinAddressof ? QualType() : Context.OverloadTy; } else if (isa<FieldDecl>(dcl) || isa<IndirectFieldDecl>(dcl)) { // Okay: we can take the address of a field. // Could be a pointer to member, though, if there is an explicit // scope qualifier for the class. if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier()) { + if (IsBuiltinAddressof) + return QualType(); DeclContext *Ctx = dcl->getDeclContext(); if (Ctx && Ctx->isRecord()) { if (dcl->getType()->isReferenceType()) { diff --git a/clang/test/SemaCXX/builtins.cpp b/clang/test/SemaCXX/builtins.cpp index 567094c94c171b..a59eb36eef4451 100644 --- a/clang/test/SemaCXX/builtins.cpp +++ b/clang/test/SemaCXX/builtins.cpp @@ -39,7 +39,43 @@ namespace addressof { struct U { int n : 5; } u; int *pbf = __builtin_addressof(u.n); // expected-error {{address of bit-field requested}} - S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}} expected-warning {{temporary whose address is used as value of local variable 'ptmp' will be destroyed at the end of the full-expression}} + S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}} + int *memtmp = __builtin_addressof(T{}.n); // expected-error {{cannot take the address of an rvalue of type 'int'}} + S *pxval = __builtin_addressof(static_cast<S&&>(s)); // expected-error {{cannot take the address of an rvalue of type 'S'}} + + void a(int) {} // expected-note 3 {{possible target for call}} + void a(float) {} // expected-note 3 {{possible target for call}} + + int A = __builtin_addressof(a); // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} + int B = &__builtin_addressof(a); // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} + int C = __builtin_addressof(&a); // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} + + template<typename T> + constexpr decltype(void(__builtin_addressof(T::f)), true) can_take_address_of_f(int) { return true; } + template<typename T> + constexpr bool can_take_address_of_f(...) { return false; } + + struct V1 { static void f(int); static void f(char); }; + struct V2 { static void f(int); }; + struct V3 { static int f; }; + struct V4 { + int f; + int* g() { + return __builtin_addressof(f); + } + int* h() { + return __builtin_addressof(V4::f); + } + }; + struct V5 { void f(int); }; + struct V6 { using f = int; }; + + static_assert(!can_take_address_of_f<V1>(0), ""); + static_assert( can_take_address_of_f<V2>(0), ""); + static_assert( can_take_address_of_f<V3>(0), ""); + static_assert(!can_take_address_of_f<V4>(0), ""); + static_assert(!can_take_address_of_f<V5>(0), ""); + static_assert(!can_take_address_of_f<V6>(0), ""); } namespace function_start { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits