/// lambda.
TemplateParameterList *getGenericLambdaTemplateParameterList() const;
+ /// Retrieve the lambda template parameters that were specified explicitly.
+ ArrayRef<NamedDecl *> getLambdaExplicitTemplateParameters() const;
+
LambdaCaptureDefault getLambdaCaptureDefault() const {
assert(isLambda());
return static_cast<LambdaCaptureDefault>(getLambdaData().CaptureDefault);
return SourceRange(TemplateLoc, RAngleLoc);
}
+ void print(raw_ostream &Out, const ASTContext &Context,
+ bool OmitTemplateKW = false) const;
+ void print(raw_ostream &Out, const ASTContext &Context,
+ const PrintingPolicy &Policy, bool OmitTemplateKW = false) const;
+
public:
// FIXME: workaround for MSVC 2013; remove when no longer needed
using FixedSizeStorageOwner = TrailingObjects::FixedSizeStorageOwner;
/// parameter list associated with it, or else return null.
TemplateParameterList *getTemplateParameterList() const;
+ /// Get the template parameters were explicitly specified (as opposed to being
+ /// invented by use of an auto parameter).
+ ArrayRef<NamedDecl *> getExplicitTemplateParameters() const;
+
/// Whether this is a generic lambda.
bool isGenericLambda() const { return getTemplateParameterList(); }
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
+ for (Decl *D : S->getExplicitTemplateParameters()) {
+ // Visit explicit template parameters.
+ TRY_TO(TraverseDecl(D));
+ }
if (S->hasExplicitParameters()) {
// Visit parameters.
for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I)
def ext_constexpr_on_lambda_cxx17 : ExtWarn<
"'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>;
+ // C++2a template lambdas
+ def ext_lambda_template_parameter_list: ExtWarn<
+ "explicit template parameter list for lambdas is a C++2a extension">,
+ InGroup<CXX2a>;
+def warn_cxx17_compat_lambda_template_parameter_list: Warning<
+ "explicit template parameter list for lambdas is incompatible with "
+ "C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
+ def err_lambda_template_parameter_list_empty : Error<
+ "lambda template parameter list cannot be empty">;
+
// Availability attribute
def err_expected_version : Error<
"expected a version of the form 'major[.minor[.subminor]]'">;
Depth += D;
AddedLevels += D;
}
+ void setAddedDepth(unsigned D) {
+ Depth = Depth - AddedLevels + D;
+ AddedLevels = D;
+ }
+
unsigned getDepth() const { return Depth; }
+ unsigned getOriginalDepth() const { return Depth - AddedLevels; }
};
/// Factory object for creating ParsedAttr objects.
/// each 'auto' parameter, during initial AST construction.
unsigned AutoTemplateParameterDepth = 0;
- /// Store the list of the auto parameters for a generic lambda.
- /// If this is a generic lambda, store the list of the auto
- /// parameters converted into TemplateTypeParmDecls into a vector
- /// that can be used to construct the generic lambda's template
- /// parameter list, during initial AST construction.
- SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams;
+ /// The number of parameters in the template parameter list that were
+ /// explicitly specified by the user, as opposed to being invented by use
+ /// of an auto parameter.
+ unsigned NumExplicitTemplateParams = 0;
+
+ /// Source range covering the explicit template parameter list (if it exists).
+ SourceRange ExplicitTemplateParamsRange;
+
+ /// Store the list of the template parameters for a generic lambda.
+ /// If this is a generic lambda, this holds the explicit template parameters
+ /// followed by the auto parameters converted into TemplateTypeParmDecls.
+ /// It can be used to construct the generic lambda's template parameter list
+ /// during initial AST construction.
+ SmallVector<NamedDecl*, 4> TemplateParams;
/// If this is a generic lambda, and the template parameter
- /// list has been created (from the AutoTemplateParams) then
- /// store a reference to it (cache it to avoid reconstructing it).
+ /// list has been created (from the TemplateParams) then store
+ /// a reference to it (cache it to avoid reconstructing it).
TemplateParameterList *GLTemplateParameterList = nullptr;
/// Contains all variable-referring-expressions (i.e. DeclRefExprs
}
/// Is this scope known to be for a generic lambda? (This will be false until
- /// we parse the first 'auto'-typed parameter.
+ /// we parse a template parameter list or the first 'auto'-typed parameter).
bool isGenericLambda() const {
- return !AutoTemplateParams.empty() || GLTemplateParameterList;
+ return !TemplateParams.empty() || GLTemplateParameterList;
}
/// Add a variable that might potentially be captured by the
/// given lambda.
void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
+ /// \brief This is called after parsing the explicit template parameter list
+ /// on a lambda (if it exists) in C++2a.
+ void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
+ ArrayRef<NamedDecl *> TParams,
+ SourceLocation RAngleLoc);
+
/// Introduce the lambda parameters into scope.
void addLambdaParameters(
ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
TemplateParameterList *
CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
- if (!isLambda()) return nullptr;
+ if (!isGenericLambda()) return nullptr;
CXXMethodDecl *CallOp = getLambdaCallOperator();
if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
return Tmpl->getTemplateParameters();
return nullptr;
}
+ArrayRef<NamedDecl *>
+CXXRecordDecl::getLambdaExplicitTemplateParameters() const {
+ TemplateParameterList *List = getGenericLambdaTemplateParameterList();
+ if (!List)
+ return {};
+
+ assert(std::is_partitioned(List->begin(), List->end(),
+ [](const NamedDecl *D) { return !D->isImplicit(); })
+ && "Explicit template params should be ordered before implicit ones");
+
+ const auto ExplicitEnd = std::lower_bound(List->begin(), List->end(), false,
+ [](const NamedDecl *D, bool) {
+ return !D->isImplicit();
+ });
+ return llvm::makeArrayRef(List->begin(), ExplicitEnd);
+}
+
Decl *CXXRecordDecl::getLambdaContextDecl() const {
assert(isLambda() && "Not a lambda closure type!");
ExternalASTSource *Source = getParentASTContext().getExternalSource();
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D);
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
- void printTemplateParameters(const TemplateParameterList *Params);
+ void printTemplateParameters(const TemplateParameterList *Params,
+ bool OmitTemplateKW = false);
void printTemplateArguments(const TemplateArgumentList &Args,
const TemplateParameterList *Params = nullptr);
void prettyPrintAttributes(Decl *D);
Printer.Visit(const_cast<Decl*>(this));
}
+void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
+ bool OmitTemplateKW) const {
+ print(Out, Context, Context.getPrintingPolicy(), OmitTemplateKW);
+}
+
+void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
+ const PrintingPolicy &Policy,
+ bool OmitTemplateKW) const {
+ DeclPrinter Printer(Out, Policy, Context);
+ Printer.printTemplateParameters(this, OmitTemplateKW);
+}
+
static QualType GetBaseType(QualType T) {
// FIXME: This should be on the Type class!
QualType BaseType = T;
Visit(*D->decls_begin());
}
-void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params) {
+void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
+ bool OmitTemplateKW) {
assert(Params);
- Out << "template <";
+ if (!OmitTemplateKW)
+ Out << "template ";
+ Out << '<';
- for (unsigned i = 0, e = Params->size(); i != e; ++i) {
- if (i != 0)
+ bool NeedComma = false;
+ for (const Decl *Param : *Params) {
+ if (Param->isImplicit())
+ continue;
+
+ if (NeedComma)
Out << ", ";
+ else
+ NeedComma = true;
- const Decl *Param = Params->getParam(i);
if (auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (TTP->wasDeclaredWithTypename())
- Out << "typename ";
+ Out << "typename";
else
- Out << "class ";
+ Out << "class";
if (TTP->isParameterPack())
- Out << "...";
+ Out << " ...";
+ else if (!TTP->getName().empty())
+ Out << ' ';
Out << *TTP;
}
}
- Out << "> ";
+ Out << '>';
+ if (!OmitTemplateKW)
+ Out << ' ';
}
void DeclPrinter::printTemplateArguments(const TemplateArgumentList &Args,
TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
CXXRecordDecl *Record = getLambdaClass();
return Record->getGenericLambdaTemplateParameterList();
+}
+ArrayRef<NamedDecl *> LambdaExpr::getExplicitTemplateParameters() const {
+ const CXXRecordDecl *Record = getLambdaClass();
+ return Record->getLambdaExplicitTemplateParameters();
}
CompoundStmt *LambdaExpr::getBody() const {
const AbiTagList *AdditionalAbiTags);
void mangleBlockForPrefix(const BlockDecl *Block);
void mangleUnqualifiedBlock(const BlockDecl *Block);
+ void mangleTemplateParamDecl(const NamedDecl *Decl);
void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
const AbiTagList *AdditionalAbiTags,
// <unnamed-type-name> ::= <closure-type-name>
//
// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
- // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'.
+ // <lambda-sig> ::= <template-param-decl>* <parameter-type>+
+ // # Parameter types or 'v' for 'void'.
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
if (Record->isLambda() && Record->getLambdaManglingNumber()) {
assert(!AdditionalAbiTags &&
Out << '_';
}
+// <template-param-decl>
+// ::= Ty # template type parameter
+// ::= Tn <type> # template non-type parameter
+// ::= Tt <template-param-decl>* E # template template parameter
+void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
+ if (isa<TemplateTypeParmDecl>(Decl)) {
+ Out << "Ty";
+ } else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
+ Out << "Tn";
+ mangleType(Tn->getType());
+ } else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) {
+ Out << "Tt";
+ for (auto *Param : *Tt->getTemplateParameters())
+ mangleTemplateParamDecl(Param);
+ Out << "E";
+ }
+}
+
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// If the context of a closure type is an initializer for a class member
// (static or nonstatic), it is encoded in a qualified name with a final
}
Out << "Ul";
+ for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
+ mangleTemplateParamDecl(D);
const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
getAs<FunctionProtoType>();
mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
}
OS << ']';
+ if (!Node->getExplicitTemplateParameters().empty()) {
+ Node->getTemplateParameterList()->print(
+ OS, Node->getLambdaClass()->getASTContext(),
+ /*OmitTemplateKW*/true);
+ }
+
if (Node->hasExplicitParameters()) {
- OS << " (";
+ OS << '(';
CXXMethodDecl *Method = Node->getCallOperator();
NeedComma = false;
for (const auto *P : Method->parameters()) {
}
// Print the body.
- CompoundStmt *Body = Node->getBody();
OS << ' ';
- PrintStmt(Body);
+ PrintRawCompoundStmt(Node->getBody());
}
void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
raw_ostream &OS) {
if (IdentifierInfo *Id = T->getIdentifier())
OS << Id->getName();
- else
- OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
+ else {
+ bool IsLambdaAutoParam = false;
+ if (auto D = T->getDecl()) {
+ if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext()))
+ IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda();
+ }
+
+ if (IsLambdaAutoParam)
+ OS << "auto";
+ else
+ OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
+ }
spaceBeforePlaceHolder(OS);
}
///
/// lambda-expression:
/// lambda-introducer lambda-declarator[opt] compound-statement
+/// lambda-introducer '<' template-parameter-list '>'
+/// lambda-declarator[opt] compound-statement
///
/// lambda-introducer:
/// '[' lambda-capture[opt] ']'
<< A.getName()->getName();
};
+ // FIXME: Consider allowing this as an extension for GCC compatibiblity.
+ const bool HasExplicitTemplateParams = Tok.is(tok::less);
+ ParseScope TemplateParamScope(this, Scope::TemplateParamScope,
+ /*EnteredScope=*/HasExplicitTemplateParams);
+ if (HasExplicitTemplateParams) {
+ Diag(Tok, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_lambda_template_parameter_list
+ : diag::ext_lambda_template_parameter_list);
+
+ SmallVector<NamedDecl*, 4> TemplateParams;
+ SourceLocation LAngleLoc, RAngleLoc;
+ if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
+ TemplateParams, LAngleLoc, RAngleLoc)) {
+ Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
+ return ExprError();
+ }
+
+ if (TemplateParams.empty()) {
+ Diag(RAngleLoc,
+ diag::err_lambda_template_parameter_list_empty);
+ } else {
+ Actions.ActOnLambdaExplicitTemplateParameterList(
+ LAngleLoc, TemplateParams, RAngleLoc);
+ ++CurTemplateDepthTracker;
+ }
+ }
+
TypeResult TrailingReturnType;
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
SourceLocation EllipsisLoc;
if (Tok.isNot(tok::r_paren)) {
- Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
+ Actions.RecordParsingTemplateParameterDepth(
+ CurTemplateDepthTracker.getOriginalDepth());
+
ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc);
+
// For a generic lambda, each 'auto' within the parameter declaration
// clause creates a template type parameter, so increment the depth.
+ // If we've parsed any explicit template parameters, then the depth will
+ // have already been incremented. So we make sure that at most a single
+ // depth level is added.
if (Actions.getCurGenericLambda())
- ++CurTemplateDepthTracker;
+ CurTemplateDepthTracker.setAddedDepth(1);
}
+
T.consumeClose();
SourceLocation RParenLoc = T.getCloseLocation();
SourceLocation DeclEndLoc = RParenLoc;
StmtResult Stmt(ParseCompoundStatementBody());
BodyScope.Exit();
+ TemplateParamScope.Exit();
if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid())
return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
// an associated template parameter list.
LambdaScopeInfo *Sema::getCurGenericLambda() {
if (LambdaScopeInfo *LSI = getCurLambda()) {
- return (LSI->AutoTemplateParams.size() ||
+ return (LSI->TemplateParams.size() ||
LSI->GLTemplateParameterList) ? LSI : nullptr;
}
return nullptr;
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
+#include "llvm/ADT/STLExtras.h"
using namespace clang;
using namespace sema;
static inline TemplateParameterList *
getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
- if (LSI->GLTemplateParameterList)
- return LSI->GLTemplateParameterList;
-
- if (!LSI->AutoTemplateParams.empty()) {
- SourceRange IntroRange = LSI->IntroducerRange;
- SourceLocation LAngleLoc = IntroRange.getBegin();
- SourceLocation RAngleLoc = IntroRange.getEnd();
+ if (!LSI->GLTemplateParameterList && !LSI->TemplateParams.empty()) {
LSI->GLTemplateParameterList = TemplateParameterList::Create(
SemaRef.Context,
- /*Template kw loc*/ SourceLocation(), LAngleLoc,
- llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(),
- LSI->AutoTemplateParams.size()),
- RAngleLoc, nullptr);
+ /*Template kw loc*/ SourceLocation(),
+ /*L angle loc*/ LSI->ExplicitTemplateParamsRange.getBegin(),
+ LSI->TemplateParams,
+ /*R angle loc*/LSI->ExplicitTemplateParamsRange.getEnd(),
+ nullptr);
}
return LSI->GLTemplateParameterList;
}
LSI->finishedExplicitCaptures();
}
+void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
+ ArrayRef<NamedDecl *> TParams,
+ SourceLocation RAngleLoc) {
+ LambdaScopeInfo *LSI = getCurLambda();
+ assert(LSI && "Expected a lambda scope");
+ assert(LSI->NumExplicitTemplateParams == 0 &&
+ "Already acted on explicit template parameters");
+ assert(LSI->TemplateParams.empty() &&
+ "Explicit template parameters should come "
+ "before invented (auto) ones");
+ assert(!TParams.empty() &&
+ "No template parameters to act on");
+ LSI->TemplateParams.append(TParams.begin(), TParams.end());
+ LSI->NumExplicitTemplateParams = TParams.size();
+ LSI->ExplicitTemplateParamsRange = {LAngleLoc, RAngleLoc};
+}
+
void Sema::addLambdaParameters(
ArrayRef<LambdaIntroducer::LambdaCapture> Captures,
CXXMethodDecl *CallOperator, Scope *CurScope) {
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Declarator &ParamInfo,
Scope *CurScope) {
- // Determine if we're within a context where we know that the lambda will
- // be dependent, because there are template parameters in scope.
- bool KnownDependent = false;
LambdaScopeInfo *const LSI = getCurLambda();
assert(LSI && "LambdaScopeInfo should be on stack!");
- // The lambda-expression's closure type might be dependent even if its
- // semantic context isn't, if it appears within a default argument of a
- // function template.
- if (CurScope->getTemplateParamParent())
- KnownDependent = true;
+ // Determine if we're within a context where we know that the lambda will
+ // be dependent, because there are template parameters in scope.
+ bool KnownDependent;
+ if (LSI->NumExplicitTemplateParams > 0) {
+ auto *TemplateParamScope = CurScope->getTemplateParamParent();
+ assert(TemplateParamScope &&
+ "Lambda with explicit template param list should establish a "
+ "template param scope");
+ assert(TemplateParamScope->getParent());
+ KnownDependent = TemplateParamScope->getParent()
+ ->getTemplateParamParent() != nullptr;
+ } else {
+ KnownDependent = CurScope->getTemplateParamParent() != nullptr;
+ }
// Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo;
sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
assert(LSI && "No LambdaScopeInfo on the stack!");
const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
- const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
+ const unsigned AutoParameterPosition = LSI->TemplateParams.size();
const bool IsParameterPack = D.hasEllipsis();
// Create the TemplateTypeParmDecl here to retrieve the corresponding
/*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(),
TemplateParameterDepth, AutoParameterPosition,
/*Identifier*/ nullptr, false, IsParameterPack);
- LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+ CorrespondingTemplateParam->setImplicit();
+ LSI->TemplateParams.push_back(CorrespondingTemplateParam);
// Replace the 'auto' in the function parameter with this invented
// template type parameter.
// FIXME: Retain some type sugar to indicate that this was written
};
#endif
+#if __cplusplus > 201703L
// - in a template parameter pack that is a pack expansion
- // FIXME: We do not support any way to reach this case yet.
+ swallow([]<T *...v, template<T *> typename ...W>(W<v> ...wv) { });
+#endif
// - in an initializer-list
int arr[] = {T().x...};
struct T { int x; using U = int; };
void g() { f<T>(1, 2, 3); }
- template<typename ...T, typename ...U> void pack_in_lambda(U ...u) { // expected-note {{here}}
- // FIXME: Move this test into 'f' above once we support this syntax.
- []<T *...v, template<T *> typename ...U>(U<v> ...uv) {}; // expected-error {{expected body of lambda}} expected-error {{does not refer to a value}}
- }
-
template<typename ...T> void pack_expand_attr() {
// FIXME: Move this test into 'f' above once we support this.
[[gnu::aligned(alignof(T))...]] int x; // expected-error {{cannot be used as an attribute pack}} expected-error {{unexpanded}}
--- /dev/null
+// RUN: %clang_cc1 -std=c++2a -triple %itanium_abi_triple -emit-llvm -o - %s -w | FileCheck %s
+
+template<class, int, class>
+struct DummyType { };
+
+inline void inline_func() {
+ // CHECK: UlvE
+ []{}();
+
+ // CHECK: UlTyvE
+ []<class>{}.operator()<int>();
+
+ // CHECK: UlTyT_E
+ []<class T>(T){}(1);
+
+ // CHECK: UlTyTyT_T0_E
+ []<class T1, class T2>(T1, T2){}(1, 2);
+
+ // CHECK: UlTyTyT0_T_E
+ []<class T1, class T2>(T2, T1){}(2, 1);
+
+ // CHECK: UlTniTyTnjT0_E
+ []<int I, class T, unsigned U>(T){}.operator()<1, int, 2>(3);
+
+ // CHECK: UlTyTtTyTniTyETniTyvE
+ []<class,
+ template<class, int, class> class,
+ int,
+ class>{}.operator()<unsigned, DummyType, 5, int>();
+}
+
+void call_inline_func() {
+ inline_func();
+}
// DISPLAY_NAME: print-display-names.cpp:13:17: FunctionDecl=g<>(ClassTmpl<int, int>):13:17 [Specialization of g:11:6]
// RUN: env CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT=1 c-index-test -test-load-source all-pretty %s | FileCheck %s --check-prefix=PRETTY
-// PRETTY: print-display-names.cpp:2:7: ClassTemplate=template <typename T, typename > class ClassTmpl {}:2:7 (Definition) Extent=[1:1 - 2:20]
+// PRETTY: print-display-names.cpp:2:7: ClassTemplate=template <typename T, typename> class ClassTmpl {}:2:7 (Definition) Extent=[1:1 - 2:20]
// PRETTY: print-display-names.cpp:4:13: TypedefDecl=typedef int Integer:4:13 (Definition) Extent=[4:1 - 4:20]
// PRETTY: print-display-names.cpp:6:16: ClassDecl=template<> class ClassTmpl<int, int> {}:6:16 (Definition) [Specialization of ClassTmpl:2:7] Extent=[6:1 - 6:43]
// PRETTY: print-display-names.cpp:8:6: FunctionDecl=void f(ClassTmpl<float, Integer> p):8:6 Extent=[8:1 - 8:36]
}
// CHECK-PRINT: inline int add_int_slowly_twice
-// CHECK-PRINT: lambda = [&] (int z)
+// CHECK-PRINT: lambda = [&](int z)
// CHECK-PRINT: init_capture
// CHECK-PRINT: [&, x(t)]
}
// CHECK-PRINT: inline int add_int_slowly_twice
-// CHECK-PRINT: lambda = [] (type-parameter-0-0 z
+// CHECK-PRINT: lambda = [](auto z
// CHECK-PRINT: init_capture
// CHECK-PRINT: [&, x(t)]
--- /dev/null
+// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
+// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+auto l1 = []<int I>() constexpr -> int {
+ return I;
+};
+
+auto l2 = []<auto I>() constexpr -> decltype(I) {
+ return I;
+};
+
+auto l3 = []<class T>(auto i) constexpr -> T {
+ return T(i);
+};
+
+auto l4 = []<template<class> class T, class U>(T<U>, auto i) constexpr -> U {
+ return U(i);
+};
+
+#else /*included pch*/
+
+static_assert(l1.operator()<5>() == 5);
+static_assert(l1.operator()<6>() == 6);
+
+static_assert(l2.operator()<7>() == 7);
+static_assert(l2.operator()<nullptr>() == nullptr);
+
+static_assert(l3.operator()<int>(8.4) == 8);
+static_assert(l3.operator()<int>(9.9) == 9);
+
+template<typename T>
+struct DummyTemplate { };
+
+static_assert(l4(DummyTemplate<float>(), 12) == 12.0);
+static_assert(l4(DummyTemplate<int>(), 19.8) == 19);
+
+#endif // HEADER
--- /dev/null
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+auto L0 = []<> { }; //expected-error {{cannot be empty}}
+
+auto L1 = []<typename T1, typename T2> { };
+auto L2 = []<typename T1, typename T2>(T1 arg1, T2 arg2) -> T1 { };
+auto L3 = []<typename T>(auto arg) { T t; };
+auto L4 = []<int I>() { };
--- /dev/null
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+template<typename, typename>
+constexpr bool is_same = false;
+
+template<typename T>
+constexpr bool is_same<T, T> = true;
+
+template<typename T>
+struct DummyTemplate { };
+
+void func() {
+ auto L0 = []<typename T>(T arg) {
+ static_assert(is_same<T, int>); // expected-error {{static_assert failed}}
+ };
+ L0(0);
+ L0(0.0); // expected-note {{in instantiation}}
+
+ auto L1 = []<int I> {
+ static_assert(I == 5); // expected-error {{static_assert failed}}
+ };
+ L1.operator()<5>();
+ L1.operator()<6>(); // expected-note {{in instantiation}}
+
+ auto L2 = []<template<typename> class T, class U>(T<U> &&arg) {
+ static_assert(is_same<T<U>, DummyTemplate<float>>); // // expected-error {{static_assert failed}}
+ };
+ L2(DummyTemplate<float>());
+ L2(DummyTemplate<double>()); // expected-note {{in instantiation}}
+}
+
+template<typename T> // expected-note {{declared here}}
+struct ShadowMe {
+ void member_func() {
+ auto L = []<typename T> { }; // expected-error {{'T' shadows template parameter}}
+ }
+};
+
+template<typename T>
+constexpr T outer() {
+ return []<T x>() { return x; }.template operator()<123>(); // expected-error {{no matching member function}} \
+ expected-note {{candidate template ignored}}
+}
+static_assert(outer<int>() == 123);
+template int *outer<int *>(); // expected-note {{in instantiation}}
// WRONG; Should be: (a & b).operator void *()
}
+TEST(StmtPrinter, TestCXXLamda) {
+ ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
+ "void A() {"
+ " auto l = [] { };"
+ "}",
+ lambdaExpr(anything()).bind("id"),
+ "[] {\n"
+ "}"));
+
+ ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
+ "void A() {"
+ " int a = 0, b = 1;"
+ " auto l = [a,b](int c, float d) { };"
+ "}",
+ lambdaExpr(anything()).bind("id"),
+ "[a, b](int c, float d) {\n"
+ "}"));
+
+ ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX14,
+ "void A() {"
+ " auto l = [](auto a, int b, auto c, int, auto) { };"
+ "}",
+ lambdaExpr(anything()).bind("id"),
+ "[](auto a, int b, auto c, int, auto) {\n"
+ "}"));
+
+ ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX2a,
+ "void A() {"
+ " auto l = []<typename T1, class T2, int I,"
+ " template<class, typename> class T3>"
+ " (int a, auto, int, auto d) { };"
+ "}",
+ lambdaExpr(anything()).bind("id"),
+ "[]<typename T1, class T2, int I, template <class, typename> class T3>(int a, auto, int, auto d) {\n"
+ "}"));
+}
+
TEST(StmtPrinter, TestNoImplicitBases) {
const char *CPPSource = R"(
class A {
--- /dev/null
+//===- unittest/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+
+using namespace clang;
+
+namespace {
+
+// Matches (optional) explicit template parameters.
+class LambdaTemplateParametersVisitor
+ : public ExpectedLocationVisitor<LambdaTemplateParametersVisitor> {
+public:
+ bool shouldVisitImplicitCode() const { return false; }
+
+ bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ EXPECT_FALSE(D->isImplicit());
+ Match(D->getName(), D->getLocStart());
+ return true;
+ }
+
+ bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ EXPECT_FALSE(D->isImplicit());
+ Match(D->getName(), D->getLocStart());
+ return true;
+ }
+
+ bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ EXPECT_FALSE(D->isImplicit());
+ Match(D->getName(), D->getLocStart());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsLambdaExplicitTemplateParameters) {
+ LambdaTemplateParametersVisitor Visitor;
+ Visitor.ExpectMatch("T", 2, 15);
+ Visitor.ExpectMatch("I", 2, 24);
+ Visitor.ExpectMatch("TT", 2, 31);
+ EXPECT_TRUE(Visitor.runOver(
+ "void f() { \n"
+ " auto l = []<class T, int I, template<class> class TT>(auto p) { }; \n"
+ "}",
+ LambdaTemplateParametersVisitor::Lang_CXX2a));
+}
+
+} // end anonymous namespace
<tr>
<td><i>template-parameter-list</i> for generic lambdas</td>
<td><a href="http://wg21.link/p0428r2">P0428R2</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr id="p0734">
<td rowspan="4">Concepts</td>