Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit e81d7e9

Browse files
committed
Lambdas: semantic analysis of explicit captures.
This patch (and some of my other commits related to lambdas) is heavily based off of John Freeman's work-in-progress patches. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147706 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 3070e13 commit e81d7e9

File tree

4 files changed

+151
-8
lines changed

4 files changed

+151
-8
lines changed

include/clang/Basic/DiagnosticSemaKinds.td

+12
Original file line numberDiff line numberDiff line change
@@ -3992,6 +3992,18 @@ def err_return_in_constructor_handler : Error<
39923992
"return in the catch of a function try block of a constructor is illegal">;
39933993

39943994
def err_lambda_unsupported : Error<"lambda expressions are not supported yet">;
3995+
def err_capture_more_than_once : Error<
3996+
"%0 can appear only once in a capture list">;
3997+
def err_reference_capture_with_reference_default : Error<
3998+
"'&' cannot precede a capture when the capture default is '&'">;
3999+
def err_this_capture_with_copy_default : Error<
4000+
"'this' cannot appear in a capture list when the capture default is '='">;
4001+
def err_copy_capture_with_copy_default : Error<
4002+
"'&' must precede a capture when the capture default is '='">;
4003+
def err_capture_does_not_name_variable : Error<
4004+
"%0 in capture list does not name a variable">;
4005+
def err_capture_non_automatic_variable : Error<
4006+
"%0 cannot be captured because it does not have automatic storage duration">;
39954007

39964008
def err_operator_arrow_circular : Error<
39974009
"circular pointer delegation detected">;

include/clang/Sema/ScopeInfo.h

+24-3
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,29 @@ class BlockScopeInfo : public FunctionScopeInfo {
160160

161161
class LambdaScopeInfo : public FunctionScopeInfo {
162162
public:
163+
164+
class Capture {
165+
llvm::PointerIntPair<VarDecl*, 2, LambdaCaptureKind> InitAndKind;
166+
167+
public:
168+
Capture(VarDecl *Var, LambdaCaptureKind Kind)
169+
: InitAndKind(Var, Kind) {}
170+
171+
enum IsThisCapture { ThisCapture };
172+
Capture(IsThisCapture)
173+
: InitAndKind(0, LCK_This) {}
174+
175+
bool isThisCapture() const { return InitAndKind.getInt() == LCK_This; }
176+
bool isVariableCapture() const { return !isThisCapture(); }
177+
bool isCopyCapture() const { return InitAndKind.getInt() == LCK_ByCopy; }
178+
bool isReferenceCapture() const { return InitAndKind.getInt() == LCK_ByRef; }
179+
180+
VarDecl *getVariable() const {
181+
return InitAndKind.getPointer();
182+
}
183+
184+
};
185+
163186
/// \brief The class that describes the lambda.
164187
CXXRecordDecl *Lambda;
165188

@@ -169,9 +192,7 @@ class LambdaScopeInfo : public FunctionScopeInfo {
169192

170193
/// \brief The list of captured variables, starting with the explicit
171194
/// captures and then finishing with any implicit captures.
172-
// TODO: This is commented out until an implementation of LambdaExpr is
173-
// committed.
174-
// llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
195+
llvm::SmallVector<Capture, 4> Captures;
175196

176197
/// \brief The number of captures in the \c Captures list that are
177198
/// explicit captures.

lib/Sema/SemaExprCXX.cpp

+78-5
Original file line numberDiff line numberDiff line change
@@ -4793,6 +4793,84 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
47934793
Class->startDefinition();
47944794
CurContext->addDecl(Class);
47954795

4796+
// Introduce the lambda scope.
4797+
PushLambdaScope(Class);
4798+
4799+
LambdaScopeInfo *LSI = getCurLambda();
4800+
4801+
QualType ThisCaptureType;
4802+
llvm::DenseMap<const IdentifierInfo*, SourceLocation> CapturesSoFar;
4803+
for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
4804+
C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) {
4805+
if (C->Kind == LCK_This) {
4806+
if (!ThisCaptureType.isNull()) {
4807+
Diag(C->Loc, diag::err_capture_more_than_once) << "'this'";
4808+
continue;
4809+
}
4810+
4811+
if (Intro.Default == LCD_ByCopy) {
4812+
Diag(C->Loc, diag::err_this_capture_with_copy_default);
4813+
continue;
4814+
}
4815+
4816+
ThisCaptureType = getCurrentThisType();
4817+
4818+
if (ThisCaptureType.isNull()) {
4819+
Diag(C->Loc, diag::err_invalid_this_use);
4820+
continue;
4821+
}
4822+
LSI->Captures.push_back(LambdaScopeInfo::Capture::ThisCapture);
4823+
continue;
4824+
}
4825+
4826+
assert(C->Id && "missing identifier for capture");
4827+
4828+
if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
4829+
Diag(C->Loc, diag::err_reference_capture_with_reference_default);
4830+
continue;
4831+
} else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
4832+
Diag(C->Loc, diag::err_copy_capture_with_copy_default);
4833+
continue;
4834+
}
4835+
4836+
llvm::DenseMap<const IdentifierInfo*, SourceLocation>::iterator Appearance;
4837+
bool IsFirstAppearance;
4838+
llvm::tie(Appearance, IsFirstAppearance)
4839+
= CapturesSoFar.insert(std::make_pair(C->Id, C->Loc));
4840+
4841+
if (!IsFirstAppearance) {
4842+
Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
4843+
continue;
4844+
}
4845+
4846+
DeclarationNameInfo Name(C->Id, C->Loc);
4847+
LookupResult R(*this, Name, LookupOrdinaryName);
4848+
CXXScopeSpec ScopeSpec;
4849+
LookupParsedName(R, CurScope, &ScopeSpec);
4850+
if (R.isAmbiguous())
4851+
continue;
4852+
if (R.empty())
4853+
if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, CTC_Unknown))
4854+
continue;
4855+
4856+
VarDecl *Var = R.getAsSingle<VarDecl>();
4857+
if (!Var) {
4858+
Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
4859+
continue;
4860+
}
4861+
4862+
if (!Var->hasLocalStorage()) {
4863+
Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
4864+
continue;
4865+
}
4866+
4867+
// FIXME: Actually capturing a variable is much more complicated than this
4868+
// in the general case; see shouldCaptureValueReference.
4869+
// FIXME: Should we be building a DeclRefExpr here? We don't really need
4870+
// it until the point where we're actually building the LambdaExpr.
4871+
LSI->Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind));
4872+
}
4873+
47964874
// Build the call operator; we don't really have all the relevant information
47974875
// at this point, but we need something to attach child declarations to.
47984876
QualType MethodTy;
@@ -4837,17 +4915,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
48374915

