2012-09-05 09:37:39 +00:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author: Vassil Vassilev <vvasielv@cern.ch>
//------------------------------------------------------------------------------
2012-10-02 10:30:25 +00:00
# include "cling/Interpreter/Transaction.h"
2012-09-05 09:37:39 +00:00
2012-10-19 11:49:49 +00:00
# include "cling/Utils/AST.h"
2012-10-01 11:47:27 +00:00
# include "clang/AST/ASTContext.h"
2012-09-05 09:37:39 +00:00
# include "clang/AST/DeclBase.h"
2012-10-01 11:47:27 +00:00
# include "clang/AST/PrettyPrinter.h"
2013-04-24 16:28:08 +00:00
# include "llvm/Support/raw_ostream.h"
2013-10-25 15:22:45 +02:00
# include "clang/Lex/MacroInfo.h"
2012-09-05 09:37:39 +00:00
using namespace clang ;
namespace cling {
2013-08-26 17:56:09 +02:00
Transaction : : Transaction ( ASTContext & C ) : m_ASTContext ( C ) {
2013-08-04 18:31:52 +02:00
Initialize ( C ) ;
2013-07-06 12:18:59 +02:00
}
2013-08-26 17:56:09 +02:00
Transaction : : Transaction ( const CompilationOptions & Opts , ASTContext & C )
2013-08-04 18:31:52 +02:00
: m_ASTContext ( C ) {
Initialize ( C ) ;
2013-07-06 12:18:59 +02:00
m_Opts = Opts ; // intentional copy.
}
2013-08-26 17:56:09 +02:00
void Transaction : : Initialize ( ASTContext & C ) {
2013-07-06 12:18:59 +02:00
m_NestedTransactions . reset ( 0 ) ;
m_Parent = 0 ;
m_State = kCollecting ;
m_IssuedDiags = kNone ;
m_Opts = CompilationOptions ( ) ;
m_Module = 0 ;
m_WrapperFD = 0 ;
m_Next = 0 ;
2013-08-04 18:31:52 +02:00
//m_ASTContext = C;
2013-07-06 12:18:59 +02:00
}
2012-09-05 09:37:39 +00:00
Transaction : : ~ Transaction ( ) {
2013-04-08 14:27:57 +00:00
if ( hasNestedTransactions ( ) )
2013-06-13 12:45:15 +02:00
for ( size_t i = 0 ; i < m_NestedTransactions - > size ( ) ; + + i ) {
2013-11-27 13:58:37 +01:00
assert ( ( ( * m_NestedTransactions ) [ i ] - > getState ( ) = = kCommitted
| | ( * m_NestedTransactions ) [ i ] - > getState ( ) = = kRolledBack )
2013-06-13 12:45:15 +02:00
& & " All nested transactions must be committed! " ) ;
2013-04-08 14:27:57 +00:00
delete ( * m_NestedTransactions ) [ i ] ;
2013-06-13 12:45:15 +02:00
}
2012-09-05 09:37:39 +00:00
}
2013-07-06 12:16:35 +02:00
void Transaction : : addNestedTransaction ( Transaction * nested ) {
// Create lazily the list
if ( ! m_NestedTransactions )
m_NestedTransactions . reset ( new NestedTransactions ( ) ) ;
nested - > setParent ( this ) ;
// Leave a marker in the parent transaction, where the nested transaction
// started.
DelayCallInfo marker ( clang : : DeclGroupRef ( ) , Transaction : : kCCINone ) ;
2013-07-06 12:53:54 +02:00
m_DeclQueue . push_back ( marker ) ;
2013-07-06 12:16:35 +02:00
m_NestedTransactions - > push_back ( nested ) ;
}
2013-06-20 18:21:21 +02:00
void Transaction : : removeNestedTransaction ( Transaction * nested ) {
assert ( hasNestedTransactions ( ) & & " Does not contain nested transactions " ) ;
int nestedPos = - 1 ;
for ( size_t i = 0 ; i < m_NestedTransactions - > size ( ) ; + + i )
if ( ( * m_NestedTransactions ) [ i ] = = nested ) {
nestedPos = i ;
break ;
}
assert ( nestedPos > - 1 & & " Not found!? " ) ;
m_NestedTransactions - > erase ( m_NestedTransactions - > begin ( ) + nestedPos ) ;
// We need to remove the marker too.
2013-07-06 12:28:52 +02:00
int markerPos = - 1 ;
2013-11-25 14:26:15 +01:00
for ( iterator I = decls_begin ( ) , E = decls_end ( ) ; I ! = E ; + + I ) {
if ( I - > m_DGR . isNull ( ) & & I - > m_Call = = kCCINone ) {
2013-07-06 12:28:52 +02:00
+ + markerPos ;
if ( nestedPos = = markerPos ) {
2013-11-25 14:26:15 +01:00
erase ( I ) ; // Safe because of the break stmt.
2013-07-06 12:28:52 +02:00
break ;
}
2013-06-20 18:21:21 +02:00
}
}
2013-07-06 12:53:54 +02:00
if ( ! m_NestedTransactions - > size ( ) )
m_NestedTransactions . reset ( 0 ) ;
2013-06-20 18:21:21 +02:00
}
void Transaction : : reset ( ) {
2013-10-29 15:14:50 -05:00
assert ( ( empty ( ) | | getState ( ) = = kRolledBack )
& & " The transaction must be empty. " ) ;
2013-06-20 18:21:21 +02:00
if ( Transaction * parent = getParent ( ) )
parent - > removeNestedTransaction ( this ) ;
m_Parent = 0 ;
m_State = kCollecting ;
m_IssuedDiags = kNone ;
m_Opts = CompilationOptions ( ) ;
2013-07-06 12:53:54 +02:00
m_NestedTransactions . reset ( 0 ) ; // FIXME: leaks the nested transactions.
m_Module = 0 ;
2013-06-20 18:21:21 +02:00
m_WrapperFD = 0 ;
m_Next = 0 ;
}
2012-12-03 14:27:12 +00:00
void Transaction : : append ( DelayCallInfo DCI ) {
2013-06-12 14:48:47 +02:00
assert ( ! DCI . m_DGR . isNull ( ) & & " Appending null DGR?! " ) ;
2013-06-13 12:47:16 +02:00
assert ( getState ( ) = = kCollecting
& & " Cannot append declarations in current state. " ) ;
2013-06-13 14:53:58 +02:00
forceAppend ( DCI ) ;
}
void Transaction : : forceAppend ( DelayCallInfo DCI ) {
assert ( ! DCI . m_DGR . isNull ( ) & & " Appending null DGR?! " ) ;
2013-07-31 09:04:30 +02:00
assert ( ( getState ( ) = = kCollecting | | getState ( ) = = kCompleted )
& & " Must not be " ) ;
2013-06-21 15:39:28 +02:00
2013-09-10 12:41:41 +02:00
bool checkForWrapper = ! m_WrapperFD ;
2013-06-26 14:56:11 +02:00
# ifndef NDEBUG
2013-06-21 15:39:28 +02:00
// Check for duplicates
2013-07-06 12:53:54 +02:00
for ( size_t i = 0 , e = m_DeclQueue . size ( ) ; i < e ; + + i ) {
DelayCallInfo & oldDCI ( m_DeclQueue [ i ] ) ;
2013-08-08 14:50:44 +02:00
// FIXME: This is possible bug in clang, which will instantiate one and
// the same CXXStaticMemberVar several times. This happens when there are
// two dependent expressions and the first uses another declaration from
// the redeclaration chain. This will force Sema in to instantiate the
// definition (usually the most recent decl in the chain) and then the
// second expression might referece the definition (which was already)
// instantiated, but Sema seems not to keep track of these kinds of
// instantiations, even though the points of instantiation are the same!
//
// This should be investigated further when we merge with newest clang.
// This is triggered by running the roottest: ./root/io/newstl
if ( oldDCI . m_Call = = kCCIHandleCXXStaticMemberVarInstantiation )
continue ;
2013-06-27 14:54:40 +02:00
// It is possible to have duplicate calls to HandleVTable with the same
// declaration, because each time Sema believes a vtable is used it emits
// that callback.
// For reference (clang::CodeGen::CodeGenModule::EmitVTable).
if ( oldDCI . m_Call ! = kCCIHandleVTable )
assert ( oldDCI ! = DCI & & " Duplicates?! " ) ;
}
2013-09-10 12:41:41 +02:00
// We want to assert there is only one wrapper per transaction.
checkForWrapper = true ;
2013-06-21 15:39:28 +02:00
# endif
2013-09-10 12:41:41 +02:00
2013-04-09 08:47:47 +00:00
// register the wrapper if any.
2013-09-10 12:41:41 +02:00
if ( checkForWrapper & & ! DCI . m_DGR . isNull ( ) & & DCI . m_DGR . isSingleDecl ( ) ) {
2013-09-10 12:35:39 +02:00
if ( FunctionDecl * FD = dyn_cast < FunctionDecl > ( DCI . m_DGR . getSingleDecl ( ) ) ) {
2013-08-27 17:25:37 -05:00
if ( checkForWrapper & & utils : : Analyze : : IsWrapper ( FD ) ) {
2012-10-19 11:49:49 +00:00
assert ( ! m_WrapperFD & & " Two wrappers in one transaction? " ) ;
m_WrapperFD = FD ;
}
2013-08-27 17:25:37 -05:00
}
2012-10-19 11:49:49 +00:00
}
2013-08-02 16:20:54 +02:00
if ( comesFromASTReader ( DCI . m_DGR ) )
m_DeserializedDeclQueue . push_back ( DCI ) ;
else
m_DeclQueue . push_back ( DCI ) ;
2012-12-03 14:27:12 +00:00
}
void Transaction : : append ( clang : : DeclGroupRef DGR ) {
append ( DelayCallInfo ( DGR , kCCIHandleTopLevelDecl ) ) ;
2012-09-05 09:37:39 +00:00
}
2012-12-03 14:27:12 +00:00
void Transaction : : append ( Decl * D ) {
append ( DeclGroupRef ( D ) ) ;
2012-11-21 02:26:05 +00:00
}
2013-06-13 14:53:58 +02:00
void Transaction : : forceAppend ( Decl * D ) {
forceAppend ( DelayCallInfo ( DeclGroupRef ( D ) , kCCIHandleTopLevelDecl ) ) ;
}
2013-10-21 17:31:21 +02:00
2013-11-18 14:44:23 +01:00
void Transaction : : append ( MacroDirectiveInfo MDE ) {
assert ( MDE . m_II & & " Appending null IdentifierInfo?! " ) ;
assert ( MDE . m_MD & & " Appending null MacroDirective?! " ) ;
2013-10-21 17:31:21 +02:00
assert ( getState ( ) = = kCollecting
& & " Cannot append declarations in current state. " ) ;
# ifndef NDEBUG
// Check for duplicates
2013-11-18 14:44:23 +01:00
for ( size_t i = 0 , e = m_MacroDirectiveInfoQueue . size ( ) ; i < e ; + + i ) {
MacroDirectiveInfo & oldMacroDirectiveInfo ( m_MacroDirectiveInfoQueue [ i ] ) ;
assert ( oldMacroDirectiveInfo ! = MDE & & " Duplicates?! " ) ;
2013-10-21 17:31:21 +02:00
}
# endif
2013-11-18 14:44:23 +01:00
m_MacroDirectiveInfoQueue . push_back ( MDE ) ;
2013-10-29 10:43:48 +01:00
}
2013-04-24 09:57:30 +00:00
2013-10-24 11:46:42 -05:00
void Transaction : : erase ( iterator pos ) {
2013-04-24 15:04:09 +00:00
assert ( ! empty ( ) & & " Erasing from an empty transaction. " ) ;
2013-10-24 11:46:42 -05:00
if ( ! pos - > m_DGR . isNull ( ) & & m_WrapperFD = = * pos - > m_DGR . begin ( ) )
m_WrapperFD = 0 ;
2013-10-29 13:06:19 -05:00
m_DeclQueue . erase ( pos ) ;
2013-04-24 09:57:30 +00:00
}
2012-11-21 02:26:05 +00:00
2013-08-26 17:30:20 +02:00
void Transaction : : DelayCallInfo : : dump ( ) const {
PrintingPolicy Policy ( ( LangOptions ( ) ) ) ;
print ( llvm : : errs ( ) , Policy , /*Indent*/ 0 , /*PrintInstantiation*/ true ) ;
}
void Transaction : : DelayCallInfo : : print ( llvm : : raw_ostream & Out ,
const PrintingPolicy & Policy ,
unsigned Indent ,
bool PrintInstantiation ,
2013-08-28 11:12:44 +02:00
llvm : : StringRef prependInfo /*=""*/ ) const {
2013-08-26 17:30:20 +02:00
static const char * const stateNames [ Transaction : : kCCINumStates ] = {
" kCCINone " ,
" kCCIHandleTopLevelDecl " ,
" kCCIHandleInterestingDecl " ,
" kCCIHandleTagDeclDefinition " ,
" kCCIHandleVTable " ,
" kCCIHandleCXXImplicitFunctionInstantiation " ,
" kCCIHandleCXXStaticMemberVarInstantiation " ,
} ;
assert ( ( sizeof ( stateNames ) / sizeof ( void * ) ) = = Transaction : : kCCINumStates
& & " Missing states? " ) ;
2013-08-28 11:12:44 +02:00
if ( ! prependInfo . empty ( ) ) {
2013-08-26 17:30:20 +02:00
Out . changeColor ( llvm : : raw_ostream : : RED ) ;
Out < < prependInfo ;
Out . resetColor ( ) ;
Out < < " , " ;
}
Out . changeColor ( llvm : : raw_ostream : : BLUE ) ;
Out < < stateNames [ m_Call ] ;
Out . changeColor ( llvm : : raw_ostream : : GREEN ) ;
Out < < " <- " ;
Out . resetColor ( ) ;
for ( DeclGroupRef : : const_iterator I = m_DGR . begin ( ) , E = m_DGR . end ( ) ;
2013-08-30 10:39:06 +02:00
I ! = E ; + + I ) {
2013-08-26 17:30:20 +02:00
if ( * I )
( * I ) - > print ( Out , Policy , Indent , PrintInstantiation ) ;
else
Out < < " <<NULL DECL>> " ;
2013-08-30 10:39:06 +02:00
Out < < ' \n ' ;
}
2013-08-26 17:30:20 +02:00
}
2012-10-24 07:34:53 +00:00
2013-08-26 17:30:20 +02:00
void Transaction : : dump ( ) const {
2013-08-23 09:34:40 +02:00
const ASTContext & C = getASTContext ( ) ;
2012-10-08 10:38:52 +00:00
PrintingPolicy Policy = C . getPrintingPolicy ( ) ;
2013-01-17 15:27:14 +00:00
print ( llvm : : errs ( ) , Policy , /*Indent*/ 0 , /*PrintInstantiation*/ true ) ;
2012-10-01 11:47:27 +00:00
}
void Transaction : : dumpPretty ( ) const {
2013-08-23 09:34:40 +02:00
const ASTContext & C = getASTContext ( ) ;
2013-08-23 09:35:11 +02:00
PrintingPolicy Policy ( C . getLangOpts ( ) ) ;
2013-01-17 15:27:14 +00:00
print ( llvm : : errs ( ) , Policy , /*Indent*/ 0 , /*PrintInstantiation*/ true ) ;
2012-10-01 11:47:27 +00:00
}
void Transaction : : print ( llvm : : raw_ostream & Out , const PrintingPolicy & Policy ,
unsigned Indent , bool PrintInstantiation ) const {
2012-09-05 09:37:39 +00:00
int nestedT = 0 ;
for ( const_iterator I = decls_begin ( ) , E = decls_end ( ) ; I ! = E ; + + I ) {
2012-12-03 14:27:12 +00:00
if ( I - > m_DGR . isNull ( ) ) {
2012-09-05 09:37:39 +00:00
assert ( hasNestedTransactions ( ) & & " DGR is null even if no nesting? " ) ;
// print the nested decl
2012-11-19 21:17:28 +00:00
Out < < " \n " ;
2012-10-01 11:47:27 +00:00
Out < < " +====================================================+ \n " ;
2012-11-19 21:17:28 +00:00
Out < < " Nested Transaction " < < nestedT < < " \n " ;
2012-10-01 11:47:27 +00:00
Out < < " +====================================================+ \n " ;
2013-04-08 14:27:57 +00:00
( * m_NestedTransactions ) [ nestedT + + ] - > print ( Out , Policy , Indent ,
PrintInstantiation ) ;
2012-11-19 21:17:28 +00:00
Out < < " \n " ;
2012-10-01 11:47:27 +00:00
Out < < " +====================================================+ \n " ;
2012-11-19 21:17:28 +00:00
Out < < " End Transaction " < < nestedT < < " \n " ;
2012-10-01 11:47:27 +00:00
Out < < " +====================================================+ \n " ;
2012-09-05 09:37:39 +00:00
}
2013-08-26 17:57:33 +02:00
I - > print ( Out , Policy , Indent , PrintInstantiation ) ;
}
// Print the deserialized decls if any.
for ( const_iterator I = deserialized_decls_begin ( ) ,
E = deserialized_decls_end ( ) ; I ! = E ; + + I ) {
assert ( ! I - > m_DGR . isNull ( ) & & " Must not contain null DGR. " ) ;
I - > print ( Out , Policy , Indent , PrintInstantiation , " Deserialized " ) ;
2012-09-05 09:37:39 +00:00
}
}
2013-04-05 13:12:57 +00:00
void Transaction : : printStructure ( size_t nindent ) const {
2013-04-24 15:04:09 +00:00
static const char * const stateNames [ kNumStates ] = {
2013-04-05 13:12:57 +00:00
" Collecting " ,
2013-04-24 12:51:09 +00:00
" kCompleted " ,
2013-04-05 13:12:57 +00:00
" RolledBack " ,
" RolledBackWithErrors " ,
" Committed "
} ;
2013-08-26 17:23:30 +02:00
assert ( ( sizeof ( stateNames ) / sizeof ( void * ) ) = = kNumStates
& & " Missing a state to print. " ) ;
2013-04-05 13:12:57 +00:00
std : : string indent ( nindent , ' ' ) ;
llvm : : errs ( ) < < indent < < " Transaction @ " < < this < < " : \n " ;
2013-04-08 14:35:35 +00:00
for ( const_nested_iterator I = nested_begin ( ) , E = nested_end ( ) ;
I ! = E ; + + I ) {
2013-04-24 12:51:09 +00:00
( * I ) - > printStructure ( nindent + 3 ) ;
2013-04-05 13:12:57 +00:00
}
2013-11-25 14:26:15 +01:00
llvm : : errs ( ) < < indent < < " state: " < < stateNames [ getState ( ) ]
< < " decl groups, " ;
2013-04-24 12:51:09 +00:00
if ( hasNestedTransactions ( ) )
llvm : : errs ( ) < < m_NestedTransactions - > size ( ) ;
else
llvm : : errs ( ) < < " 0 " ;
llvm : : errs ( ) < < " nested transactions \n "
2013-04-05 13:12:57 +00:00
< < indent < < " wrapper: " < < m_WrapperFD
< < " , parent: " < < m_Parent
< < " , next: " < < m_Next < < " \n " ;
}
2013-08-04 18:21:35 +02:00
void Transaction : : printStructureBrief ( size_t nindent /*=0*/ ) const {
2013-07-06 12:33:25 +02:00
std : : string indent ( nindent , ' ' ) ;
2013-08-04 18:21:35 +02:00
llvm : : errs ( ) < < indent < < " <cling::Transaction* " < < this
< < " isEmpty= " < < empty ( ) ;
2013-08-02 16:19:38 +02:00
llvm : : errs ( ) < < " isCommitted= " < < ( getState ( ) = = kCommitted ) ;
llvm : : errs ( ) < < " > \n " ;
2013-07-06 12:33:25 +02:00
for ( const_nested_iterator I = nested_begin ( ) , E = nested_end ( ) ;
I ! = E ; + + I ) {
llvm : : errs ( ) < < indent < < " ` " ;
( * I ) - > printStructureBrief ( nindent + 3 ) ;
}
}
2013-08-02 16:20:54 +02:00
bool Transaction : : comesFromASTReader ( DeclGroupRef DGR ) const {
assert ( ! DGR . isNull ( ) & & " DeclGroupRef is Null! " ) ;
if ( getCompilationOpts ( ) . CodeGenerationForModule )
return true ;
// Take the first/only decl in the group.
Decl * D = * DGR . begin ( ) ;
return D - > isFromASTFile ( ) ;
}
2012-09-05 09:37:39 +00:00
} // end namespace cling