Revert "Treat `std::move`, `forward`, and `move_if_noexcept` as builtins."

Revert "Extend support for std::move etc to also cover std::as_const and"
Revert "Update test to handle opaque pointers flag flip."

It crashes on libcxx tests https://lab.llvm.org/buildbot/#/builders/85/builds/8174

This reverts commit fc30901096.
This reverts commit a571f82a50.
This reverts commit 64c045e25b.
This commit is contained in:
Vitaly Buka 2022-04-16 00:18:48 -07:00
parent 709868707c
commit e75d8b7037
28 changed files with 78 additions and 540 deletions

View File

@ -252,24 +252,8 @@ Language Selection and Mode Options
.. option:: -fno-builtin
Disable special handling and optimizations of well-known library functions,
like :c:func:`strlen` and :c:func:`malloc`.
.. option:: -fno-builtin-<function>
Disable special handling and optimizations for the specific library function.
For example, ``-fno-builtin-strlen`` removes any special handling for the
:c:func:`strlen` library function.
.. option:: -fno-builtin-std-<function>
Disable special handling and optimizations for the specific C++ standard
library function in namespace ``std``. For example,
``-fno-builtin-std-move_if_noexcept`` removes any special handling for the
:cpp:func:`std::move_if_noexcept` library function.
For C standard library functions that the C++ standard library also provides
in namespace ``std``, use :option:`-fno-builtin-\<function\>` instead.
Disable special handling and optimizations of builtin functions like
:c:func:`strlen` and :c:func:`malloc`.
.. option:: -fmath-errno

View File

@ -230,10 +230,7 @@ C2x Feature Support
C++ Language Changes in Clang
-----------------------------
- Improved ``-O0`` code generation for calls to ``std::move``, ``std::forward``,
and ``std::move_if_noexcept``. These are now treated as compiler builtins and
implemented directly, rather than instantiating the definition from the
standard library.
- ...
C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^

View File

@ -81,9 +81,7 @@
// builtin even if type doesn't match signature, and don't warn if we
// can't be sure the type is right
// F -> this is a libc/libm function with a '__builtin_' prefix added.
// f -> this is a libc/libm function without a '__builtin_' prefix, or with
// 'z', a C++ standard library function in namespace std::. This builtin
// is disableable by '-fno-builtin-foo' / '-fno-builtin-std-foo'.
// f -> this is a libc/libm function without the '__builtin_' prefix.
// h -> this function requires a specific header or an explicit declaration.
// i -> this is a runtime library implemented function without the
// '__builtin_' prefix. It will be implemented in compiler-rt or libgcc.
@ -103,7 +101,6 @@
// V:N: -> requires vectors of at least N bits to be legal
// C<N,M_0,...,M_k> -> callback behavior: argument N is called with argument
// M_0, ..., M_k as payload
// z -> this is a function in (possibly-versioned) namespace std
// FIXME: gcc has nonnull
#if defined(BUILTIN) && !defined(LIBBUILTIN)
@ -922,7 +919,7 @@ LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__GetExceptionInfo, "v*.", "zntu", ALL_MS_LANGUAGES)
LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedAnd8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedAnd16, "ssD*s", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedAnd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
@ -1546,15 +1543,6 @@ LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
// C++ standard library builtins in namespace 'std'.
LIBBUILTIN(addressof, "v*v&", "zfncTh", "memory", CXX_LANG)
// Synonym for addressof used internally by libstdc++.
LANGBUILTIN(__addressof, "v*v&", "zfncT", CXX_LANG)
LIBBUILTIN(as_const, "v&v&", "zfncTh", "utility", CXX_LANG)
LIBBUILTIN(forward, "v&v&", "zfncTh", "utility", CXX_LANG)
LIBBUILTIN(move, "v&v&", "zfncTh", "utility", CXX_LANG)
LIBBUILTIN(move_if_noexcept, "v&v&", "zfncTh", "utility", CXX_LANG)
// Annotation function
BUILTIN(__builtin_annotation, "v.", "tn")

View File

