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:
Wei Pan 2013-05-04 03:59:06 +00:00
parent 3df61b7bef
commit 17fbf6edc2
8 changed files with 182 additions and 21 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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();

View File

@ -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

View File

@ -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(),

View File

@ -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

View File

@ -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
}