48384916
ProcessDeclAttributes(CurScope, Method, ParamInfo);
48394917

4840-
// Introduce the lambda scope.
4841-
PushLambdaScope(Class);
4842-
48434918
// Enter a new evaluation context to insulate the block from any
48444919
// cleanups from the enclosing full-expression.
48454920
PushExpressionEvaluationContext(PotentiallyEvaluated);
48464921

48474922
PushDeclContext(CurScope, Method);
48484923

4849-
LambdaScopeInfo *LSI = getCurLambda();
4850-
48514924
// Set the parameters on the decl, if specified.
48524925
if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
48534926
FunctionProtoTypeLoc Proto =

test/SemaCXX/lambda-expressions.cpp

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
2+
3+
namespace ExplicitCapture {
4+
int GlobalVar; // expected-note {{declared here}}
5+
6+
namespace N {
7+
int AmbiguousVar; // expected-note {{candidate}}
8+
}
9+
int AmbiguousVar; // expected-note {{candidate}}
10+
using namespace N;
11+
12+
class C {
13+
int x;
14+
15+
void f(int);
16+
void f() {
17+
int foo;
18+
19+
[foo, foo] () {}; // expected-error {{'foo' can appear only once}} expected-error {{not supported yet}}
20+
[this, this] () {}; // expected-error {{'this' can appear only once}} expected-error {{not supported yet}}
21+
[=, foo] () {}; // expected-error {{'&' must precede a capture when}} expected-error {{not supported yet}}
22+
[=, &foo] () {}; // expected-error {{not supported yet}}
23+
[=, this] () {}; // expected-error {{'this' cannot appear}} expected-error {{not supported yet}}
24+
[&, foo] () {}; // expected-error {{not supported yet}}
25+
[&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}} expected-error {{not supported yet}}
26+
[&, this] () {}; // expected-error {{not supported yet}}
27+
[&f] () {}; // expected-error {{does not name a variable}} expected-error {{not supported yet}}
28+
[&GlobalVar] () {}; // expected-error {{does not have automatic storage duration}} expected-error {{not supported yet}}
29+
[&AmbiguousVar] () {} // expected-error {{reference to 'AmbiguousVar' is ambiguous}} expected-error {{not supported yet}}
30+
[&Globalvar] () {}; // expected-error {{use of undeclared identifier 'Globalvar'; did you mean 'GlobalVar}}
31+
}
32+
};
33+
34+
void f() {
35+
[this] () {}; // expected-error {{invalid use of 'this'}} expected-error {{not supported yet}}
36+
}
37+
}

0 commit comments

Comments
 (0)