Vendor import of clang RELEASE_360/rc3 tag r229040 (effectively, 3.6.0 RC3):
https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_360/rc3@229040
This commit is contained in:
parent
9e435806aa
commit
ec12bbe359
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=278754 svn path=/vendor/clang/clang-release_360-r229040/; revision=278755; tag=vendor/clang/clang-release_360-r229040
@ -98,6 +98,8 @@ Windows Support
|
||||
|
||||
- Basic support for DWARF debug information in COFF files
|
||||
|
||||
- Support for Visual C++ '__super' keyword
|
||||
|
||||
|
||||
C Language Changes in Clang
|
||||
---------------------------
|
||||
@ -118,10 +120,35 @@ C++ Language Changes in Clang
|
||||
- Clang will put individual ``.init_array/.ctors`` sections in
|
||||
comdats, reducing code duplication and speeding up startup.
|
||||
|
||||
C++11 Feature Support
|
||||
C++17 Feature Support
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
...
|
||||
Clang has experimental support for some proposed C++1z (tentatively, C++17)
|
||||
features. This support can be enabled using the `-std=c++1z` flag.
|
||||
|
||||
New in Clang 3.6 is support for:
|
||||
|
||||
- Fold expressions
|
||||
|
||||
- `u8` character literals
|
||||
|
||||
- Nested namespace definitions: `namespace A::B { ... }` as a shorthand for
|
||||
`namespace A { namespace B { ... } }`
|
||||
|
||||
- Attributes for namespaces and enumerators
|
||||
|
||||
- Constant evaluation for all non-type template arguments
|
||||
|
||||
Note that these features may be changed or removed in future Clang releases
|
||||
without notice.
|
||||
|
||||
Support for `for (identifier : range)` as a synonym for
|
||||
`for (auto &&identifier : range)` has been removed as it is no longer currently
|
||||
considered for C++17.
|
||||
|
||||
For more details on C++ feature support, see
|
||||
`the C++ status page <http://clang.llvm.org/cxx_status.html>`_.
|
||||
|
||||
|
||||
Objective-C Language Changes in Clang
|
||||
-------------------------------------
|
||||
@ -133,6 +160,19 @@ OpenCL C Language Changes in Clang
|
||||
|
||||
...
|
||||
|
||||
OpenMP Language Changes in Clang
|
||||
--------------------------------
|
||||
|
||||
Clang 3.6 contains codegen for many individual pragmas for OpenMP but combinations are not completed as yet.
|
||||
We plan to continue codegen code drop aiming for completion for 3.7. Please see this link for up-to-date
|
||||
`status <https://github.com/clang-omp/clang/wiki/Status-of-supported-OpenMP-constructs>_`
|
||||
LLVM’s OpenMP runtime library, originally developed by Intel, has been modified to work on ARM, PowerPC,
|
||||
as well as X86. The Runtime Library's compatibility with GCC 4.9 is improved
|
||||
- missed entry points added, Barrier and fork/join code improved, one more type of barrier enabled.
|
||||
Support for ppc64le architecture is now available and automatically detected when using cmake system.
|
||||
Using makefile the new "ppc64le" arch type is available.
|
||||
Contributors to this work include AMD, Argonne National Lab., IBM, Intel, Texas Instruments, University of Houston and many others.
|
||||
|
||||
Internal API Changes
|
||||
--------------------
|
||||
|
||||
|
@ -749,3 +749,6 @@ def SerializedDiagnostics : DiagGroup<"serialized-diagnostics">;
|
||||
// A warning group for warnings about code that clang accepts when
|
||||
// compiling CUDA C/C++ but which is not compatible with the CUDA spec.
|
||||
def CudaCompat : DiagGroup<"cuda-compat">;
|
||||
|
||||
// A warning group for things that will change semantics in the future.
|
||||
def FutureCompat : DiagGroup<"future-compat">;
|
||||
|
@ -802,6 +802,10 @@ def warn_cxx98_compat_lambda : Warning<
|
||||
def err_lambda_missing_parens : Error<
|
||||
"lambda requires '()' before %select{'mutable'|return type|"
|
||||
"attribute specifier}0">;
|
||||
def warn_init_capture_direct_list_init : Warning<
|
||||
"direct list initialization of a lambda init-capture will change meaning in "
|
||||
"a future version of Clang; insert an '=' to avoid a change in behavior">,
|
||||
InGroup<FutureCompat>;
|
||||
|
||||
// Availability attribute
|
||||
def err_expected_version : Error<
|
||||
|
@ -1635,6 +1635,10 @@ def err_auto_var_init_multiple_expressions : Error<
|
||||
def err_auto_var_init_paren_braces : Error<
|
||||
"cannot deduce type for variable %0 with type %1 from "
|
||||
"parenthesized initializer list">;
|
||||
def warn_auto_var_direct_list_init : Warning<
|
||||
"direct list initialization of a variable with a deduced type will change "
|
||||
"meaning in a future version of Clang; insert an '=' to avoid a change in "
|
||||
"behavior">, InGroup<FutureCompat>;
|
||||
def err_auto_new_ctor_multiple_expressions : Error<
|
||||
"new expression for type %0 contains multiple constructor arguments">;
|
||||
def err_auto_missing_trailing_return : Error<
|
||||
|
@ -1693,12 +1693,12 @@ const Type *CXXCtorInitializer::getBaseClass() const {
|
||||
}
|
||||
|
||||
SourceLocation CXXCtorInitializer::getSourceLocation() const {
|
||||
if (isAnyMemberInitializer())
|
||||
return getMemberLocation();
|
||||
|
||||
if (isInClassMemberInitializer())
|
||||
return getAnyMember()->getLocation();
|
||||
|
||||
if (isAnyMemberInitializer())
|
||||
return getMemberLocation();
|
||||
|
||||
if (TypeSourceInfo *TSInfo = Initializee.get<TypeSourceInfo*>())
|
||||
return TSInfo->getTypeLoc().getLocalSourceRange().getBegin();
|
||||
|
||||
|
@ -544,7 +544,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
CXXCtorInitializer *MemberInit,
|
||||
const CXXConstructorDecl *Constructor,
|
||||
FunctionArgList &Args) {
|
||||
ApplyDebugLocation Loc(CGF, MemberInit->getMemberLocation());
|
||||
ApplyDebugLocation Loc(CGF, MemberInit->getSourceLocation());
|
||||
assert(MemberInit->isAnyMemberInitializer() &&
|
||||
"Must have member initializer!");
|
||||
assert(MemberInit->getInit() && "Must have initializer!");
|
||||
@ -598,7 +598,6 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
ArrayRef<VarDecl *> ArrayIndexes;
|
||||
if (MemberInit->getNumArrayIndices())
|
||||
ArrayIndexes = MemberInit->getArrayIndexes();
|
||||
ApplyDebugLocation DL(CGF, MemberInit->getMemberLocation());
|
||||
CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit(), ArrayIndexes);
|
||||
}
|
||||
|
||||
|
@ -3393,11 +3393,12 @@ Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
|
||||
assert(E && hasScalarEvaluationKind(E->getType()) &&
|
||||
"Invalid scalar expression to emit");
|
||||
|
||||
bool hasDebugInfo = getDebugInfo();
|
||||
if (isa<CXXDefaultArgExpr>(E))
|
||||
disableDebugInfo();
|
||||
Value *V = ScalarExprEmitter(*this, IgnoreResultAssign)
|
||||
.Visit(const_cast<Expr*>(E));
|
||||
if (isa<CXXDefaultArgExpr>(E))
|
||||
if (isa<CXXDefaultArgExpr>(E) && hasDebugInfo)
|
||||
enableDebugInfo();
|
||||
return V;
|
||||
}
|
||||
|
@ -935,8 +935,8 @@ static void emitUsed(CodeGenModule &CGM, StringRef Name,
|
||||
UsedArray.resize(List.size());
|
||||
for (unsigned i = 0, e = List.size(); i != e; ++i) {
|
||||
UsedArray[i] =
|
||||
llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(&*List[i]),
|
||||
CGM.Int8PtrTy);
|
||||
llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
|
||||
cast<llvm::Constant>(&*List[i]), CGM.Int8PtrTy);
|
||||
}
|
||||
|
||||
if (UsedArray.empty())
|
||||
|
@ -324,7 +324,7 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
/// referenced. These get code generated when the module is done.
|
||||
struct DeferredGlobal {
|
||||
DeferredGlobal(llvm::GlobalValue *GV, GlobalDecl GD) : GV(GV), GD(GD) {}
|
||||
llvm::AssertingVH<llvm::GlobalValue> GV;
|
||||
llvm::TrackingVH<llvm::GlobalValue> GV;
|
||||
GlobalDecl GD;
|
||||
};
|
||||
std::vector<DeferredGlobal> DeferredDeclsToEmit;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/ObjCRuntime.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/Config/config.h"
|
||||
#include "clang/Driver/Action.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
@ -1538,7 +1539,7 @@ static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
|
||||
// as gold requires -plugin to come before any -plugin-opt that -Wl might
|
||||
// forward.
|
||||
CmdArgs.push_back("-plugin");
|
||||
std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
|
||||
std::string Plugin = ToolChain.getDriver().Dir + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold.so";
|
||||
CmdArgs.push_back(Args.MakeArgString(Plugin));
|
||||
|
||||
// Try to pass driver level flags relevant to LTO code generation down to
|
||||
|
@ -894,11 +894,16 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
||||
// to save the necessary state, and restore it later.
|
||||
EnterExpressionEvaluationContext EC(Actions,
|
||||
Sema::PotentiallyEvaluated);
|
||||
TryConsumeToken(tok::equal);
|
||||
bool HadEquals = TryConsumeToken(tok::equal);
|
||||
|
||||
if (!SkippedInits)
|
||||
if (!SkippedInits) {
|
||||
// Warn on constructs that will change meaning when we implement N3922
|
||||
if (!HadEquals && Tok.is(tok::l_brace)) {
|
||||
Diag(Tok, diag::warn_init_capture_direct_list_init)
|
||||
<< FixItHint::CreateInsertion(Tok.getLocation(), "=");
|
||||
}
|
||||
Init = ParseInitializer();
|
||||
else if (Tok.is(tok::l_brace)) {
|
||||
} else if (Tok.is(tok::l_brace)) {
|
||||
BalancedDelimiterTracker Braces(*this, tok::l_brace);
|
||||
Braces.consumeOpen();
|
||||
Braces.skipToEnd();
|
||||
|
@ -8702,6 +8702,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
||||
CheckVariableDeclarationType(VDecl);
|
||||
if (VDecl->isInvalidDecl())
|
||||
return;
|
||||
|
||||
// If all looks well, warn if this is a case that will change meaning when
|
||||
// we implement N3922.
|
||||
if (DirectInit && !CXXDirectInit && isa<InitListExpr>(Init)) {
|
||||
Diag(Init->getLocStart(),
|
||||
diag::warn_auto_var_direct_list_init)
|
||||
<< FixItHint::CreateInsertion(Init->getLocStart(), "=");
|
||||
}
|
||||
}
|
||||
|
||||
// dllimport cannot be used on variable definitions.
|
||||
|
@ -2500,8 +2500,18 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
|
||||
// will always be a (possibly implicit) declaration to shadow any others.
|
||||
OverloadCandidateSet OCS(RD->getLocation(), OverloadCandidateSet::CSK_Normal);
|
||||
DeclContext::lookup_result R = RD->lookup(Name);
|
||||
assert(!R.empty() &&
|
||||
"lookup for a constructor or assignment operator was empty");
|
||||
|
||||
if (R.empty()) {
|
||||
// We might have no default constructor because we have a lambda's closure
|
||||
// type, rather than because there's some other declared constructor.
|
||||
// Every class has a copy/move constructor, copy/move assignment, and
|
||||
// destructor.
|
||||
assert(SM == CXXDefaultConstructor &&
|
||||
"lookup for a constructor or assignment operator was empty");
|
||||
Result->setMethod(nullptr);
|
||||
Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Copy the candidates as our processing of them may load new declarations
|
||||
// from an external source and invalidate lookup_result.
|
||||
|
@ -370,21 +370,21 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
|
||||
// FunctionDecl's body is handled last at ASTWriterDecl::Visit,
|
||||
// after everything else is written.
|
||||
|
||||
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
|
||||
Record.push_back((int)D->SClass); // FIXME: stable encoding
|
||||
Record.push_back(D->IsInline);
|
||||
Record.push_back(D->isInlineSpecified());
|
||||
Record.push_back(D->isVirtualAsWritten());
|
||||
Record.push_back(D->isPure());
|
||||
Record.push_back(D->hasInheritedPrototype());
|
||||
Record.push_back(D->hasWrittenPrototype());
|
||||
Record.push_back(D->isDeletedAsWritten());
|
||||
Record.push_back(D->isTrivial());
|
||||
Record.push_back(D->isDefaulted());
|
||||
Record.push_back(D->isExplicitlyDefaulted());
|
||||
Record.push_back(D->hasImplicitReturnZero());
|
||||
Record.push_back(D->isConstexpr());
|
||||
Record.push_back(D->IsInlineSpecified);
|
||||
Record.push_back(D->IsVirtualAsWritten);
|
||||
Record.push_back(D->IsPure);
|
||||
Record.push_back(D->HasInheritedPrototype);
|
||||
Record.push_back(D->HasWrittenPrototype);
|
||||
Record.push_back(D->IsDeleted);
|
||||
Record.push_back(D->IsTrivial);
|
||||
Record.push_back(D->IsDefaulted);
|
||||
Record.push_back(D->IsExplicitlyDefaulted);
|
||||
Record.push_back(D->HasImplicitReturnZero);
|
||||
Record.push_back(D->IsConstexpr);
|
||||
Record.push_back(D->HasSkippedBody);
|
||||
Record.push_back(D->isLateTemplateParsed());
|
||||
Record.push_back(D->IsLateTemplateParsed);
|
||||
Record.push_back(D->getLinkageInternal());
|
||||
Writer.AddSourceLocation(D->getLocEnd(), Record);
|
||||
|
||||
@ -1802,7 +1802,7 @@ void ASTWriter::WriteDeclAbbrevs() {
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto
|
||||
Abv->Add(BitCodeAbbrevOp(1)); // HasWrittenProto
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // DeletedAsWritten
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Deleted
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Trivial
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Defaulted
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitlyDefaulted
|
||||
|
@ -48,7 +48,7 @@ auto bad_init_2 = [a(1, 2)] {}; // expected-error {{initializer for lambda captu
|
||||
auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}}
|
||||
auto bad_init_4 = [a(void_fn())] {}; // expected-error {{has incomplete type 'void'}}
|
||||
auto bad_init_5 = [a(overload_fn)] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer of type '<overloaded function}}
|
||||
auto bad_init_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer list}}
|
||||
auto bad_init_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer list}} expected-warning {{will change meaning in a future version of Clang}}
|
||||
|
||||
template<typename...T> void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}}
|
||||
template void pack_1<>(); // expected-note {{instantiation of}}
|
||||
@ -61,7 +61,7 @@ auto a = [a(4), b = 5, &c = static_cast<const int&&>(0)] {
|
||||
using T = decltype(c);
|
||||
using T = const int &;
|
||||
};
|
||||
auto b = [a{0}] {}; // expected-error {{include <initializer_list>}}
|
||||
auto b = [a{0}] {}; // expected-error {{include <initializer_list>}} expected-warning {{will change meaning in a future version of Clang}}
|
||||
|
||||
struct S { S(); S(S&&); };
|
||||
template<typename T> struct remove_reference { typedef T type; };
|
||||
|
8
test/CodeGenCUDA/llvm-used.cu
Normal file
8
test/CodeGenCUDA/llvm-used.cu
Normal file
@ -0,0 +1,8 @@
|
||||
// RUN: %clang_cc1 -emit-llvm %s -o - -fcuda-is-device -triple nvptx64-unknown-unknown | FileCheck %s
|
||||
|
||||
|
||||
// Make sure we emit the proper addrspacecast for llvm.used. PR22383 exposed an
|
||||
// issue where we were generating a bitcast instead of an addrspacecast.
|
||||
|
||||
// CHECK: @llvm.used = appending global [1 x i8*] [i8* addrspacecast (i8 addrspace(1)* bitcast ([0 x i32] addrspace(1)* @a to i8 addrspace(1)*) to i8*)], section "llvm.metadata"
|
||||
__attribute__((device)) __attribute__((__used__)) int a[] = {};
|
@ -232,3 +232,14 @@ foo::~foo() {}
|
||||
// CHECK6: @_ZN6test113fooD2Ev = alias {{.*}} @_ZN6test113barD2Ev
|
||||
// CHECK6: @_ZN6test113fooD1Ev = alias {{.*}} @_ZN6test113fooD2Ev
|
||||
}
|
||||
|
||||
namespace test12 {
|
||||
template <int>
|
||||
struct foo {
|
||||
~foo() { delete this; }
|
||||
};
|
||||
|
||||
template class foo<1>;
|
||||
// CHECK6: @_ZN6test123fooILi1EED1Ev = weak_odr alias {{.*}} @_ZN6test123fooILi1EED2Ev
|
||||
// CHECK6: define weak_odr void @_ZN6test123fooILi1EED2Ev({{.*}}) {{.*}} comdat($_ZN6test123fooILi1EED5Ev)
|
||||
}
|
||||
|
@ -166,6 +166,33 @@ void f13() {
|
||||
F13_IMPL;
|
||||
}
|
||||
|
||||
struct f14 {
|
||||
f14(int);
|
||||
};
|
||||
|
||||
// CHECK-LABEL: define
|
||||
struct f14_use {
|
||||
// CHECK: call {{.*}}, !dbg [[DBG_F14_CTOR_CALL:![0-9]*]]
|
||||
#line 1600
|
||||
f14 v
|
||||
=
|
||||
1;
|
||||
f14_use();
|
||||
};
|
||||
|
||||
f14_use::f14_use() = default;
|
||||
|
||||
// CHECK-LABEL: define
|
||||
|
||||
// CHECK-LABEL: define
|
||||
int f21_a(int = 0);
|
||||
void f21_b(int = f21_a());
|
||||
void f21() {
|
||||
// CHECK: call {{.*}}f21_b{{.*}}, !dbg [[DBG_F21:![0-9]*]]
|
||||
#line 2300
|
||||
f21_b();
|
||||
}
|
||||
|
||||
// CHECK: [[DBG_F1]] = !MDLocation(line: 100,
|
||||
// CHECK: [[DBG_FOO_VALUE]] = !MDLocation(line: 200,
|
||||
// CHECK: [[DBG_FOO_REF]] = !MDLocation(line: 202,
|
||||
|
18
test/PCH/implicitly-deleted.cpp
Normal file
18
test/PCH/implicitly-deleted.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
// RUN: %clang_cc1 -std=c++11 -x c++-header %s -emit-pch -o %t.pch
|
||||
// RUN: %clang_cc1 -std=c++11 -x c++ /dev/null -include-pch %t.pch
|
||||
class move_only { move_only(const move_only&) = delete; move_only(move_only&&); };
|
||||
struct sb {
|
||||
move_only il;
|
||||
sb();
|
||||
sb(sb &&);
|
||||
};
|
||||
|
||||
template<typename T> T make();
|
||||
template<typename T> void doit(decltype(T(make<const T&>()))*) { T(make<const T&>()); }
|
||||
template<typename T> void doit(...) { T(make<T&&>()); }
|
||||
template<typename T> void later() { doit<T>(0); }
|
||||
|
||||
void fn1() {
|
||||
sb x;
|
||||
later<sb>();
|
||||
}
|
@ -61,7 +61,7 @@ class C {
|
||||
int z;
|
||||
void init_capture() {
|
||||
[n(0)] () mutable -> int { return ++n; }; // expected-warning{{extension}}
|
||||
[n{0}] { return; }; // expected-error {{<initializer_list>}} expected-warning{{extension}}
|
||||
[n{0}] { return; }; // expected-error {{<initializer_list>}} expected-warning{{extension}} expected-warning{{will change meaning in a future version}}
|
||||
[n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} expected-warning{{extension}}
|
||||
[n = {0}] { return; }; // expected-error {{<initializer_list>}} expected-warning{{extension}}
|
||||
[a([&b = z]{})](){}; // expected-warning 2{{extension}}
|
||||
|
@ -21,7 +21,7 @@ class C {
|
||||
|
||||
[foo(bar)] () {};
|
||||
[foo = bar] () {};
|
||||
[foo{bar}] () {}; // expected-error {{<initializer_list>}}
|
||||
[foo{bar}] () {}; // expected-error {{<initializer_list>}} expected-warning {{will change meaning}}
|
||||
[foo = {bar}] () {}; // expected-error {{<initializer_list>}}
|
||||
|
||||
[foo(bar) baz] () {}; // expected-error {{called object type 'int' is not a function}}
|
||||
|
@ -117,6 +117,7 @@ void argument_deduction() {
|
||||
|
||||
void auto_deduction() {
|
||||
auto l = {1, 2, 3, 4};
|
||||
auto l2 {1, 2, 3, 4}; // expected-warning {{will change meaning in a future version of Clang}}
|
||||
static_assert(same_type<decltype(l), std::initializer_list<int>>::value, "");
|
||||
auto bl = {1, 2.0}; // expected-error {{cannot deduce}}
|
||||
|
||||
|
@ -437,3 +437,12 @@ namespace error_in_transform_prototype {
|
||||
f(S()); // expected-note {{requested here}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace PR21857 {
|
||||
template<typename Fn> struct fun : Fn {
|
||||
fun() = default;
|
||||
using Fn::operator();
|
||||
};
|
||||
template<typename Fn> fun<Fn> wrap(Fn fn);
|
||||
auto x = wrap([](){});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user