@ -138,10 +138,6 @@ public:
/// Determines whether this builtin is a predefined libc/libm
/// function, such as "malloc", where we know the signature a
/// priori.
/// In C, such functions behave as if they are predeclared,
/// possibly with a warning on first use. In Objective-C and C++,
/// they do not, but they are recognized as builtins once we see
/// a declaration.
bool isPredefinedLibFunction(unsigned ID) const {
return strchr(getRecord(ID).Attributes, 'f') != nullptr;
}
@ -160,23 +156,6 @@ public:
return strchr(getRecord(ID).Attributes, 'i') != nullptr;
}
/// Determines whether this builtin is a C++ standard library function
/// that lives in (possibly-versioned) namespace std, possibly a template
/// specialization, where the signature is determined by the standard library
/// declaration.
bool isInStdNamespace(unsigned ID) const {
return strchr(getRecord(ID).Attributes, 'z') != nullptr;
}
/// Determines whether this builtin can have its address taken with no
/// special action required.
bool isDirectlyAddressable(unsigned ID) const {
// Most standard library functions can have their addresses taken. C++
// standard library functions formally cannot in C++20 onwards, and when
// we allow it, we need to ensure we instantiate a definition.
return isPredefinedLibFunction(ID) && !isInStdNamespace(ID);
}
/// Determines whether this builtin has custom typechecking.
bool hasCustomTypechecking(unsigned ID) const {
return strchr(getRecord(ID).Attributes, 't') != nullptr;
@ -258,6 +237,10 @@ public:
private:
const Info &getRecord(unsigned ID) const;
/// Is this builtin supported according to the given language options?
bool builtinIsSupported(const Builtin::Info &BuiltinInfo,
const LangOptions &LangOpts);
/// Helper function for isPrintfLike and isScanfLike.
bool isLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg,
const char *Fmt) const;

View File

@ -6586,15 +6586,6 @@ def warn_self_move : Warning<
"explicitly moving variable of type %0 to itself">,
InGroup<SelfMove>, DefaultIgnore;
def err_builtin_move_forward_unsupported : Error<
"unsupported signature for %q0">;
def err_use_of_unaddressable_function : Error<
"taking address of non-addressable standard library function">;
// FIXME: This should also be in -Wc++23-compat once we have it.
def warn_cxx20_compat_use_of_unaddressable_function : Warning<
"taking address of non-addressable standard library function "
"is incompatible with C++20">, InGroup<CXX20Compat>;
def warn_redundant_move_on_return : Warning<
"redundant move in return statement">,
InGroup<RedundantMove>, DefaultIgnore;

View File

@ -8127,7 +8127,6 @@ public:
bool VisitVarDecl(const Expr *E, const VarDecl *VD);
bool VisitUnaryPreIncDec(const UnaryOperator *UO);
bool VisitCallExpr(const CallExpr *E);
bool VisitDeclRefExpr(const DeclRefExpr *E);
bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); }
bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
@ -8293,20 +8292,6 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
return Success(*V, E);
}
bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (unsigned BuiltinOp = E->getBuiltinCallee()) {
case Builtin::BIas_const:
case Builtin::BIforward:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
if (cast<FunctionDecl>(E->getCalleeDecl())->isConstexpr())
return Visit(E->getArg(0));
break;
}
return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
// Walk through the expression to find the materialized temporary itself.
@ -9085,8 +9070,6 @@ static bool isOneByteCharacterType(QualType T) {
bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
switch (BuiltinOp) {
case Builtin::BIaddressof:
case Builtin::BI__addressof:
case Builtin::BI__builtin_addressof:
return evaluateLValue(E->getArg(0), Result);
case Builtin::BI__builtin_assume_aligned: {

View File

@ -20,7 +20,6 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Analysis/CodeInjector.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
@ -87,9 +86,6 @@ public:
ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty,
CastKind CK = CK_LValueToRValue);
/// Create a cast to reference type.
CastExpr *makeReferenceCast(const Expr *Arg, QualType Ty);
/// Create an Objective-C bool literal.
ObjCBoolLiteralExpr *makeObjCBool(bool Val);
@ -177,16 +173,6 @@ ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty,
/* FPFeatures */ FPOptionsOverride());
}
CastExpr *ASTMaker::makeReferenceCast(const Expr *Arg, QualType Ty) {
assert(Ty->isReferenceType());
return CXXStaticCastExpr::Create(
C, Ty.getNonReferenceType(),
Ty->isLValueReferenceType() ? VK_LValue : VK_XValue, CK_NoOp,
const_cast<Expr *>(Arg), /*CXXCastPath=*/nullptr,
/*Written=*/C.getTrivialTypeSourceInfo(Ty), FPOptionsOverride(),
SourceLocation(), SourceLocation(), SourceRange());
}
Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
if (Arg->getType() == Ty)
return const_cast<Expr*>(Arg);
@ -310,22 +296,6 @@ static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,
/*FPFeatures=*/FPOptionsOverride());
}
/// Create a fake body for 'std::move' or 'std::forward'. This is just:
///
/// \code
/// return static_cast<return_type>(param);
/// \endcode
static Stmt *create_std_move_forward(ASTContext &C, const FunctionDecl *D) {
LLVM_DEBUG(llvm::dbgs() << "Generating body for std::move / std::forward\n");
ASTMaker M(C);
QualType ReturnType = D->getType()->castAs<FunctionType>()->getReturnType();
Expr *Param = M.makeDeclRefExpr(D->getParamDecl(0));
Expr *Cast = M.makeReferenceCast(Param, ReturnType);
return M.makeReturn(Cast);
}
/// Create a fake body for std::call_once.
/// Emulates the following function body:
///
@ -711,20 +681,8 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
FunctionFarmer FF;
if (unsigned BuiltinID = D->getBuiltinID()) {
switch (BuiltinID) {
case Builtin::BIas_const:
case Builtin::BIforward:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
FF = create_std_move_forward;
break;
default:
FF = nullptr;
break;
}
} else if (Name.startswith("OSAtomicCompareAndSwap") ||
Name.startswith("objc_atomicCompareAndSwap")) {
if (Name.startswith("OSAtomicCompareAndSwap") ||
Name.startswith("objc_atomicCompareAndSwap")) {
FF = create_OSAtomicCompareAndSwap;
} else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) {
FF = create_call_once;

View File

@ -48,22 +48,18 @@ void Builtin::Context::InitializeTarget(const TargetInfo &Target,
}
bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) {
bool InStdNamespace = FuncName.consume_front("std-");
for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin;
++i) {
if (FuncName.equals(BuiltinInfo[i].Name) &&
(bool)strchr(BuiltinInfo[i].Attributes, 'z') == InStdNamespace)
for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i)
if (FuncName.equals(BuiltinInfo[i].Name))
return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr;
}
return false;
}
/// Is this builtin supported according to the given language options?
static bool builtinIsSupported(const Builtin::Info &BuiltinInfo,
const LangOptions &LangOpts) {
bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo,
const LangOptions &LangOpts) {
bool BuiltinsUnsupported =
LangOpts.NoBuiltin && strchr(BuiltinInfo.Attributes, 'f') != nullptr;
(LangOpts.NoBuiltin || LangOpts.isNoBuiltinFunc(BuiltinInfo.Name)) &&
strchr(BuiltinInfo.Attributes, 'f');
bool CorBuiltinsUnsupported =
!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG);
bool MathBuiltinsUnsupported =
@ -115,19 +111,6 @@ void Builtin::Context::initializeBuiltins(IdentifierTable &Table,
for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i)
Table.get(AuxTSRecords[i].Name)
.setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size());
// Step #4: Unregister any builtins specified by -fno-builtin-foo.
for (llvm::StringRef Name : LangOpts.NoBuiltinFuncs) {
bool InStdNamespace = Name.consume_front("std-");
auto NameIt = Table.find(Name);
if (NameIt != Table.end()) {
unsigned ID = NameIt->second->getBuiltinID();
if (ID != Builtin::NotBuiltin && isPredefinedLibFunction(ID) &&
isInStdNamespace(ID) == InStdNamespace) {
Table.get(Name).setBuiltinID(Builtin::NotBuiltin);
}
}
}
}
unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const {
@ -207,7 +190,8 @@ bool Builtin::Context::performsCallback(unsigned ID,
}
bool Builtin::Context::canBeRedeclared(unsigned ID) const {
return ID == Builtin::NotBuiltin || ID == Builtin::BI__va_start ||
(!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) ||
isInStdNamespace(ID);
return ID == Builtin::NotBuiltin ||
ID == Builtin::BI__va_start ||
(!hasReferenceArgsOrResult(ID) &&
!hasCustomTypechecking(ID));
}

View File

@ -4566,8 +4566,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Carry);
}
case Builtin::BIaddressof:
case Builtin::BI__addressof:
case Builtin::BI__builtin_addressof:
return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this));
case Builtin::BI__builtin_function_start:
@ -4727,12 +4725,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
break;
// C++ std:: builtins.
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
case Builtin::BIforward:
case Builtin::BIas_const:
return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this));
case Builtin::BI__GetExceptionInfo: {
if (llvm::GlobalVariable *GV =
CGM.getCXXABI().getThrowInfo(FD->getParamDecl(0)->getType()))

View File

@ -1805,8 +1805,6 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
if (AttrOnCallSite) {
// Attributes that should go on the call site only.
// FIXME: Look for 'BuiltinAttr' on the function rather than re-checking
// the -fno-builtin-foo list.
if (!CodeGenOpts.SimplifyLibCalls || LangOpts.isNoBuiltinFunc(Name))
FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin);
if (!CodeGenOpts.TrapFuncName.empty())

View File

@ -2130,32 +2130,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
TheCall->setType(Context.VoidPtrTy);
break;
case Builtin::BIaddressof:
case Builtin::BI__addressof:
case Builtin::BIforward:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
case Builtin::BIas_const: {
// These are all expected to be of the form
// T &/&&/* f(U &/&&)
// where T and U only differ in qualification.
if (checkArgCount(*this, TheCall, 1))
return ExprError();
QualType Param = FDecl->getParamDecl(0)->getType();
QualType Result = FDecl->getReturnType();
bool ReturnsPointer = BuiltinID == Builtin::BIaddressof ||
BuiltinID == Builtin::BI__addressof;
if (!(Param->isReferenceType() &&
(ReturnsPointer ? Result->isPointerType()
: Result->isReferenceType()) &&
Context.hasSameUnqualifiedType(Param->getPointeeType(),
Result->getPointeeType()))) {
Diag(TheCall->getBeginLoc(), diag::err_builtin_move_forward_unsupported)
<< FDecl;
return ExprError();
}
break;
}
// OpenCL v2.0, s6.13.16 - Pipe functions
case Builtin::BIread_pipe:
case Builtin::BIwrite_pipe:

View File

@ -9269,32 +9269,6 @@ static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {
return S;
}
/// Determine whether a declaration matches a known function in namespace std.
static bool isStdBuiltin(ASTContext &Ctx, FunctionDecl *FD,
unsigned BuiltinID) {
switch (BuiltinID) {
case Builtin::BI__GetExceptionInfo:
// No type checking whatsoever.
return Ctx.getTargetInfo().getCXXABI().isMicrosoft();
case Builtin::BIaddressof:
case Builtin::BI__addressof:
case Builtin::BIforward:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
case Builtin::BIas_const: {
// Ensure that we don't treat the algorithm
// OutputIt std::move(InputIt, InputIt, OutputIt)
// as the builtin std::move.
const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
return FPT->getNumParams() == 1 && !FPT->isVariadic();
}
default:
return false;
}
}
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@ -10147,30 +10121,28 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// If this is the first declaration of a library builtin function, add
// attributes as appropriate.
if (!D.isRedeclaration()) {
if (!D.isRedeclaration() &&
NewFD->getDeclContext()->getRedeclContext()->isFileContext()) {
if (IdentifierInfo *II = Previous.getLookupName().getAsIdentifierInfo()) {
if (unsigned BuiltinID = II->getBuiltinID()) {
bool InStdNamespace = Context.BuiltinInfo.isInStdNamespace(BuiltinID);
if (!InStdNamespace &&
NewFD->getDeclContext()->getRedeclContext()->isFileContext()) {
if (NewFD->getLanguageLinkage() == CLanguageLinkage) {
// Validate the type matches unless this builtin is specified as
// matching regardless of its declared type.
if (Context.BuiltinInfo.allowTypeMismatch(BuiltinID)) {
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
} else {
ASTContext::GetBuiltinTypeError Error;
LookupNecessaryTypesForBuiltin(S, BuiltinID);
QualType BuiltinType = Context.GetBuiltinType(BuiltinID, Error);
if (NewFD->getLanguageLinkage() == CLanguageLinkage) {
// Validate the type matches unless this builtin is specified as
// matching regardless of its declared type.
if (Context.BuiltinInfo.allowTypeMismatch(BuiltinID)) {
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
} else {
ASTContext::GetBuiltinTypeError Error;
LookupNecessaryTypesForBuiltin(S, BuiltinID);
QualType BuiltinType = Context.GetBuiltinType(BuiltinID, Error);
if (!Error && !BuiltinType.isNull() &&
Context.hasSameFunctionTypeIgnoringExceptionSpec(
NewFD->getType(), BuiltinType))
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
}
if (!Error && !BuiltinType.isNull() &&
Context.hasSameFunctionTypeIgnoringExceptionSpec(
NewFD->getType(), BuiltinType))
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
}
} else if (InStdNamespace && NewFD->isInStdNamespace() &&
isStdBuiltin(Context, NewFD, BuiltinID)) {
} else if (BuiltinID == Builtin::BI__GetExceptionInfo &&
Context.getTargetInfo().getCXXABI().isMicrosoft()) {
// FIXME: We should consider this a builtin only in the std namespace.
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
}
}

View File

@ -3395,7 +3395,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
case Decl::Function: {
if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) {
if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
type = Context.BuiltinFnTy;
valueKind = VK_PRValue;
break;
@ -20528,8 +20528,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
if (DRE) {
auto *FD = cast<FunctionDecl>(DRE->getDecl());
unsigned BuiltinID = FD->getBuiltinID();
if (BuiltinID == Builtin::BI__noop) {
if (FD->getBuiltinID() == Builtin::BI__noop) {
E = ImpCastExprToType(E, Context.getPointerType(FD->getType()),
CK_BuiltinFnToFnPtr)
.get();
@ -20537,36 +20536,6 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
VK_PRValue, SourceLocation(),
FPOptionsOverride());
}
if (Context.BuiltinInfo.isInStdNamespace(BuiltinID)) {
// Any use of these other than a direct call is ill-formed as of C++20,
// because they are not addressable functions. In earlier language
// modes, warn and force an instantiation of the real body.
Diag(E->getBeginLoc(),
getLangOpts().CPlusPlus20
? diag::err_use_of_unaddressable_function
: diag::warn_cxx20_compat_use_of_unaddressable_function);
if (FD->isImplicitlyInstantiable()) {
// Require a definition here because a normal attempt at
// instantiation for a builtin will be ignored, and we won't try
// again later. We assume that the definition of the template
// precedes this use.
InstantiateFunctionDefinition(E->getBeginLoc(), FD,
/*Recursive=*/false,
/*DefinitionRequired=*/true,
/*AtEndOfTU=*/false);
}
// Produce a properly-typed reference to the function.
CXXScopeSpec SS;
SS.Adopt(DRE->getQualifierLoc());
TemplateArgumentListInfo TemplateArgs;
DRE->copyTemplateArgumentsInto(TemplateArgs);
return BuildDeclRefExpr(
FD, FD->getType(), VK_LValue, DRE->getNameInfo(),
DRE->hasQualifier() ? &SS : nullptr, DRE->getFoundDecl(),
DRE->getTemplateKeywordLoc(),
DRE->hasExplicitTemplateArgs() ? &TemplateArgs : nullptr);
}
}
Diag(E->getBeginLoc(), diag::err_builtin_fn_use);

View File

@ -4236,14 +4236,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
From = FixOverloadedFunctionReference(From, Found, Fn);
// We might get back another placeholder expression if we resolved to a
// builtin.
ExprResult Checked = CheckPlaceholderExpr(From);
if (Checked.isInvalid())
return ExprError();
From = Checked.get();
FromType = From->getType();
}

View File

@ -8215,10 +8215,6 @@ ExprResult InitializationSequence::Perform(Sema &S,
CurInit = S.FixOverloadedFunctionReference(CurInit,
Step->Function.FoundDecl,
Step->Function.Function);
// We might get back another placeholder expression if we resolved to a
// builtin.
if (!CurInit.isInvalid())
CurInit = S.CheckPlaceholderExpr(CurInit.get());
break;
case SK_CastDerivedToBasePRValue:

View File

@ -1747,6 +1747,13 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
"Non-address-of operator for overloaded function expression");
FromType = S.Context.getPointerType(FromType);
}
// Check that we've computed the proper type after overload resolution.
// FIXME: FixOverloadedFunctionReference has side-effects; we shouldn't
// be calling it from within an NDEBUG block.
assert(S.Context.hasSameType(
FromType,
S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
} else {
return false;
}
@ -15181,9 +15188,10 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (SubExpr == UnOp->getSubExpr())
return UnOp;
// FIXME: This can't currently fail, but in principle it could.
return CreateBuiltinUnaryOp(UnOp->getOperatorLoc(), UO_AddrOf, SubExpr)
.get();
return UnaryOperator::Create(
Context, SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()),
VK_PRValue, OK_Ordinary, UnOp->getOperatorLoc(), false,
CurFPFeatureOverrides());
}
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
@ -15194,20 +15202,10 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
TemplateArgs = &TemplateArgsBuffer;
}
QualType Type = Fn->getType();
ExprValueKind ValueKind = getLangOpts().CPlusPlus ? VK_LValue : VK_PRValue;
// FIXME: Duplicated from BuildDeclarationNameExpr.
if (unsigned BID = Fn->getBuiltinID()) {
if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) {
Type = Context.BuiltinFnTy;
ValueKind = VK_PRValue;
}
}
DeclRefExpr *DRE = BuildDeclRefExpr(
Fn, Type, ValueKind, ULE->getNameInfo(), ULE->getQualifierLoc(),
Found.getDecl(), ULE->getTemplateKeywordLoc(), TemplateArgs);
DeclRefExpr *DRE =
BuildDeclRefExpr(Fn, Fn->getType(), VK_LValue, ULE->getNameInfo(),
ULE->getQualifierLoc(), Found.getDecl(),
ULE->getTemplateKeywordLoc(), TemplateArgs);
DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
return DRE;
}

View File

@ -4771,12 +4771,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (TSK == TSK_ExplicitSpecialization)
return;
// Never implicitly instantiate a builtin; we don't actually need a function
// body.
if (Function->getBuiltinID() && TSK == TSK_ImplicitInstantiation &&
!DefinitionRequired)
return;
// Don't instantiate a definition if we already have one.
const FunctionDecl *ExistingDefn = nullptr;
if (Function->isDefined(ExistingDefn,

View File

@ -379,7 +379,7 @@ void func_addressof() {
const char *c;
std::string s;
c = s.c_str();
(void)addressof(s);
addressof(s);
consume(c); // no-warning
}

View File

@ -244,7 +244,7 @@ void reinitializationTest(int i) {
A a;
if (i == 1) { // peaceful-note 2 {{'i' is not equal to 1}}
// peaceful-note@-1 2 {{Taking false branch}}
(void)std::move(a);
std::move(a);
}
if (i == 2) { // peaceful-note 2 {{'i' is not equal to 2}}
// peaceful-note@-1 2 {{Taking false branch}}
@ -494,7 +494,7 @@ void templateArgIsNotUseTest() {
// Moves of global variables are not reported.
A global_a;
void globalVariablesTest() {
(void)std::move(global_a);
std::move(global_a);
global_a.foo(); // no-warning
}

View File

@ -1,57 +0,0 @@
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - -std=c++17 %s | FileCheck %s --implicit-check-not=@_ZSt4move
namespace std {
template<typename T> constexpr T &&move(T &val) { return static_cast<T&&>(val); }
template<typename T> constexpr T &&move_if_noexcept(T &val);
template<typename T> constexpr T &&forward(T &val);
template<typename T> constexpr const T &as_const(T &val);
// Not the builtin.
template<typename T, typename U> T move(U source, U source_end, T dest);
}
class T {};
extern "C" void take(T &&);
extern "C" void take_lval(const T &);
T a;
// Check emission of a constant-evaluated call.
// CHECK-DAG: @move_a = constant ptr @a
T &&move_a = std::move(a);
// CHECK-DAG: @move_if_noexcept_a = constant ptr @a
T &&move_if_noexcept_a = std::move_if_noexcept(a);
// CHECK-DAG: @forward_a = constant ptr @a
T &forward_a = std::forward<T&>(a);
// Check emission of a non-constant call.
// CHECK-LABEL: define {{.*}} void @test
extern "C" void test(T &t) {
// CHECK: store ptr %{{.*}}, ptr %[[T_REF:[^,]*]]
// CHECK: %0 = load ptr, ptr %[[T_REF]]
// CHECK: call void @take(ptr {{.*}} %0)
take(std::move(t));
// CHECK: %1 = load ptr, ptr %[[T_REF]]
// CHECK: call void @take(ptr {{.*}} %1)
take(std::move_if_noexcept(t));
// CHECK: %2 = load ptr, ptr %[[T_REF]]
// CHECK: call void @take(ptr {{.*}} %2)
take(std::forward<T&&>(t));
// CHECK: %3 = load ptr, ptr %[[T_REF]]
// CHECK: call void @take_lval(ptr {{.*}} %3)
take_lval(std::as_const<T&&>(t));
// CHECK: call {{.*}} @_ZSt4moveI1TS0_ET_T0_S2_S1_
std::move(t, t, t);
}
// CHECK: declare {{.*}} @_ZSt4moveI1TS0_ET_T0_S2_S1_
// Check that we instantiate and emit if the address is taken.
// CHECK-LABEL: define {{.*}} @use_address
extern "C" void *use_address() {
// CHECK: ret {{.*}} @_ZSt4moveIiEOT_RS0_
return (void*)&std::move<int>;
}
// CHECK: define {{.*}} ptr @_ZSt4moveIiEOT_RS0_(ptr

View File

@ -30,24 +30,6 @@ S *addressof(bool b, S &s, S &t) {
return __builtin_addressof(b ? s : t);
}
namespace std { template<typename T> T *addressof(T &); }
// CHECK: define {{.*}} @_Z13std_addressofbR1SS0_(
S *std_addressof(bool b, S &s, S &t) {
// CHECK: %[[LVALUE:.*]] = phi
// CHECK: ret {{.*}}* %[[LVALUE]]
return std::addressof(b ? s : t);
}
namespace std { template<typename T> T *__addressof(T &); }
// CHECK: define {{.*}} @_Z15std___addressofbR1SS0_(
S *std___addressof(bool b, S &s, S &t) {
// CHECK: %[[LVALUE:.*]] = phi
// CHECK: ret {{.*}}* %[[LVALUE]]
return std::__addressof(b ? s : t);
}
extern "C" int __builtin_abs(int); // #1
long __builtin_abs(long); // #2
extern "C" int __builtin_abs(int); // #3

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -no-opaque-pointers -emit-llvm -o - -triple=i386-pc-win32 -std=c++11 %s -fcxx-exceptions -fms-extensions | FileCheck %s
// RUN: %clang_cc1 -no-opaque-pointers -emit-llvm -o - -triple=i386-pc-win32 -std=c++11 %s -fcxx-exceptions -fms-extensions -DSTD | FileCheck %s
// CHECK-DAG: @"??_R0?AUY@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"??_7type_info@@6B@", i8* null, [8 x i8] c".?AUY@@\00" }, comdat
// CHECK-DAG: @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 4, i8* bitcast (%rtti.TypeDescriptor7* @"??_R0?AUY@@@8" to i8*), i32 0, i32 -1, i32 0, i32 8, i8* bitcast (%struct.Y* (%struct.Y*, %struct.Y*, i32)* @"??0Y@@QAE@ABU0@@Z" to i8*) }, section ".xdata", comdat
@ -133,10 +134,15 @@ void h() {
throw nullptr;
}
#ifdef STD
namespace std {
template <typename T>
void *__GetExceptionInfo(T);
}
#else
template <typename T>
void *__GetExceptionInfo(T);
#endif
using namespace std;
void *GetExceptionInfo_test0() {

View File

@ -1,20 +0,0 @@
// RUN: %clang_cc1 -std=c++20 -verify %s -DBUILTIN=builtin
// RUN: %clang_cc1 -std=c++20 -verify %s -DBUILTIN=nobuiltin -fno-builtin
// RUN: %clang_cc1 -std=c++20 -verify %s -DBUILTIN=nobuiltin -fno-builtin-std-move -fno-builtin-std-move_if_noexcept -fno-builtin-std-forward
// RUN: %clang_cc1 -std=c++20 -verify %s -DBUILTIN=nobuiltin -ffreestanding
// expected-no-diagnostics
int nobuiltin;
namespace std {
template<typename T> constexpr T &&move(T &x) { return (T&&)nobuiltin; }
template<typename T> constexpr T &&move_if_noexcept(T &x) { return (T&&)nobuiltin; }
template<typename T> constexpr T &&forward(T &x) { return (T&&)nobuiltin; }
}
template<typename T> constexpr T *addr(T &&r) { return &r; }
int builtin;
static_assert(addr(std::move(builtin)) == &BUILTIN);
static_assert(addr(std::move_if_noexcept(builtin)) == &BUILTIN);
static_assert(addr(std::forward(builtin)) == &BUILTIN);

View File

@ -1,126 +0,0 @@
// RUN: %clang_cc1 -std=c++17 -verify %s
// RUN: %clang_cc1 -std=c++17 -verify %s -DNO_CONSTEXPR
// RUN: %clang_cc1 -std=c++20 -verify %s
namespace std {
#ifndef NO_CONSTEXPR
#define CONSTEXPR constexpr
#else
#define CONSTEXPR
#endif
template<typename T> CONSTEXPR T &&move(T &x) {
static_assert(T::moveable, "instantiated move"); // expected-error {{no member named 'moveable' in 'B'}}
// expected-error@-1 {{no member named 'moveable' in 'C'}}
return static_cast<T&&>(x);
}
// Unrelated move functions are not the builtin.
template<typename T> CONSTEXPR int move(T, T) { return 5; }
template<typename T, bool Rref> struct ref { using type = T&; };
template<typename T> struct ref<T, true> { using type = T&&; };
template<typename T> CONSTEXPR auto move_if_noexcept(T &x) -> typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type {
static_assert(T::moveable, "instantiated move_if_noexcept"); // expected-error {{no member named 'moveable' in 'B'}}
return static_cast<typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type>(x);
}
template<typename T> struct remove_reference { using type = T; };
template<typename T> struct remove_reference<T&> { using type = T; };
template<typename T> struct remove_reference<T&&> { using type = T; };
template<typename T> CONSTEXPR T &&forward(typename remove_reference<T>::type &x) {
static_assert(T::moveable, "instantiated forward"); // expected-error {{no member named 'moveable' in 'B'}}
// expected-error@-1 {{no member named 'moveable' in 'C'}}
return static_cast<T&&>(x);
}
template<typename T> CONSTEXPR const T &as_const(T &x) {
static_assert(T::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
return x;
}
template<typename T> CONSTEXPR T *addressof(T &x) {
static_assert(T::moveable, "instantiated addressof"); // expected-error {{no member named 'moveable' in 'B'}}
return __builtin_addressof(x);
}
template<typename T> CONSTEXPR T *__addressof(T &x) {
static_assert(T::moveable, "instantiated __addressof"); // expected-error {{no member named 'moveable' in 'B'}}
return __builtin_addressof(x);
}
}
// Note: this doesn't have a 'moveable' member. Instantiation of the above
// functions will fail if it's attempted.
struct A {};
constexpr bool f(A a) { // #f
A &&move = std::move(a); // #call
A &&move_if_noexcept = std::move_if_noexcept(a);
A &&forward1 = std::forward<A>(a);
A &forward2 = std::forward<A&>(a);
const A &as_const = std::as_const(a);
A *addressof = std::addressof(a);
A *addressof2 = std::__addressof(a);
return &move == &a && &move_if_noexcept == &a &&
&forward1 == &a && &forward2 == &a &&
&as_const == &a && addressof == &a &&
addressof2 == &a && std::move(a, a) == 5;
}
#ifndef NO_CONSTEXPR
static_assert(f({}), "should be constexpr");
#else
// expected-error@#f {{never produces a constant expression}}
// expected-note@#call {{}}
#endif
struct B {};
B &&(*pMove)(B&) = std::move; // #1 expected-note {{instantiation of}}
B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept; // #2 expected-note {{instantiation of}}
B &&(*pForward)(B&) = &std::forward<B>; // #3 expected-note {{instantiation of}}
const B &(*pAsConst)(B&) = &std::as_const; // #4 expected-note {{instantiation of}}
B *(*pAddressof)(B&) = &std::addressof; // #5 expected-note {{instantiation of}}
B *(*pUnderUnderAddressof)(B&) = &std::__addressof; // #6 expected-note {{instantiation of}}
int (*pUnrelatedMove)(B, B) = std::move;
struct C {};
C &&(&rMove)(C&) = std::move; // #7 expected-note {{instantiation of}}
C &&(&rForward)(C&) = std::forward<C>; // #8 expected-note {{instantiation of}}
int (&rUnrelatedMove)(B, B) = std::move;
#if __cplusplus <= 201703L
// expected-warning@#1 {{non-addressable}}
// expected-warning@#2 {{non-addressable}}
// expected-warning@#3 {{non-addressable}}
// expected-warning@#4 {{non-addressable}}
// expected-warning@#5 {{non-addressable}}
// expected-warning@#6 {{non-addressable}}
// expected-warning@#7 {{non-addressable}}
// expected-warning@#8 {{non-addressable}}
#else
// expected-error@#1 {{non-addressable}}
// expected-error@#2 {{non-addressable}}
// expected-error@#3 {{non-addressable}}
// expected-error@#4 {{non-addressable}}
// expected-error@#5 {{non-addressable}}
// expected-error@#6 {{non-addressable}}
// expected-error@#7 {{non-addressable}}
// expected-error@#8 {{non-addressable}}
#endif
void attribute_const() {
int n;
std::move(n); // expected-warning {{ignoring return value}}
std::move_if_noexcept(n); // expected-warning {{ignoring return value}}
std::forward<int>(n); // expected-warning {{ignoring return value}}
std::addressof(n); // expected-warning {{ignoring return value}}
std::__addressof(n); // expected-warning {{ignoring return value}}
std::as_const(n); // expected-warning {{ignoring return value}}
}
namespace std {
template<typename T> int move(T);
}
int bad_signature = std::move(0); // expected-error {{unsupported signature for 'std::move<int>'}}

View File

@ -6,9 +6,9 @@
namespace std {
int &&move(auto &&a) { return a; }
void move(auto &&a) {}
int &&forward(auto &a) { return a; }
void forward(auto &a) {}
} // namespace std
@ -16,8 +16,8 @@ using namespace std;
void f() {
int i = 0;
(void)move(i); // expected-warning {{unqualified call to std::move}}
// CHECK: {{^}} (void)std::move
(void)forward(i); // expected-warning {{unqualified call to std::forward}}
// CHECK: {{^}} (void)std::forward
move(i); // expected-warning {{unqualified call to std::move}}
// CHECK: {{^}} std::
forward(i); // expected-warning {{unqualified call to std::forward}}
// CHECK: {{^}} std::
}

View File

@ -1,17 +1,17 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wall -std=c++11 %s -Wno-unused-value
// RUN: %clang_cc1 -fsyntax-only -verify -Wall -std=c++11 %s
namespace std {
template <typename T>
void dummy(T &&) {}
template <typename T>
T &&move(T &&x) { return x; }
void move(T &&) {}
template <typename T, typename U>
void move(T &&, U &&) {}
inline namespace __1 {
template <typename T>
T &forward(T &x) { return x; }
void forward(T &) {}
} // namespace __1
struct foo {};

View File

@ -953,12 +953,12 @@ void test6() {
namespace std {
void move();
template<class T>
T &&move(T&);
void move(T&&);
namespace __1 {
void move();
template<class T>
T &&move(T&);
void move(T&&);
}
}
@ -971,7 +971,7 @@ namespace PR18260 {
void test() {
x.move();
std::move();
std::move(x); // expected-warning {{ignoring return value}}
std::move(x);
std::__1::move();
std::__1::move(x);
}

View File

@ -1444,7 +1444,7 @@ TEST(ExprMutationAnalyzerTest, UnevaluatedContext) {
TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) {
const std::string Reproducer =
"namespace std {"
"template <class T> T &forward(T &A) { return static_cast<T&&>(A); }"
"template <class T> T forward(T & A) { return static_cast<T&&>(A); }"
"template <class T> struct __bind {"
" T f;"
" template <class V> __bind(T v, V &&) : f(forward(v)) {}"