зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
3070e13dca
Коммит
e81d7e9810
|
@ -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}}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче