зеркало из 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">;
|
"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_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<
|
def err_operator_arrow_circular : Error<
|
||||||
"circular pointer delegation detected">;
|
"circular pointer delegation detected">;
|
||||||
|
|
|
@ -160,6 +160,29 @@ public:
|
||||||
|
|
||||||
class LambdaScopeInfo : public FunctionScopeInfo {
|
class LambdaScopeInfo : public FunctionScopeInfo {
|
||||||
public:
|
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.
|
/// \brief The class that describes the lambda.
|
||||||
CXXRecordDecl *Lambda;
|
CXXRecordDecl *Lambda;
|
||||||
|
|
||||||
|
@ -169,9 +192,7 @@ public:
|
||||||
|
|
||||||
/// \brief The list of captured variables, starting with the explicit
|
/// \brief The list of captured variables, starting with the explicit
|
||||||
/// captures and then finishing with any implicit captures.
|
/// captures and then finishing with any implicit captures.
|
||||||
// TODO: This is commented out until an implementation of LambdaExpr is
|
llvm::SmallVector<Capture, 4> Captures;
|
||||||
// committed.
|
|
||||||
// llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
|
|
||||||
|
|
||||||
/// \brief The number of captures in the \c Captures list that are
|
/// \brief The number of captures in the \c Captures list that are
|
||||||
/// explicit captures.
|
/// explicit captures.
|
||||||
|
|
|
@ -4793,6 +4793,84 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||||
Class->startDefinition();
|
Class->startDefinition();
|
||||||
CurContext->addDecl(Class);
|
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
|
// 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.
|
// at this point, but we need something to attach child declarations to.
|
||||||
QualType MethodTy;
|
QualType MethodTy;
|
||||||
|
@ -4837,17 +4915,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||||
|
|
||||||
ProcessDeclAttributes(CurScope, Method, ParamInfo);
|
ProcessDeclAttributes(CurScope, Method, ParamInfo);
|
||||||
|
|
||||||
// Introduce the lambda scope.
|
|
||||||
PushLambdaScope(Class);
|
|
||||||
|
|
||||||
// Enter a new evaluation context to insulate the block from any
|
// Enter a new evaluation context to insulate the block from any
|
||||||
// cleanups from the enclosing full-expression.
|
// cleanups from the enclosing full-expression.
|
||||||
PushExpressionEvaluationContext(PotentiallyEvaluated);
|
PushExpressionEvaluationContext(PotentiallyEvaluated);
|
||||||
|
|
||||||
PushDeclContext(CurScope, Method);
|
PushDeclContext(CurScope, Method);
|
||||||
|
|
||||||
LambdaScopeInfo *LSI = getCurLambda();
|
|
||||||
|
|
||||||
// Set the parameters on the decl, if specified.
|
// Set the parameters on the decl, if specified.
|
||||||
if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
|
if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
|
||||||
FunctionProtoTypeLoc Proto =
|
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}}
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче