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
This commit is contained in:
Eli Friedman 2012-01-07 01:08:17 +00:00
Родитель 3070e13dca
Коммит e81d7e9810
4 изменённых файлов: 151 добавлений и 8 удалений

Просмотреть файл

@ -3992,6 +3992,18 @@ def err_return_in_constructor_handler : Error<
"return in the catch of a function try block of a constructor is illegal">;
def err_lambda_unsupported : Error<"lambda expressions are not supported yet">;
def err_capture_more_than_once : Error<
"%0 can appear only once in a capture list">;
def err_reference_capture_with_reference_default : Error<
"'&' cannot precede a capture when the capture default is '&'">;
def err_this_capture_with_copy_default : Error<
"'this' cannot appear in a capture list when the capture default is '='">;
def err_copy_capture_with_copy_default : Error<
"'&' must precede a capture when the capture default is '='">;
def err_capture_does_not_name_variable : Error<
"%0 in capture list does not name a variable">;
def err_capture_non_automatic_variable : Error<
"%0 cannot be captured because it does not have automatic storage duration">;
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;

Просмотреть файл

@ -160,6 +160,29 @@ public:
class LambdaScopeInfo : public FunctionScopeInfo {
public:
class Capture {
llvm::PointerIntPair<VarDecl*, 2, LambdaCaptureKind> InitAndKind;
public:
Capture(VarDecl *Var, LambdaCaptureKind Kind)
: InitAndKind(Var, Kind) {}
enum IsThisCapture { ThisCapture };
Capture(IsThisCapture)
: InitAndKind(0, LCK_This) {}
bool isThisCapture() const { return InitAndKind.getInt() == LCK_This; }
bool isVariableCapture() const { return !isThisCapture(); }
bool isCopyCapture() const { return InitAndKind.getInt() == LCK_ByCopy; }
bool isReferenceCapture() const { return InitAndKind.getInt() == LCK_ByRef; }
VarDecl *getVariable() const {
return InitAndKind.getPointer();
}
};
/// \brief The class that describes the lambda.
CXXRecordDecl *Lambda;
@ -169,9 +192,7 @@ public:
/// \brief The list of captured variables, starting with the explicit
/// captures and then finishing with any implicit captures.
// TODO: This is commented out until an implementation of LambdaExpr is
// committed.
// llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
llvm::SmallVector<Capture, 4> Captures;
/// \brief The number of captures in the \c Captures list that are
/// explicit captures.

Просмотреть файл

@ -4793,6 +4793,84 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Class->startDefinition();
CurContext->addDecl(Class);
// Introduce the lambda scope.
PushLambdaScope(Class);
LambdaScopeInfo *LSI = getCurLambda();
QualType ThisCaptureType;
llvm::DenseMap<const IdentifierInfo*, SourceLocation> CapturesSoFar;
for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; ++C) {
if (C->Kind == LCK_This) {
if (!ThisCaptureType.isNull()) {
Diag(C->Loc, diag::err_capture_more_than_once) << "'this'";
continue;
}
if (Intro.Default == LCD_ByCopy) {
Diag(C->Loc, diag::err_this_capture_with_copy_default);
continue;
}
ThisCaptureType = getCurrentThisType();
if (ThisCaptureType.isNull()) {
Diag(C->Loc, diag::err_invalid_this_use);
continue;
}
LSI->Captures.push_back(LambdaScopeInfo::Capture::ThisCapture);
continue;
}
assert(C->Id && "missing identifier for capture");
if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
Diag(C->Loc, diag::err_reference_capture_with_reference_default);
continue;
} else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
Diag(C->Loc, diag::err_copy_capture_with_copy_default);
continue;
}
llvm::DenseMap<const IdentifierInfo*, SourceLocation>::iterator Appearance;
bool IsFirstAppearance;
llvm::tie(Appearance, IsFirstAppearance)
= CapturesSoFar.insert(std::make_pair(C->Id, C->Loc));
if (!IsFirstAppearance) {
Diag(C->Loc, diag::err_capture_more_than_once) << C->Id;
continue;
}
DeclarationNameInfo Name(C->Id, C->Loc);
LookupResult R(*this, Name, LookupOrdinaryName);
CXXScopeSpec ScopeSpec;
LookupParsedName(R, CurScope, &ScopeSpec);
if (R.isAmbiguous())
continue;
if (R.empty())
if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, CTC_Unknown))
continue;
VarDecl *Var = R.getAsSingle<VarDecl>();
if (!Var) {
Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id;
continue;
}
if (!Var->hasLocalStorage()) {
Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
continue;
}
// FIXME: Actually capturing a variable is much more complicated than this
// in the general case; see shouldCaptureValueReference.
// FIXME: Should we be building a DeclRefExpr here? We don't really need
// it until the point where we're actually building the LambdaExpr.
LSI->Captures.push_back(LambdaScopeInfo::Capture(Var, C->Kind));
}
// Build the call operator; we don't really have all the relevant information
// at this point, but we need something to attach child declarations to.
QualType MethodTy;
@ -4837,17 +4915,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
ProcessDeclAttributes(CurScope, Method, ParamInfo);
// Introduce the lambda scope.
PushLambdaScope(Class);
// Enter a new evaluation context to insulate the block from any
// cleanups from the enclosing full-expression.
PushExpressionEvaluationContext(PotentiallyEvaluated);
PushDeclContext(CurScope, Method);
LambdaScopeInfo *LSI = getCurLambda();
// Set the parameters on the decl, if specified.
if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
FunctionProtoTypeLoc Proto =

Просмотреть файл

@ -0,0 +1,37 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
namespace ExplicitCapture {
int GlobalVar; // expected-note {{declared here}}
namespace N {
int AmbiguousVar; // expected-note {{candidate}}
}
int AmbiguousVar; // expected-note {{candidate}}
using namespace N;
class C {
int x;
void f(int);
void f() {
int foo;
[foo, foo] () {}; // expected-error {{'foo' can appear only once}} expected-error {{not supported yet}}
[this, this] () {}; // expected-error {{'this' can appear only once}} expected-error {{not supported yet}}
[=, foo] () {}; // expected-error {{'&' must precede a capture when}} expected-error {{not supported yet}}
[=, &foo] () {}; // expected-error {{not supported yet}}
[=, this] () {}; // expected-error {{'this' cannot appear}} expected-error {{not supported yet}}
[&, foo] () {}; // expected-error {{not supported yet}}
[&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}} expected-error {{not supported yet}}
[&, this] () {}; // expected-error {{not supported yet}}
[&f] () {}; // expected-error {{does not name a variable}} expected-error {{not supported yet}}
[&GlobalVar] () {}; // expected-error {{does not have automatic storage duration}} expected-error {{not supported yet}}
[&AmbiguousVar] () {} // expected-error {{reference to 'AmbiguousVar' is ambiguous}} expected-error {{not supported yet}}
[&Globalvar] () {}; // expected-error {{use of undeclared identifier 'Globalvar'; did you mean 'GlobalVar}}
}
};
void f() {
[this] () {}; // expected-error {{invalid use of 'this'}} expected-error {{not supported yet}}
}
}