Implement template support for CapturedStmt
- Sema tests added and CodeGen tests are pending Differential Revision: http://llvm-reviews.chandlerc.com/D728 llvm-svn: 181101
This commit is contained in:
parent
3df61b7bef
commit
17fbf6edc2
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
#include "clang/AST/StmtIterator.h"
|
||||
#include "clang/Basic/CapturedStmt.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
|
@ -1982,16 +1983,16 @@ private:
|
|||
/// \brief The number of variable captured, including 'this'.
|
||||
unsigned NumCaptures;
|
||||
|
||||
/// \brief The implicit outlined function.
|
||||
CapturedDecl *TheCapturedDecl;
|
||||
/// \brief The pointer part is the implicit the outlined function and the
|
||||
/// int part is the captured region kind, 'CR_Default' etc.
|
||||
llvm::PointerIntPair<CapturedDecl *, 1, CapturedRegionKind> CapDeclAndKind;
|
||||
|
||||
/// \brief The record for captured variables, a RecordDecl or CXXRecordDecl.
|
||||
RecordDecl *TheRecordDecl;
|
||||
|
||||
/// \brief Construct a captured statement.
|
||||
CapturedStmt(Stmt *S, ArrayRef<Capture> Captures,
|
||||
ArrayRef<Expr *> CaptureInits,
|
||||
CapturedDecl *CD, RecordDecl *RD);
|
||||
CapturedStmt(Stmt *S, CapturedRegionKind Kind, ArrayRef<Capture> Captures,
|
||||
ArrayRef<Expr *> CaptureInits, CapturedDecl *CD, RecordDecl *RD);
|
||||
|
||||
/// \brief Construct an empty captured statement.
|
||||
CapturedStmt(EmptyShell Empty, unsigned NumCaptures);
|
||||
|
@ -2006,6 +2007,7 @@ private:
|
|||
|
||||
public:
|
||||
static CapturedStmt *Create(ASTContext &Context, Stmt *S,
|
||||
CapturedRegionKind Kind,
|
||||
ArrayRef<Capture> Captures,
|
||||
ArrayRef<Expr *> CaptureInits,
|
||||
CapturedDecl *CD, RecordDecl *RD);
|
||||
|
@ -2020,11 +2022,36 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Retrieve the outlined function declaration.
|
||||
CapturedDecl *getCapturedDecl() const { return TheCapturedDecl; }
|
||||
CapturedDecl *getCapturedDecl() { return CapDeclAndKind.getPointer(); }
|
||||
const CapturedDecl *getCapturedDecl() const {
|
||||
return const_cast<CapturedStmt *>(this)->getCapturedDecl();
|
||||
}
|
||||
|
||||
/// \brief Set the outlined function declaration.
|
||||
void setCapturedDecl(CapturedDecl *D) {
|
||||
assert(D && "null CapturedDecl");
|
||||
CapDeclAndKind.setPointer(D);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the captured region kind.
|
||||
CapturedRegionKind getCapturedRegionKind() const {
|
||||
return CapDeclAndKind.getInt();
|
||||
}
|
||||
|
||||
/// \brief Set the captured region kind.
|
||||
void setCapturedRegionKind(CapturedRegionKind Kind) {
|
||||
CapDeclAndKind.setInt(Kind);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the record declaration for captured variables.
|
||||
const RecordDecl *getCapturedRecordDecl() const { return TheRecordDecl; }
|
||||
|
||||
/// \brief Set the record declaration for captured variables.
|
||||
void setCapturedRecordDecl(RecordDecl *D) {
|
||||
assert(D && "null RecordDecl");
|
||||
TheRecordDecl = D;
|
||||
}
|
||||
|
||||
/// \brief True if this variable has been captured.
|
||||
bool capturesVariable(const VarDecl *Var) const;
|
||||
|
||||
|
|
|
@ -2798,7 +2798,7 @@ public:
|
|||
void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
|
||||
CapturedRegionKind Kind, unsigned NumParams);
|
||||
StmtResult ActOnCapturedRegionEnd(Stmt *S);
|
||||
void ActOnCapturedRegionError(bool IsInstantiation = false);
|
||||
void ActOnCapturedRegionError();
|
||||
RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD,
|
||||
SourceLocation Loc,
|
||||
unsigned NumParams);
|
||||
|
|
|
@ -1049,12 +1049,13 @@ CapturedStmt::Capture *CapturedStmt::getStoredCaptures() const {
|
|||
+ FirstCaptureOffset);
|
||||
}
|
||||
|
||||
CapturedStmt::CapturedStmt(Stmt *S, ArrayRef<Capture> Captures,
|
||||
CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind,
|
||||
ArrayRef<Capture> Captures,
|
||||
ArrayRef<Expr *> CaptureInits,
|
||||
CapturedDecl *CD,
|
||||
RecordDecl *RD)
|
||||
: Stmt(CapturedStmtClass), NumCaptures(Captures.size()),
|
||||
TheCapturedDecl(CD), TheRecordDecl(RD) {
|
||||
CapDeclAndKind(CD, Kind), TheRecordDecl(RD) {
|
||||
assert( S && "null captured statement");
|
||||
assert(CD && "null captured declaration for captured statement");
|
||||
assert(RD && "null record declaration for captured statement");
|
||||
|
@ -1074,11 +1075,12 @@ CapturedStmt::CapturedStmt(Stmt *S, ArrayRef<Capture> Captures,
|
|||
|
||||
CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures)
|
||||
: Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures),
|
||||
TheCapturedDecl(0), TheRecordDecl(0) {
|
||||
CapDeclAndKind(0, CR_Default), TheRecordDecl(0) {
|
||||
getStoredStmts()[NumCaptures] = 0;
|
||||
}
|
||||
|
||||
CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S,
|
||||
CapturedRegionKind Kind,
|
||||
ArrayRef<Capture> Captures,
|
||||
ArrayRef<Expr *> CaptureInits,
|
||||
CapturedDecl *CD,
|
||||
|
@ -1102,7 +1104,7 @@ CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S,
|
|||
}
|
||||
|
||||
void *Mem = Context.Allocate(Size);
|
||||
return new (Mem) CapturedStmt(S, Captures, CaptureInits, CD, RD);
|
||||
return new (Mem) CapturedStmt(S, Kind, Captures, CaptureInits, CD, RD);
|
||||
}
|
||||
|
||||
CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context,
|
||||
|
|
|
@ -2981,7 +2981,8 @@ static void buildCapturedStmtCaptureList(
|
|||
}
|
||||
|
||||
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
|
||||
CapturedRegionKind Kind, unsigned NumParams) {
|
||||
CapturedRegionKind Kind,
|
||||
unsigned NumParams) {
|
||||
CapturedDecl *CD = 0;
|
||||
RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, NumParams);
|
||||
|
||||
|
@ -2996,13 +2997,10 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
|
|||
PushExpressionEvaluationContext(PotentiallyEvaluated);
|
||||
}
|
||||
|
||||
void Sema::ActOnCapturedRegionError(bool IsInstantiation) {
|
||||
void Sema::ActOnCapturedRegionError() {
|
||||
DiscardCleanupsInEvaluationContext();
|
||||
PopExpressionEvaluationContext();
|
||||
|
||||
if (!IsInstantiation)
|
||||
PopDeclContext();
|
||||
|
||||
CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
|
||||
RecordDecl *Record = RSI->TheRecordDecl;
|
||||
Record->setInvalidDecl();
|
||||
|
@ -3014,6 +3012,7 @@ void Sema::ActOnCapturedRegionError(bool IsInstantiation) {
|
|||
ActOnFields(/*Scope=*/0, Record->getLocation(), Record, Fields,
|
||||
SourceLocation(), SourceLocation(), /*AttributeList=*/0);
|
||||
|
||||
PopDeclContext();
|
||||
PopFunctionScopeInfo();
|
||||
}
|
||||
|
||||
|
@ -3027,12 +3026,16 @@ StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) {
|
|||
CapturedDecl *CD = RSI->TheCapturedDecl;
|
||||
RecordDecl *RD = RSI->TheRecordDecl;
|
||||
|
||||
CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S, Captures,
|
||||
CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S,
|
||||
RSI->CapRegionKind, Captures,
|
||||
CaptureInits, CD, RD);
|
||||
|
||||
CD->setBody(Res->getCapturedStmt());
|
||||
RD->completeDefinition();
|
||||
|
||||
DiscardCleanupsInEvaluationContext();
|
||||
PopExpressionEvaluationContext();
|
||||
|
||||
PopDeclContext();
|
||||
PopFunctionScopeInfo();
|
||||
|
||||
|
|
|
@ -9449,7 +9449,18 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
|
|||
template<typename Derived>
|
||||
StmtResult
|
||||
TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) {
|
||||
llvm_unreachable("not implement yet");
|
||||
SourceLocation Loc = S->getLocStart();
|
||||
unsigned NumParams = S->getCapturedDecl()->getNumParams();
|
||||
getSema().ActOnCapturedRegionStart(Loc, /*CurScope*/0,
|
||||
S->getCapturedRegionKind(), NumParams);
|
||||
StmtResult Body = getDerived().TransformStmt(S->getCapturedStmt());
|
||||
|
||||
if (Body.isInvalid()) {
|
||||
getSema().ActOnCapturedRegionError();
|
||||
return StmtError();
|
||||
}
|
||||
|
||||
return getSema().ActOnCapturedRegionEnd(Body.take());
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -382,8 +382,9 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
|
|||
|
||||
void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
|
||||
VisitStmt(S);
|
||||
S->TheCapturedDecl = ReadDeclAs<CapturedDecl>(Record, Idx);
|
||||
S->TheRecordDecl = ReadDeclAs<RecordDecl>(Record, Idx);
|
||||
S->setCapturedDecl(ReadDeclAs<CapturedDecl>(Record, Idx));
|
||||
S->setCapturedRegionKind(static_cast<CapturedRegionKind>(Record[Idx++]));
|
||||
S->setCapturedRecordDecl(ReadDeclAs<RecordDecl>(Record, Idx));
|
||||
|
||||
// Capture inits
|
||||
for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(),
|
||||
|
@ -393,7 +394,7 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
|
|||
|
||||
// Body
|
||||
S->setCapturedStmt(Reader.ReadSubStmt());
|
||||
S->TheCapturedDecl->setBody(S->getCapturedStmt());
|
||||
S->getCapturedDecl()->setBody(S->getCapturedStmt());
|
||||
|
||||
// Captures
|
||||
for (CapturedStmt::capture_iterator I = S->capture_begin(),
|
||||
|
|
|
@ -290,7 +290,10 @@ void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
|
|||
// NumCaptures
|
||||
Record.push_back(std::distance(S->capture_begin(), S->capture_end()));
|
||||
|
||||
// CapturedDecl and captured region kind
|
||||
Writer.AddDeclRef(S->getCapturedDecl(), Record);
|
||||
Record.push_back(S->getCapturedRegionKind());
|
||||
|
||||
Writer.AddDeclRef(S->getCapturedRecordDecl(), Record);
|
||||
|
||||
// Capture inits
|
||||
|
|
|
@ -50,3 +50,117 @@ class test_this_capture {
|
|||
{ b(); } // OK
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void template_capture_var() {
|
||||
T x; // expected-error{{declaration of reference variable 'x' requires an initializer}}
|
||||
#pragma clang _debug captured
|
||||
{
|
||||
(void)x;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class Val {
|
||||
T v;
|
||||
public:
|
||||
void set(const T &v0) {
|
||||
#pragma clang __debug captured
|
||||
{
|
||||
v = v0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void test_capture_var() {
|
||||
template_capture_var<int>(); // OK
|
||||
template_capture_var<int&>(); // expected-note{{in instantiation of function template specialization 'template_capture_var<int &>' requested here}}
|
||||
|
||||
Val<float> Obj;
|
||||
Obj.set(0.0f); // OK
|
||||
}
|
||||
|
||||
template <typename S, typename T>
|
||||
S template_capture_var(S x, T y) {
|
||||
#pragma clang _debug captured
|
||||
{
|
||||
x++;
|
||||
y++; // expected-error{{read-only variable is not assignable}}
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Check if can recover from a template error.
|
||||
void test_capture_var_error() {
|
||||
template_capture_var<int, int>(0, 1); // OK
|
||||
template_capture_var<int, const int>(0, 1); // expected-note{{in instantiation of function template specialization 'template_capture_var<int, const int>' requested here}}
|
||||
template_capture_var<int, int>(0, 1); // OK
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void template_capture_in_lambda() {
|
||||
T x, y;
|
||||
[=, &y]() {
|
||||
#pragma clang __debug captured
|
||||
{
|
||||
y += x;
|
||||
}
|
||||
}();
|
||||
}
|
||||
|
||||
void test_lambda() {
|
||||
template_capture_in_lambda<int>(); // OK
|
||||
}
|
||||
|
||||
struct Foo {
|
||||
void foo() { }
|
||||
static void bar() { }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void template_capture_func(T &t) {
|
||||
#pragma clang __debug captured
|
||||
{
|
||||
t.foo();
|
||||
}
|
||||
|
||||
#pragma clang __debug captured
|
||||
{
|
||||
T::bar();
|
||||
}
|
||||
}
|
||||
|
||||
void test_template_capture_func() {
|
||||
Foo Obj;
|
||||
template_capture_func(Obj);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T captured_sum(const T &a, const T &b) {
|
||||
T result;
|
||||
|
||||
#pragma clang __debug captured
|
||||
{
|
||||
result = a + b;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T captured_sum(const T &a, const Args&... args) {
|
||||
T result;
|
||||
|
||||
#pragma clang __debug captured
|
||||
{
|
||||
result = a + captured_sum(args...);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void test_capture_variadic() {
|
||||
(void)captured_sum(1, 2, 3); // OK
|
||||
(void)captured_sum(1, 2, 3, 4, 5); // OK
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue