2012-09-05 09:37:39 +00:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
2014-01-07 11:08:37 +01:00
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
2012-09-05 09:37:39 +00:00
//------------------------------------------------------------------------------
# include "DeclCollector.h"
2015-03-16 14:49:28 +01:00
# include "IncrementalParser.h"
2012-10-02 10:30:25 +00:00
# include "cling/Interpreter/Transaction.h"
2015-03-16 14:49:28 +01:00
# include "cling/Utils/AST.h"
2012-09-05 09:37:39 +00:00
2014-09-29 15:56:15 +02:00
# include "clang/AST/ASTContext.h"
2012-09-05 09:37:39 +00:00
# include "clang/AST/Decl.h"
2012-12-03 16:28:24 +00:00
# include "clang/AST/DeclCXX.h"
2012-09-05 09:37:39 +00:00
# include "clang/AST/DeclGroup.h"
2013-10-21 17:31:21 +02:00
# include "clang/Lex/Token.h"
2012-09-05 09:37:39 +00:00
using namespace clang ;
2015-03-16 14:49:28 +01:00
namespace {
static bool shouldIgnore ( const Decl * D ) {
// This function is called for all "deserialized" decls, where the
// "deserialized" decl either really comes from an AST file or from
// a header that's loaded to import the AST for a library with a dictionary
// (the non-PCM case).
//
// Functions that are inlined must be sent to CodeGen - they will not have a
// symbol in the library.
if ( const FunctionDecl * FD = dyn_cast < FunctionDecl > ( D ) ) {
if ( D - > isFromASTFile ( ) ) {
return ! FD - > hasBody ( ) ;
} else {
// If the decl must be emitted then it will be in the library.
// If not, we must expose it to CodeGen now because it might
// not be in the library. Does this correspond to a weak symbol
// by definition?
return ! ( FD - > isInlined ( ) | | FD - > isTemplateInstantiation ( ) ) ;
}
}
// Don't codegen statics coming in from a module; they are already part of
// the library.
// We do need to expose static variables from template instantiations.
if ( const VarDecl * VD = dyn_cast < VarDecl > ( D ) )
if ( VD - > hasGlobalStorage ( ) & & ! VD - > getType ( ) . isConstQualified ( )
& & VD - > getTemplateSpecializationKind ( ) = = TSK_Undeclared )
return true ;
return false ;
}
}
2012-09-05 09:37:39 +00:00
namespace cling {
2013-04-09 15:38:50 +00:00
bool DeclCollector : : comesFromASTReader ( DeclGroupRef DGR ) const {
2013-04-04 15:40:05 +00:00
assert ( ! DGR . isNull ( ) & & " DeclGroupRef is Null! " ) ;
2013-08-07 13:27:33 -05:00
assert ( m_CurTransaction & & " No current transaction when deserializing " ) ;
2013-04-09 15:38:50 +00:00
if ( m_CurTransaction - > getCompilationOpts ( ) . CodeGenerationForModule )
return true ;
2013-04-04 15:40:05 +00:00
// Take the first/only decl in the group.
Decl * D = * DGR . begin ( ) ;
return D - > isFromASTFile ( ) ;
}
2012-09-05 09:37:39 +00:00
2014-09-29 15:32:10 +02:00
bool DeclCollector : : comesFromASTReader ( const Decl * D ) const {
// The operation is const but clang::DeclGroupRef doesn't allow us to
// express it.
return comesFromASTReader ( DeclGroupRef ( const_cast < Decl * > ( D ) ) ) ;
}
2012-09-05 09:37:39 +00:00
// pin the vtable here.
2013-08-26 17:59:33 +02:00
DeclCollector : : ~ DeclCollector ( ) { }
2013-04-04 15:40:05 +00:00
2014-09-29 15:32:10 +02:00
void DeclCollector : : AddedCXXImplicitMember ( const CXXRecordDecl * RD ,
const Decl * D ) {
assert ( D - > isImplicit ( ) ) ;
// We need to mark the decls coming from the modules
if ( comesFromASTReader ( RD ) | | comesFromASTReader ( D ) ) {
Decl * implicitD = const_cast < Decl * > ( D ) ;
implicitD - > addAttr ( UsedAttr : : CreateImplicit ( implicitD - > getASTContext ( ) ) ) ;
}
}
2015-03-16 14:49:28 +01:00
ASTTransformer : : Result DeclCollector : : TransformDecl ( Decl * D ) const {
// We are sure it's safe to pipe it through the transformers
// Consume late transformers init
for ( size_t i = 0 ; D & & i < m_TransactionTransformers . size ( ) ; + + i ) {
ASTTransformer : : Result NewDecl
= m_TransactionTransformers [ i ] - > Transform ( D , m_CurTransaction ) ;
if ( ! NewDecl . getInt ( ) ) {
m_CurTransaction - > setIssuedDiags ( Transaction : : kErrors ) ;
return NewDecl ;
}
D = NewDecl . getPointer ( ) ;
}
if ( FunctionDecl * FD = dyn_cast_or_null < FunctionDecl > ( D ) ) {
if ( utils : : Analyze : : IsWrapper ( FD ) ) {
for ( size_t i = 0 ; D & & i < m_WrapperTransformers . size ( ) ; + + i ) {
ASTTransformer : : Result NewDecl
= m_WrapperTransformers [ i ] - > Transform ( D , m_CurTransaction ) ;
if ( ! NewDecl . getInt ( ) ) {
m_CurTransaction - > setIssuedDiags ( Transaction : : kErrors ) ;
return NewDecl ;
}
D = NewDecl . getPointer ( ) ;
}
}
}
return ASTTransformer : : Result ( D , true ) ;
}
bool DeclCollector : : Transform ( DeclGroupRef & DGR ) const {
struct CommitTransactionRAII_t {
IncrementalParser * m_IncrParser ;
Transaction * m_Transaction ;
CommitTransactionRAII_t ( IncrementalParser * IP , CompilationOptions CO ) :
m_IncrParser ( IP ) {
m_Transaction = IP - > beginTransaction ( CO ) ;
}
~ CommitTransactionRAII_t ( ) {
2015-03-16 11:25:01 +01:00
IncrementalParser : : ParseResultTransaction PRT = m_IncrParser - > endTransaction ( m_Transaction ) ;
2015-03-18 09:38:35 +01:00
if ( Transaction * T = PRT . getPointer ( ) ) {
assert ( T = = m_Transaction & & " Ended different transaction? " ) ;
2015-03-16 14:49:28 +01:00
}
2015-03-18 09:38:35 +01:00
m_IncrParser - > commitTransaction ( PRT ) ;
2015-03-16 14:49:28 +01:00
}
} CommitTransactionRAII ( m_IncrParser ,
m_CurTransaction - > getCompilationOpts ( ) ) ;
llvm : : SmallVector < Decl * , 4 > ReplacedDecls ;
bool HaveReplacement = false ;
for ( Decl * D : DGR ) {
ASTTransformer : : Result NewDecl = TransformDecl ( D ) ;
if ( ! NewDecl . getInt ( ) )
return false ;
HaveReplacement | = ( NewDecl . getPointer ( ) ! = D ) ;
if ( NewDecl . getPointer ( ) )
ReplacedDecls . push_back ( NewDecl . getPointer ( ) ) ;
}
if ( HaveReplacement )
DGR = DeclGroupRef : : Create ( ( * DGR . begin ( ) ) - > getASTContext ( ) ,
ReplacedDecls . data ( ) , ReplacedDecls . size ( ) ) ;
return true ;
}
2014-01-29 15:37:10 +01:00
bool DeclCollector : : HandleTopLevelDecl ( DeclGroupRef DGR ) {
2015-03-16 14:49:28 +01:00
if ( ! Transform ( DGR ) )
return false ;
if ( DGR . isNull ( ) )
return true ;
2012-12-03 16:28:24 +00:00
Transaction : : DelayCallInfo DCI ( DGR , Transaction : : kCCIHandleTopLevelDecl ) ;
m_CurTransaction - > append ( DCI ) ;
2015-03-17 10:53:17 +01:00
if ( ! m_Consumer
| | getTransaction ( ) - > getIssuedDiags ( ) = = Transaction : : kErrors )
2015-03-16 14:49:28 +01:00
return true ;
if ( comesFromASTReader ( DGR ) ) {
for ( DeclGroupRef : : iterator DI = DGR . begin ( ) , DE = DGR . end ( ) ;
DI ! = DE ; + + DI ) {
DeclGroupRef SplitDGR ( * DI ) ;
// FIXME: The special namespace treatment (not sending itself to
// CodeGen, but only its content - if the contained decl should be
// emitted) works around issue with the static initialization when
// having a PCH and loading a library. We don't want to generate
// code for the static that will come through the library.
//
// This will be fixed with the clang::Modules. Make sure we remember.
// assert(!getCI()->getLangOpts().Modules && "Please revisit!");
if ( NamespaceDecl * ND = dyn_cast < NamespaceDecl > ( * DI ) ) {
for ( NamespaceDecl : : decl_iterator NDI = ND - > decls_begin ( ) ,
EN = ND - > decls_end ( ) ; NDI ! = EN ; + + NDI ) {
// Recurse over decls inside the namespace, like
// CodeGenModule::EmitNamespace() does.
if ( ! shouldIgnore ( * NDI ) )
m_Consumer - > HandleTopLevelDecl ( DeclGroupRef ( * NDI ) ) ;
}
} else if ( ! shouldIgnore ( * DI ) ) {
m_Consumer - > HandleTopLevelDecl ( DeclGroupRef ( * DI ) ) ;
}
continue ;
}
} else {
m_Consumer - > HandleTopLevelDecl ( DGR ) ;
}
2012-09-05 09:37:39 +00:00
return true ;
}
void DeclCollector : : HandleInterestingDecl ( DeclGroupRef DGR ) {
2012-12-03 16:28:24 +00:00
Transaction : : DelayCallInfo DCI ( DGR , Transaction : : kCCIHandleInterestingDecl ) ;
m_CurTransaction - > append ( DCI ) ;
2015-03-16 14:49:28 +01:00
if ( m_Consumer
& & ( ! comesFromASTReader ( DGR ) | | ! shouldIgnore ( * DGR . begin ( ) ) ) )
m_Consumer - > HandleTopLevelDecl ( DGR ) ;
2012-09-05 09:37:39 +00:00
}
void DeclCollector : : HandleTagDeclDefinition ( TagDecl * TD ) {
2014-01-29 15:37:10 +01:00
Transaction : : DelayCallInfo DCI ( DeclGroupRef ( TD ) ,
2012-12-03 16:28:24 +00:00
Transaction : : kCCIHandleTagDeclDefinition ) ;
2014-01-29 15:37:10 +01:00
m_CurTransaction - > append ( DCI ) ;
2015-03-16 14:49:28 +01:00
if ( m_Consumer
& & ( ! comesFromASTReader ( DeclGroupRef ( TD ) )
| | ! shouldIgnore ( TD ) ) )
m_Consumer - > HandleTagDeclDefinition ( TD ) ;
2012-09-05 09:37:39 +00:00
}
2015-01-21 13:28:55 +01:00
void DeclCollector : : HandleVTable ( CXXRecordDecl * RD ) {
2012-12-03 16:28:24 +00:00
Transaction : : DelayCallInfo DCI ( DeclGroupRef ( RD ) ,
Transaction : : kCCIHandleVTable ) ;
2014-01-29 15:37:10 +01:00
m_CurTransaction - > append ( DCI ) ;
2012-12-03 16:28:24 +00:00
2015-03-16 14:49:28 +01:00
if ( m_Consumer
& & ( ! comesFromASTReader ( DeclGroupRef ( RD ) )
| | ! shouldIgnore ( RD ) ) )
m_Consumer - > HandleVTable ( RD ) ;
2012-11-18 22:44:58 +00:00
// Intentional no-op. It comes through Sema::DefineUsedVTables, which
// comes either Sema::ActOnEndOfTranslationUnit or while instantiating a
2014-01-29 15:37:10 +01:00
// template. In our case we will do it on transaction commit, without
2012-11-18 22:44:58 +00:00
// keeping track of used vtables, because we have cases where we bypass the
2014-01-29 15:37:10 +01:00
// clang/AST and directly ask the module so that we have to generate
2012-11-18 22:44:58 +00:00
// everything without extra smartness.
2012-09-05 09:37:39 +00:00
}
void DeclCollector : : CompleteTentativeDefinition ( VarDecl * VD ) {
2014-01-29 15:48:13 +01:00
// C has tentative definitions which we might need to deal with when running
// in C mode.
Transaction : : DelayCallInfo DCI ( DeclGroupRef ( VD ) ,
Transaction : : kCCICompleteTentativeDefinition ) ;
m_CurTransaction - > append ( DCI ) ;
2015-03-16 14:49:28 +01:00
if ( m_Consumer
& & ( ! comesFromASTReader ( DeclGroupRef ( VD ) )
| | ! shouldIgnore ( VD ) ) )
m_Consumer - > CompleteTentativeDefinition ( VD ) ;
2012-09-05 09:37:39 +00:00
}
void DeclCollector : : HandleTranslationUnit ( ASTContext & Ctx ) {
2015-03-16 14:49:28 +01:00
//if (m_Consumer)
// m_Consumer->HandleTranslationUnit(Ctx);
2012-09-05 09:37:39 +00:00
}
2012-12-12 08:08:56 +00:00
void DeclCollector : : HandleCXXImplicitFunctionInstantiation ( FunctionDecl * D ) {
Transaction : : DelayCallInfo DCI ( DeclGroupRef ( D ) ,
Transaction : : kCCIHandleCXXImplicitFunctionInstantiation ) ;
m_CurTransaction - > append ( DCI ) ;
2015-03-16 14:49:28 +01:00
if ( m_Consumer
& & ( ! comesFromASTReader ( DeclGroupRef ( D ) )
| | ! shouldIgnore ( D ) ) )
m_Consumer - > HandleCXXImplicitFunctionInstantiation ( D ) ;
2012-12-12 08:08:56 +00:00
}
2015-03-16 14:49:28 +01:00
2012-12-12 08:08:56 +00:00
void DeclCollector : : HandleCXXStaticMemberVarInstantiation ( VarDecl * D ) {
Transaction : : DelayCallInfo DCI ( DeclGroupRef ( D ) ,
Transaction : : kCCIHandleCXXStaticMemberVarInstantiation ) ;
m_CurTransaction - > append ( DCI ) ;
2015-03-16 14:49:28 +01:00
if ( m_Consumer
& & ( ! comesFromASTReader ( DeclGroupRef ( D ) )
| | ! shouldIgnore ( D ) ) )
m_Consumer - > HandleCXXStaticMemberVarInstantiation ( D ) ;
2012-12-12 08:08:56 +00:00
}
2013-10-21 17:31:21 +02:00
2013-11-18 14:44:23 +01:00
void DeclCollector : : MacroDefined ( const clang : : Token & MacroNameTok ,
const clang : : MacroDirective * MD ) {
Transaction : : MacroDirectiveInfo MDE ( MacroNameTok . getIdentifierInfo ( ) , MD ) ;
2013-10-21 17:31:21 +02:00
m_CurTransaction - > append ( MDE ) ;
}
2013-10-29 10:43:48 +01:00
2012-09-05 09:37:39 +00:00
} // namespace cling