2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vvasilev@cern.ch>
2014-01-07 14:08:37 +04: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 13:37:39 +04:00
//------------------------------------------------------------------------------
# include "cling/Interpreter/LookupHelper.h"
2014-03-27 20:30:09 +04:00
# include "TransactionUnloader.h"
2013-04-03 20:25:08 +04:00
# include "cling/Interpreter/Interpreter.h"
2014-09-15 14:43:47 +04:00
# include "cling/Utils/AST.h"
2013-04-03 20:25:08 +04:00
2012-09-05 13:37:39 +04:00
# include "clang/AST/ASTContext.h"
2014-08-01 18:36:54 +04:00
# include "clang/Frontend/CompilerInstance.h"
2012-09-05 13:37:39 +04:00
# include "clang/Parse/Parser.h"
2012-11-16 00:19:21 +04:00
# include "clang/Parse/RAIIObjectsForParser.h"
2012-09-05 13:37:39 +04:00
# include "clang/Sema/Scope.h"
# include "clang/Sema/Lookup.h"
# include "clang/Sema/Overload.h"
# include "clang/Sema/Sema.h"
# include "clang/Sema/Template.h"
# include "clang/Sema/TemplateDeduction.h"
2015-10-01 15:16:08 +03:00
# if defined(_MSC_VER) && (_MSC_VER <= 1800)
# define constexpr const
# endif
2012-09-05 13:37:39 +04:00
using namespace clang ;
2015-01-08 20:29:58 +03:00
namespace clang {
2012-09-05 13:37:39 +04:00
///\brief Cleanup Parser state after a failed lookup.
2013-08-03 09:48:28 +04:00
///
2012-09-05 13:37:39 +04:00
/// After a failed lookup we need to discard the remaining unparsed input,
2012-11-20 17:17:55 +04:00
/// restore the original state of the incremental parsing flag, clear any
2012-09-05 13:37:39 +04:00
/// pending diagnostics, restore the suppress diagnostics flag, and restore
/// the spell checking language options.
///
class ParserStateRAII {
private :
Parser * P ;
Preprocessor & PP ;
2015-09-05 08:44:47 +03:00
decltype ( Parser : : TemplateIds ) OldTemplateIds ;
2012-09-05 13:37:39 +04:00
bool ResetIncrementalProcessing ;
bool OldSuppressAllDiagnostics ;
2015-09-09 08:07:57 +03:00
bool OldPPSuppressAllDiagnostics ;
2012-09-05 13:37:39 +04:00
bool OldSpellChecking ;
2015-01-08 20:29:58 +03:00
SourceLocation OldPrevTokLocation ;
unsigned short OldParenCount , OldBracketCount , OldBraceCount ;
unsigned OldTemplateParameterDepth ;
2015-09-09 08:08:52 +03:00
decltype ( P - > getActions ( ) . InNonInstantiationSFINAEContext )
OldInNonInstantiationSFINAEContext ;
2015-01-08 20:29:58 +03:00
2012-09-05 13:37:39 +04:00
public :
2012-11-20 17:17:55 +04:00
ParserStateRAII ( Parser & p )
2013-08-03 09:48:28 +04:00
: P ( & p ) , PP ( p . getPreprocessor ( ) ) ,
2013-02-19 13:25:04 +04:00
ResetIncrementalProcessing ( p . getPreprocessor ( )
. isIncrementalProcessingEnabled ( ) ) ,
2015-09-09 08:07:57 +03:00
OldSuppressAllDiagnostics ( P - > getActions ( ) . getDiagnostics ( )
. getSuppressAllDiagnostics ( ) ) ,
OldPPSuppressAllDiagnostics ( p . getPreprocessor ( ) . getDiagnostics ( )
2013-02-19 13:25:04 +04:00
. getSuppressAllDiagnostics ( ) ) ,
OldSpellChecking ( p . getPreprocessor ( ) . getLangOpts ( ) . SpellChecking ) ,
2015-09-05 08:44:47 +03:00
OldPrevTokLocation ( p . PrevTokLocation ) ,
2015-01-08 20:29:58 +03:00
OldParenCount ( p . ParenCount ) , OldBracketCount ( p . BracketCount ) ,
OldBraceCount ( p . BraceCount ) ,
2015-09-09 08:08:52 +03:00
OldTemplateParameterDepth ( p . TemplateParameterDepth ) ,
OldInNonInstantiationSFINAEContext ( P - > getActions ( )
. InNonInstantiationSFINAEContext )
2013-02-19 13:25:04 +04:00
{
2015-09-05 08:44:47 +03:00
OldTemplateIds . swap ( P - > TemplateIds ) ;
2013-02-19 13:25:04 +04:00
}
2012-09-05 13:37:39 +04:00
~ ParserStateRAII ( )
{
//
// Advance the parser to the end of the file, and pop the include stack.
//
// Note: Consuming the EOF token will pop the include stack.
//
2015-09-05 08:44:47 +03:00
{
// Cleanup the TemplateIds before swapping the previous set back.
DestroyTemplateIdAnnotationsRAIIObj CleanupTemplateIds ( * P ) ;
}
P - > TemplateIds . swap ( OldTemplateIds ) ;
2014-02-18 11:22:16 +04:00
P - > SkipUntil ( tok : : eof ) ;
2012-10-12 20:09:04 +04:00
PP . enableIncrementalProcessing ( ResetIncrementalProcessing ) ;
2014-04-01 12:51:50 +04:00
// Doesn't reset the diagnostic mappings
P - > getActions ( ) . getDiagnostics ( ) . Reset ( /*soft=*/ true ) ;
2015-09-09 08:07:57 +03:00
P - > getActions ( ) . getDiagnostics ( ) . setSuppressAllDiagnostics ( OldSuppressAllDiagnostics ) ;
PP . getDiagnostics ( ) . Reset ( /*soft=*/ true ) ;
PP . getDiagnostics ( ) . setSuppressAllDiagnostics ( OldPPSuppressAllDiagnostics ) ;
2012-09-05 13:37:39 +04:00
const_cast < LangOptions & > ( PP . getLangOpts ( ) ) . SpellChecking =
OldSpellChecking ;
2015-01-08 20:29:58 +03:00
P - > PrevTokLocation = OldPrevTokLocation ;
P - > ParenCount = OldParenCount ;
P - > BracketCount = OldBracketCount ;
P - > BraceCount = OldBraceCount ;
P - > TemplateParameterDepth = OldTemplateParameterDepth ;
2015-09-09 08:08:52 +03:00
P - > getActions ( ) . InNonInstantiationSFINAEContext =
OldInNonInstantiationSFINAEContext ;
2012-09-05 13:37:39 +04:00
}
} ;
2015-01-08 20:29:58 +03:00
}
2012-09-05 13:37:39 +04:00
2015-01-08 20:29:58 +03:00
namespace cling {
2013-08-25 08:19:24 +04:00
///\brief Class to help with the custom allocation of clang::Expr
///
struct ExprAlloc {
char fBuffer [ sizeof ( clang : : OpaqueValueExpr ) ] ;
} ;
2012-11-26 17:45:32 +04:00
// pin *tor here so that we can have clang::Parser defined and be able to call
// the dtor on the OwningPtr
2013-08-03 09:48:28 +04:00
LookupHelper : : LookupHelper ( clang : : Parser * P , Interpreter * interp )
2013-04-03 20:25:08 +04:00
: m_Parser ( P ) , m_Interpreter ( interp ) { }
2012-11-26 17:45:32 +04:00
LookupHelper : : ~ LookupHelper ( ) { }
2012-10-12 19:27:02 +04:00
2014-09-15 14:16:36 +04:00
static
DeclContext * getContextAndSpec ( CXXScopeSpec & SS ,
const Decl * scopeDecl ,
ASTContext & Context , Sema & S ) ;
2014-09-12 06:54:19 +04:00
static void prepareForParsing ( Parser & P ,
const Interpreter * Interp ,
llvm : : StringRef code ,
llvm : : StringRef bufferName ,
LookupHelper : : DiagSetting diagOnOff ) {
//Parser& P = *m_Parser;
Sema & S = P . getActions ( ) ;
Preprocessor & PP = P . getPreprocessor ( ) ;
//
// Tell the diagnostic engine to ignore all diagnostics.
//
2015-09-09 08:07:57 +03:00
P . getActions ( ) . getDiagnostics ( ) . setSuppressAllDiagnostics (
diagOnOff = = LookupHelper : : NoDiagnostics ) ;
2014-09-12 06:54:19 +04:00
PP . getDiagnostics ( ) . setSuppressAllDiagnostics (
2015-09-09 08:08:52 +03:00
diagOnOff = = LookupHelper : : NoDiagnostics ) ;
//
// Tell Sema we are not in the process of doing an instantiation.
//
P . getActions ( ) . InNonInstantiationSFINAEContext = true ;
2014-09-12 06:54:19 +04:00
//
// Tell the parser to not attempt spelling correction.
//
const_cast < LangOptions & > ( PP . getLangOpts ( ) ) . SpellChecking = 0 ;
//
// Turn on ignoring of the main file eof token.
//
// Note: We need this because token readahead in the following
// routine calls ends up parsing it multiple times.
//
if ( ! PP . isIncrementalProcessingEnabled ( ) ) {
PP . enableIncrementalProcessing ( ) ;
}
2014-09-12 13:20:29 +04:00
assert ( ! code . empty ( ) & & " prepareForParsing should only be called when needd " ) ;
//
// Create a fake file to parse the type name.
//
2015-01-15 17:13:14 +03:00
std : : unique_ptr < llvm : : MemoryBuffer >
SB = llvm : : MemoryBuffer : : getMemBufferCopy ( code . str ( ) + " \n " ,
bufferName . str ( ) ) ;
2014-09-12 13:20:29 +04:00
SourceLocation NewLoc = Interp - > getNextAvailableLoc ( ) ;
2015-01-15 17:13:14 +03:00
FileID FID = S . getSourceManager ( ) . createFileID ( std : : move ( SB ) ,
SrcMgr : : C_User ,
2014-09-12 13:20:29 +04:00
/*LoadedID*/ 0 ,
/*LoadedOffset*/ 0 , NewLoc ) ;
//
// Switch to the new file the way #include does.
//
// Note: To switch back to the main file we must consume an eof token.
//
PP . EnterSourceFile ( FID , /*DirLookup*/ 0 , NewLoc ) ;
PP . Lex ( const_cast < Token & > ( P . getCurToken ( ) ) ) ;
2014-09-12 06:54:19 +04:00
}
2014-09-15 14:16:36 +04:00
static const TagDecl * RequireCompleteDeclContext ( Sema & S ,
Preprocessor & PP ,
const TagDecl * tobeCompleted ,
LookupHelper : : DiagSetting diagOnOff )
{
// getContextAndSpec create the CXXScopeSpec and requires the scope
// to be complete, so this is exactly what we need.
bool OldSuppressAllDiagnostics ( PP . getDiagnostics ( )
. getSuppressAllDiagnostics ( ) ) ;
PP . getDiagnostics ( ) . setSuppressAllDiagnostics (
diagOnOff = = LookupHelper : : NoDiagnostics ) ;
CXXScopeSpec SS ;
ASTContext & Context = S . getASTContext ( ) ;
DeclContext * complete = getContextAndSpec ( SS , tobeCompleted , Context , S ) ;
PP . getDiagnostics ( ) . setSuppressAllDiagnostics ( OldSuppressAllDiagnostics ) ;
if ( complete ) {
const TagDecl * result = dyn_cast < TagDecl > ( complete ) ;
return result - > getDefinition ( ) ;
} else return 0 ;
}
2015-09-27 16:47:29 +03:00
///\brief Look for a tag decl based on its name
///
2015-09-27 16:51:33 +03:00
///\param declName name of the class, enum, uniorn or namespace being
2015-09-27 16:47:29 +03:00
/// looked for
///\param resultDecl pointer that will be updated with the answer
2015-09-30 17:45:39 +03:00
///\param P Parse to use for the search
2015-09-27 16:47:29 +03:00
///\param diagOnOff whether the error diagnostics are printed or not.
///\return returns true if the answer is authoritative or false if a more
/// detailed search is needed (usually this is for class template
/// instances).
///
2015-09-27 16:51:33 +03:00
static bool quickFindDecl ( llvm : : StringRef declName ,
2015-09-26 12:59:59 +03:00
const Decl * & resultDecl ,
Parser & P ,
LookupHelper : : DiagSetting diagOnOff ) {
Sema & S = P . getActions ( ) ;
Preprocessor & PP = P . getPreprocessor ( ) ;
resultDecl = nullptr ;
const clang : : DeclContext * sofar = nullptr ;
const clang : : Decl * next = nullptr ;
2015-09-27 16:51:33 +03:00
for ( size_t c = 0 , last = 0 ; c < declName . size ( ) ; + + c ) {
2015-09-28 19:40:45 +03:00
const char current = declName [ c ] ;
if ( current = = ' < ' | | current = = ' > ' | |
current = = ' ' | | current = = ' & ' | |
current = = ' * ' | | current = = ' [ ' | |
current = = ' ] ' ) {
2015-09-26 12:59:59 +03:00
// For now we do not know how to deal with
// template instances.
return false ;
}
2015-09-28 19:40:45 +03:00
if ( current = = ' : ' ) {
2015-09-27 16:51:33 +03:00
if ( c + 2 > = declName . size ( ) | | declName [ c + 1 ] ! = ' : ' ) {
2015-09-26 12:59:59 +03:00
// Looks like an invalid name, we won't find anything.
2015-09-26 23:52:42 +03:00
return true ;
2015-09-26 12:59:59 +03:00
}
2015-09-27 16:51:33 +03:00
next = utils : : Lookup : : Named ( & S , declName . substr ( last , c - last ) , sofar ) ;
2015-09-26 12:59:59 +03:00
if ( next & & next ! = ( void * ) - 1 ) {
// Need to handle typedef here too.
const TypedefNameDecl * typedefDecl = dyn_cast < TypedefNameDecl > ( next ) ;
if ( typedefDecl ) {
// We are stripping the typedef, this is technically incorrect,
// as the result (if resultType has been specified) will not be
// an accurate representation of the input string.
// As we strip the typedef we ought to rebuild the nested name
// specifier.
// Since we do not use this path for template handling, this
// is not relevant for ROOT itself ....
ASTContext & Context = S . getASTContext ( ) ;
QualType T = Context . getTypedefType ( typedefDecl ) ;
const TagType * TagTy = T - > getAs < TagType > ( ) ;
if ( TagTy ) next = TagTy - > getDecl ( ) ;
}
// To use Lookup::Named we need to fit the assertion:
// ((!isa<TagDecl>(LookupCtx) || LookupCtx->isDependentContext()
// || cast<TagDecl>(LookupCtx)->isCompleteDefinition()
// || cast<TagDecl>(LookupCtx)->isBeingDefined()) &&
// "Declaration context must already be complete!"),
// function LookupQualifiedName, file SemaLookup.cpp, line 1614.
const clang : : TagDecl * tdecl = dyn_cast < TagDecl > ( next ) ;
if ( tdecl & & ! ( next = tdecl - > getDefinition ( ) ) ) {
//fprintf(stderr,"Incomplete (inner) type for %s (part %s).\n",
2015-09-27 16:51:33 +03:00
// declName.str().c_str(),
// declName.substr(last,c-last).str().c_str());
2015-09-26 12:59:59 +03:00
// Incomplete type we will not be able to go on.
// We always require completeness of the scope, if the caller
// want piece-meal instantiation, the calling code will need to
// split the call to findScope.
// if (instantiateTemplate) {
if ( dyn_cast < ClassTemplateSpecializationDecl > ( tdecl ) ) {
// Go back to the normal schedule since we need a valid point
// of instantiation:
// Assertion failed: (Loc.isValid() &&
// "point of instantiation must be valid!"),
// function setPointOfInstantiation, file DeclTemplate.h,
// line 1520.
// Which can happen here because the simple name maybe a
// typedef to a template (for example std::string).
2015-09-26 23:52:42 +03:00
return false ;
2015-09-26 12:59:59 +03:00
}
next = RequireCompleteDeclContext ( S , PP , tdecl , diagOnOff ) ;
// } else {
// return false;
// }
}
sofar = dyn_cast_or_null < DeclContext > ( next ) ;
} else {
sofar = 0 ;
}
if ( ! sofar ) {
// We are looking into something that is not a decl context,
// we won't find anything.
2015-09-26 23:52:42 +03:00
return true ;
2015-09-26 12:59:59 +03:00
}
last = c + 2 ;
+ + c ; // Consume the second ':'
2015-09-27 16:51:33 +03:00
} else if ( c + 1 = = declName . size ( ) ) {
2015-09-26 12:59:59 +03:00
// End of the line.
2015-09-27 16:51:33 +03:00
next = utils : : Lookup : : Named ( & S , declName . substr ( last , c + 1 - last ) , sofar ) ;
2015-09-26 12:59:59 +03:00
if ( next = = ( void * ) - 1 ) next = 0 ;
if ( next ) {
resultDecl = next ;
}
2015-09-26 23:52:42 +03:00
return true ;
2015-09-26 12:59:59 +03:00
}
} // for each characters
// Should be unreacheable.
return false ;
}
2015-09-28 20:05:27 +03:00
static QualType findBuiltinType ( llvm : : StringRef typeName , ASTContext & Context )
{
bool issigned = false ;
bool isunsigned = false ;
if ( typeName . startswith ( " signed " ) ) {
issigned = true ;
typeName = StringRef ( typeName . data ( ) + 7 , typeName . size ( ) - 7 ) ;
}
if ( ! issigned & & typeName . startswith ( " unsigned " ) ) {
isunsigned = true ;
typeName = StringRef ( typeName . data ( ) + 9 , typeName . size ( ) - 9 ) ;
}
if ( typeName . equals ( " char " ) ) {
if ( isunsigned ) return Context . UnsignedCharTy ;
return Context . SignedCharTy ;
}
if ( typeName . equals ( " short " ) ) {
if ( isunsigned ) return Context . UnsignedShortTy ;
return Context . ShortTy ;
}
if ( typeName . equals ( " int " ) ) {
if ( isunsigned ) return Context . UnsignedIntTy ;
return Context . IntTy ;
}
if ( typeName . equals ( " long " ) ) {
if ( isunsigned ) return Context . UnsignedLongTy ;
return Context . LongTy ;
}
if ( typeName . equals ( " long long " ) ) {
if ( isunsigned ) return Context . LongLongTy ;
return Context . UnsignedLongLongTy ;
}
if ( ! issigned & & ! isunsigned ) {
if ( typeName . equals ( " bool " ) ) return Context . BoolTy ;
if ( typeName . equals ( " float " ) ) return Context . FloatTy ;
if ( typeName . equals ( " double " ) ) return Context . DoubleTy ;
if ( typeName . equals ( " long double " ) ) return Context . LongDoubleTy ;
if ( typeName . equals ( " wchar_t " ) ) return Context . WCharTy ;
if ( typeName . equals ( " char16_t " ) ) return Context . Char16Ty ;
if ( typeName . equals ( " char32_t " ) ) return Context . Char32Ty ;
}
/* Missing
CanQualType WideCharTy ; // Same as WCharTy in C++, integer type in C99.
CanQualType WIntTy ; // [C99 7.24.1], integer type unchanged by default promotions.
*/
return QualType ( ) ;
}
2015-09-29 01:47:15 +03:00
///\brief Look for a tag decl based on its name
///
2015-09-30 17:45:39 +03:00
///\param typeName name of the class, enum, uniorn or namespace being
2015-09-29 01:47:15 +03:00
/// looked for
///\param resultType reference to QualType that will be updated with the answer
2015-09-30 17:45:39 +03:00
///\param P Parse to use for the search
2015-09-29 01:47:15 +03:00
///\param diagOnOff whether the error diagnostics are printed or not.
///\return returns true if the answer is authoritative or false if a more
/// detailed search is needed (usually this is for class template
/// instances).
///
static bool quickFindType ( llvm : : StringRef typeName ,
QualType & resultType ,
Parser & P ,
LookupHelper : : DiagSetting diagOnOff ) {
resultType = QualType ( ) ;
llvm : : StringRef quickTypeName = typeName . trim ( ) ;
bool innerConst = false ;
bool outerConst = false ;
if ( quickTypeName . startswith ( " const " ) ) {
// Use this syntax to avoid the redudant tests in substr.
quickTypeName = StringRef ( quickTypeName . data ( ) + 6 ,
quickTypeName . size ( ) - 6 ) ;
innerConst = true ;
}
constexpr int pointerType = 0 ;
constexpr int lrefType = 1 ;
constexpr int rrefType = 2 ;
if ( quickTypeName . endswith ( " const " ) ) {
if ( quickTypeName . size ( ) < 6 ) return true ;
auto c = quickTypeName [ quickTypeName . size ( ) - 6 ] ;
if ( c = = ' ' | | c = = ' & ' | | c = = ' * ' ) {
outerConst = true ;
if ( c = = ' ' )
quickTypeName = StringRef ( quickTypeName . data ( ) ,
quickTypeName . size ( ) - 6 ) ;
else quickTypeName = StringRef ( quickTypeName . data ( ) ,
quickTypeName . size ( ) - 5 ) ;
}
}
std : : vector < int > ptrref ;
for ( auto c = quickTypeName . end ( ) - 1 ; c ! = quickTypeName . begin ( ) ; - - c ) {
if ( * c = = ' * ' ) ptrref . push_back ( pointerType ) ;
else if ( * c = = ' & ' ) {
if ( * ( c - 1 ) = = ' & ' ) {
- - c ;
ptrref . push_back ( rrefType ) ;
} else
ptrref . push_back ( lrefType ) ;
}
else break ;
}
if ( ! ptrref . empty ( ) ) quickTypeName = StringRef ( quickTypeName . data ( ) , quickTypeName . size ( ) - ptrref . size ( ) ) ;
Sema & S = P . getActions ( ) ;
ASTContext & Context = S . getASTContext ( ) ;
QualType quickFind = findBuiltinType ( quickTypeName , Context ) ;
const Decl * quickDecl = nullptr ;
if ( quickFind . isNull ( ) & &
quickFindDecl ( quickTypeName , quickDecl , P , diagOnOff ) ) {
// The result of quickFindDecl was definitive, we don't need
// to check any further.
//const TypeDecl *typedecl = dyn_cast<TypeDecl>(quickDecl);
if ( quickDecl ) {
const TypeDecl * typedecl = dyn_cast < TypeDecl > ( quickDecl ) ;
if ( typedecl ) {
quickFind = Context . getTypeDeclType ( typedecl ) ;
} else {
return true ;
}
} else {
return true ;
}
}
if ( ! quickFind . isNull ( ) ) {
2015-09-29 20:11:35 +03:00
if ( innerConst & & ! quickFind - > isReferenceType ( ) ) quickFind . addConst ( ) ;
2015-09-29 01:47:15 +03:00
for ( auto t : ptrref ) {
switch ( t ) {
case pointerType :
quickFind = Context . getPointerType ( quickFind ) ;
break ;
case rrefType :
quickFind = Context . getRValueReferenceType ( quickFind ) ;
break ;
case lrefType :
quickFind = Context . getLValueReferenceType ( quickFind ) ;
break ;
}
}
2015-09-29 20:11:35 +03:00
if ( outerConst & & ! quickFind - > isReferenceType ( ) ) quickFind . addConst ( ) ;
2015-09-29 01:47:15 +03:00
resultType = quickFind ;
return true ;
}
return false ;
}
2015-09-28 20:05:27 +03:00
QualType LookupHelper : : findType ( llvm : : StringRef typeName ,
DiagSetting diagOnOff ) const {
//
// Our return value.
//
QualType TheQT ;
if ( typeName . empty ( ) ) return TheQT ;
2015-09-29 22:44:52 +03:00
// Could trigger deserialization of decls.
Interpreter : : PushTransactionRAII RAII ( m_Interpreter ) ;
2015-09-29 01:47:15 +03:00
// Deal with the most common case.
2015-09-29 09:09:33 +03:00
// Going through this custom finder is both much faster
// (6 times faster, 10.6s to 57.5s for 1 000 000 calls) and consumes
// infinite less memory (0B vs 181 B per call for 'Float_t*').
2015-09-28 20:05:27 +03:00
QualType quickFind ;
2015-09-29 01:47:15 +03:00
if ( quickFindType ( typeName , quickFind , * m_Parser , diagOnOff ) ) {
// The result of quickFindDecl was definitive, we don't need
// to check any further.
return quickFind ;
2015-09-28 20:05:27 +03:00
}
// Use P for shortness
Parser & P = * m_Parser ;
ParserStateRAII ResetParserState ( P ) ;
prepareForParsing ( P , m_Interpreter ,
typeName , llvm : : StringRef ( " lookup.type.by.name.file " ) ,
diagOnOff ) ;
//
// Try parsing the type name.
//
clang : : ParsedAttributes Attrs ( P . getAttrFactory ( ) ) ;
TypeResult Res ( P . ParseTypeName ( 0 , Declarator : : TypeNameContext , clang : : AS_none ,
0 , & Attrs ) ) ;
if ( Res . isUsable ( ) ) {
// Accept it only if the whole name was parsed.
if ( P . NextToken ( ) . getKind ( ) = = clang : : tok : : eof ) {
TypeSourceInfo * TSI = 0 ;
TheQT = clang : : Sema : : GetTypeFromParser ( Res . get ( ) , & TSI ) ;
}
}
2015-09-29 20:11:35 +03:00
// if (!quickFind.isNull() && !TheQT.isNull() && TheQT != quickFind) {
// fprintf(stderr,"Different result\n");
// fprintf(stderr,"quickFindType:"); quickFind.dump();
// fprintf(stderr,"TheQT :"); TheQT.dump();
//
// }
2015-09-28 20:05:27 +03:00
return TheQT ;
}
const Decl * LookupHelper : : findScope ( llvm : : StringRef className ,
2014-02-19 11:31:45 +04:00
DiagSetting diagOnOff ,
2012-12-09 05:51:25 +04:00
const Type * * resultType /* = 0 */ ,
bool instantiateTemplate /*=true*/ ) const {
2014-09-15 14:16:36 +04:00
2012-09-05 13:37:39 +04:00
//
// Some utilities.
//
// Use P for shortness
2015-09-26 12:59:59 +03:00
Parser & P = * m_Parser ;
Sema & S = P . getActions ( ) ;
Preprocessor & PP = P . getPreprocessor ( ) ;
ASTContext & Context = S . getASTContext ( ) ;
2013-04-08 14:16:01 +04:00
2014-09-15 14:16:36 +04:00
// See if we can find it without a buffer and any clang parsing,
// We need to go scope by scope.
2015-09-26 12:59:59 +03:00
{
const Decl * quickResult = nullptr ;
if ( quickFindDecl ( className , quickResult , * m_Parser , diagOnOff ) ) {
// The result of quickFindDecl was definitive, we don't need
// to check any further.
if ( ! quickResult ) {
return nullptr ;
} else {
const TagDecl * tagdecl = dyn_cast < TagDecl > ( quickResult ) ;
const TypedefNameDecl * typedefDecl = dyn_cast < TypedefNameDecl > ( quickResult ) ;
if ( typedefDecl ) {
QualType T = Context . getTypedefType ( typedefDecl ) ;
const TagType * TagTy = T - > getAs < TagType > ( ) ;
if ( TagTy ) tagdecl = TagTy - > getDecl ( ) ;
// NOTE: Should we instantiate here? ... maybe ...
if ( tagdecl & & resultType ) * resultType = T . getTypePtr ( ) ;
} else if ( tagdecl & & resultType ) {
* resultType = tagdecl - > getTypeForDecl ( ) ;
2014-09-15 14:16:36 +04:00
}
2015-09-26 12:59:59 +03:00
// fprintf(stderr,"Short cut taken for %s.\n",className.str().c_str());
if ( tagdecl ) {
const TagDecl * defdecl = tagdecl - > getDefinition ( ) ;
if ( ! defdecl | | ! defdecl - > isCompleteDefinition ( ) ) {
// fprintf(stderr,"Incomplete type for %s.\n",className.str().c_str());
if ( instantiateTemplate ) {
if ( dyn_cast < ClassTemplateSpecializationDecl > ( tagdecl ) ) {
// Go back to the normal schedule since we need a valid point
// of instantiation:
// Assertion failed: (Loc.isValid() &&
// "point of instantiation must be valid!"),
// function setPointOfInstantiation, file DeclTemplate.h,
// line 1520.
// Which can happen here because the simple name maybe a
// typedef to a template (for example std::string).
// break;
// the next code executed must be the TransactionRAII below
} else
return RequireCompleteDeclContext ( S , PP , tagdecl , diagOnOff ) ;
} else {
return nullptr ;
2014-09-15 14:16:36 +04:00
}
2015-09-26 23:52:42 +03:00
} else {
return defdecl ; // now pointing to the definition.
2014-09-15 14:16:36 +04:00
}
2015-09-26 12:59:59 +03:00
} else if ( isa < NamespaceDecl > ( quickResult ) ) {
return quickResult - > getCanonicalDecl ( ) ;
} else if ( auto alias = dyn_cast < NamespaceAliasDecl > ( quickResult ) ) {
return alias - > getNamespace ( ) - > getCanonicalDecl ( ) ;
2014-09-15 14:16:36 +04:00
} else {
2015-09-26 12:59:59 +03:00
//fprintf(stderr,"Not a scope decl for %s.\n",className.str().c_str());
// The name exist and does not point to a 'scope' decl.
return nullptr ;
2014-09-15 14:16:36 +04:00
}
}
}
}
2013-08-03 09:48:28 +04:00
// The user wants to see the template instantiation, existing or not.
// Here we might not have an active transaction to handle
// the caused instantiation decl.
2013-04-08 14:16:01 +04:00
Interpreter : : PushTransactionRAII pushedT ( m_Interpreter ) ;
2012-11-20 17:17:55 +04:00
ParserStateRAII ResetParserState ( P ) ;
2014-09-12 06:54:19 +04:00
prepareForParsing ( P , m_Interpreter ,
className . str ( ) + " :: " ,
2014-02-19 11:31:45 +04:00
llvm : : StringRef ( " lookup.class.by.name.file " ) , diagOnOff ) ;
2012-09-05 13:37:39 +04:00
//
2012-10-12 20:09:04 +04:00
// Our return values.
2012-09-05 13:37:39 +04:00
//
2012-10-12 20:09:04 +04:00
const Type * TheType = 0 ;
const Type * * setResultType = & TheType ;
if ( resultType )
setResultType = resultType ;
* setResultType = 0 ;
2012-09-05 13:37:39 +04:00
//
// Prevent failing on an assert in TryAnnotateCXXScopeToken.
//
2013-08-03 09:48:28 +04:00
if ( ! P . getCurToken ( ) . is ( clang : : tok : : identifier )
& & ! P . getCurToken ( ) . is ( clang : : tok : : coloncolon )
& & ! ( P . getCurToken ( ) . is ( clang : : tok : : annot_template_id )
& & P . NextToken ( ) . is ( clang : : tok : : coloncolon ) )
2012-12-01 11:22:56 +04:00
& & ! P . getCurToken ( ) . is ( clang : : tok : : kw_decltype ) ) {
2012-09-05 13:37:39 +04:00
// error path
2014-09-15 14:16:36 +04:00
return 0 ;
2012-09-05 13:37:39 +04:00
}
//
// Try parsing the name as a nested-name-specifier.
//
2012-09-18 15:45:00 +04:00
if ( P . TryAnnotateCXXScopeToken ( false ) ) {
2012-09-05 13:37:39 +04:00
// error path
2014-09-15 14:16:36 +04:00
return 0 ;
2012-09-05 13:37:39 +04:00
}
2014-09-15 14:16:36 +04:00
Decl * TheDecl = 0 ;
2012-09-05 13:37:39 +04:00
if ( P . getCurToken ( ) . getKind ( ) = = tok : : annot_cxxscope ) {
CXXScopeSpec SS ;
S . RestoreNestedNameSpecifierAnnotation ( P . getCurToken ( ) . getAnnotationValue ( ) ,
P . getCurToken ( ) . getAnnotationRange ( ) ,
SS ) ;
if ( SS . isValid ( ) ) {
NestedNameSpecifier * NNS = SS . getScopeRep ( ) ;
NestedNameSpecifier : : SpecifierKind Kind = NNS - > getKind ( ) ;
// Only accept the parse if we consumed all of the name.
2012-09-18 15:45:00 +04:00
if ( P . NextToken ( ) . getKind ( ) = = clang : : tok : : eof ) {
2012-09-05 13:37:39 +04:00
//
// Be careful, not all nested name specifiers refer to classes
// and namespaces, and those are the only things we want.
//
switch ( Kind ) {
case NestedNameSpecifier : : Identifier : {
// Dependent type.
// We do not accept these.
}
break ;
case NestedNameSpecifier : : Namespace : {
// Namespace.
NamespaceDecl * NSD = NNS - > getAsNamespace ( ) ;
NSD = NSD - > getCanonicalDecl ( ) ;
TheDecl = NSD ;
}
break ;
case NestedNameSpecifier : : NamespaceAlias : {
// Namespace alias.
// Note: In the future, should we return the alias instead?
NamespaceAliasDecl * NSAD = NNS - > getAsNamespaceAlias ( ) ;
NamespaceDecl * NSD = NSAD - > getNamespace ( ) ;
NSD = NSD - > getCanonicalDecl ( ) ;
TheDecl = NSD ;
}
break ;
case NestedNameSpecifier : : TypeSpec :
// Type name.
2012-09-28 10:48:09 +04:00
// Intentional fall-though
2012-09-05 13:37:39 +04:00
case NestedNameSpecifier : : TypeSpecWithTemplate : {
// Type name qualified with "template".
// Note: Do we need to check for a dependent type here?
NestedNameSpecifier * prefix = NNS - > getPrefix ( ) ;
if ( prefix ) {
2013-08-03 09:48:28 +04:00
QualType temp
2012-10-14 15:44:16 +04:00
= Context . getElaboratedType ( ETK_None , prefix ,
QualType ( NNS - > getAsType ( ) , 0 ) ) ;
2012-09-05 13:37:39 +04:00
* setResultType = temp . getTypePtr ( ) ;
} else {
* setResultType = NNS - > getAsType ( ) ;
}
const TagType * TagTy = ( * setResultType ) - > getAs < TagType > ( ) ;
if ( TagTy ) {
// It is a class, struct, or union.
TagDecl * TD = TagTy - > getDecl ( ) ;
if ( TD ) {
2013-04-06 20:43:35 +04:00
TheDecl = TD - > getDefinition ( ) ;
Fix ROOT-7462 (extend fix for ROOT-6070)
Original problem:
set atlas shell environment
root.exe
TFile *_file0 = TFile::Open("atlasfile.root");
bunch of Warning about missing dictionary
c = TClass::GetClass("GaudiCommon<Algorithm>")
Error in <TProtoClass::FindDataMember>: data member with index 0 is not found in class GaudiUtils::Map<string,SmartIF<IService>,__gnu_cxx::hash_map<string,SmartIF<IService>,GaudiUtils::Hash<string>,equal_to<s
tring>,allocator<SmartIF<IService> > > >
Error in <CreateRealData>: Cannot find data member # 0 of class GaudiUtils::Map<string,SmartIF<IService>,__gnu_cxx::hash_map<string,SmartIF<IService>,GaudiUtils::Hash<string>,equal_to<string>,allocator<SmartI
F<IService> > > > for parent GaudiCommon<Algorithm>!
c->GetListOfRealData()->ls();
...
OBJ: TRealData m_services Description of persistent data members : 0 at: 0x9d46d70
OBJ: TRealData m_errors Description of persistent data members : 0 at: 0x9d47cb0
...
Tweak of the problem:
c = TClass::GetClass("GaudiCommon<Algorithm>");
c->GetListOfRealData()->ls();
...
OBJ: TRealData m_services Description of persistent data members : 0 at: 0x300ce10
OBJ: TRealData m_services. Description of persistent data members : 0 at: 0x300e9c0
OBJ: TRealData m_errors Description of persistent data members : 0 at: 0x300eaa0
...
Note: no error or warning but the ListOfRealData is 'wrong'.
Correct behavior:
TClass::GetClass("SmartIF<IService>");
TFile *_file0 = TFile::Open("atlasfile.root");
TClass::GetClass("GaudiUtils::Map<string,SmartIF<IService>,__gnu_cxx::hash_map<string,SmartIF<IService>,GaudiUtils::Hash<string>,equal_to<string>,allocator<SmartIF<IService> > > >");
c = TClass::GetClass("GaudiCommon<Algorithm>");
c->GetListOfRealData()->ls();
...
OBJ: TRealData m_services Description of persistent data members : 0 at: 0xc81c820
OBJ: TRealData m_services.m_map Description of persistent data members : 0 at: 0xc81dd00
OBJ: TRealData m_errors Description of persistent data members : 0 at: 0xc81ddb0
...
See autoparse for
unary_function<pair<const string,SmartIF<IService> >,const string>
SmartIF<IService>
Analysis:
1) Opening the file triggering the autoloading of a lots of libraries and the autoparsing of many files.
This includes the declaration of Gaudi::Map but *not* of SmartIF nor SmartIF<IService>.
[Side note: this autoloading is due to DataVector<xAOD::Jet_v1> not having a dictionary]
2) During TClass::GetClass("GaudiCommon<Algorithm>"), the TProtoClass::FillTClass is called and
disable autoloading and autoparsing and then request the GaudiUtils::Map
3) Since there is no dictionary for GaudiUtils::Map, findScope is invoked.
4) During findScope, the instantiation of GaudiUtils::Map fails with an error similar to:
error: field has incomplete type 'SmartIF<IService>'
5) The error handling code path in this case in findScope did *not* revert the transaction
and unload the 'invalid' decl for the GaudiUtils::Map
6) TClingClassInfo assume all decl are valid but finds and use the invalid decl
7) In this case, the invalidity of the decl leads to a lack of data members
8) Thus TProtoClass::FindDataMember complains about the discrepency between the TProtoClass
information and the information from the decl.
Requesting the TClass for the GaudiUtils::Map when autoloading and autoparsing are leads
to the proper instantiation and thus success.
Requesting the TClass for GaudiCommon<Algorithm> before loading the file means that
when the request for the TClass for GaudiUtils::Map is done, the declaration for
GaudiUtils::Map has not yet been parsed and thus findScope use a different error
handling code path (one where the instantiation is not even attempted).
In normal circunstances (all dictionary properly generated and loaded/loadable),
the missing name part in the list of real data member is not fatal (it would be
if it was the case during the initial gathering of information but as it is, all
the necessary information is already in the rootpcm files).
2015-08-09 21:59:21 +03:00
// NOTE: if (TheDecl) ... check for theDecl->isInvalidDecl()
if ( TD & & TD - > isInvalidDecl ( ) ) {
printf ( " Warning: FindScope got an invalid tag decl \n " ) ;
}
if ( TheDecl & & TheDecl - > isInvalidDecl ( ) ) {
printf ( " ERROR: FindScope about to return an invalid decl \n " ) ;
}
2013-04-06 20:43:35 +04:00
if ( ! TheDecl & & instantiateTemplate ) {
2013-04-06 20:44:22 +04:00
2012-12-09 05:51:25 +04:00
// Make sure it is not just forward declared, and
// instantiate any templates.
if ( ! S . RequireCompleteDeclContext ( SS , TD ) ) {
// Success, type is complete, instantiations have
// been done.
2013-04-06 20:43:35 +04:00
TheDecl = TD - > getDefinition ( ) ;
2014-02-27 20:11:08 +04:00
if ( TheDecl - > isInvalidDecl ( ) ) {
// if the decl is invalid try to clean up
2015-02-03 23:32:09 +03:00
TransactionUnloader U ( & S , /*CodeGenerator*/ 0 ) ;
2014-03-27 20:30:09 +04:00
U . UnloadDecl ( TheDecl ) ;
Fix ROOT-7462 (extend fix for ROOT-6070)
Original problem:
set atlas shell environment
root.exe
TFile *_file0 = TFile::Open("atlasfile.root");
bunch of Warning about missing dictionary
c = TClass::GetClass("GaudiCommon<Algorithm>")
Error in <TProtoClass::FindDataMember>: data member with index 0 is not found in class GaudiUtils::Map<string,SmartIF<IService>,__gnu_cxx::hash_map<string,SmartIF<IService>,GaudiUtils::Hash<string>,equal_to<s
tring>,allocator<SmartIF<IService> > > >
Error in <CreateRealData>: Cannot find data member # 0 of class GaudiUtils::Map<string,SmartIF<IService>,__gnu_cxx::hash_map<string,SmartIF<IService>,GaudiUtils::Hash<string>,equal_to<string>,allocator<SmartI
F<IService> > > > for parent GaudiCommon<Algorithm>!
c->GetListOfRealData()->ls();
...
OBJ: TRealData m_services Description of persistent data members : 0 at: 0x9d46d70
OBJ: TRealData m_errors Description of persistent data members : 0 at: 0x9d47cb0
...
Tweak of the problem:
c = TClass::GetClass("GaudiCommon<Algorithm>");
c->GetListOfRealData()->ls();
...
OBJ: TRealData m_services Description of persistent data members : 0 at: 0x300ce10
OBJ: TRealData m_services. Description of persistent data members : 0 at: 0x300e9c0
OBJ: TRealData m_errors Description of persistent data members : 0 at: 0x300eaa0
...
Note: no error or warning but the ListOfRealData is 'wrong'.
Correct behavior:
TClass::GetClass("SmartIF<IService>");
TFile *_file0 = TFile::Open("atlasfile.root");
TClass::GetClass("GaudiUtils::Map<string,SmartIF<IService>,__gnu_cxx::hash_map<string,SmartIF<IService>,GaudiUtils::Hash<string>,equal_to<string>,allocator<SmartIF<IService> > > >");
c = TClass::GetClass("GaudiCommon<Algorithm>");
c->GetListOfRealData()->ls();
...
OBJ: TRealData m_services Description of persistent data members : 0 at: 0xc81c820
OBJ: TRealData m_services.m_map Description of persistent data members : 0 at: 0xc81dd00
OBJ: TRealData m_errors Description of persistent data members : 0 at: 0xc81ddb0
...
See autoparse for
unary_function<pair<const string,SmartIF<IService> >,const string>
SmartIF<IService>
Analysis:
1) Opening the file triggering the autoloading of a lots of libraries and the autoparsing of many files.
This includes the declaration of Gaudi::Map but *not* of SmartIF nor SmartIF<IService>.
[Side note: this autoloading is due to DataVector<xAOD::Jet_v1> not having a dictionary]
2) During TClass::GetClass("GaudiCommon<Algorithm>"), the TProtoClass::FillTClass is called and
disable autoloading and autoparsing and then request the GaudiUtils::Map
3) Since there is no dictionary for GaudiUtils::Map, findScope is invoked.
4) During findScope, the instantiation of GaudiUtils::Map fails with an error similar to:
error: field has incomplete type 'SmartIF<IService>'
5) The error handling code path in this case in findScope did *not* revert the transaction
and unload the 'invalid' decl for the GaudiUtils::Map
6) TClingClassInfo assume all decl are valid but finds and use the invalid decl
7) In this case, the invalidity of the decl leads to a lack of data members
8) Thus TProtoClass::FindDataMember complains about the discrepency between the TProtoClass
information and the information from the decl.
Requesting the TClass for the GaudiUtils::Map when autoloading and autoparsing are leads
to the proper instantiation and thus success.
Requesting the TClass for GaudiCommon<Algorithm> before loading the file means that
when the request for the TClass for GaudiUtils::Map is done, the declaration for
GaudiUtils::Map has not yet been parsed and thus findScope use a different error
handling code path (one where the instantiation is not even attempted).
In normal circunstances (all dictionary properly generated and loaded/loadable),
the missing name part in the list of real data member is not fatal (it would be
if it was the case during the initial gathering of information but as it is, all
the necessary information is already in the rootpcm files).
2015-08-09 21:59:21 +03:00
* setResultType = nullptr ;
2014-02-13 19:00:30 +04:00
return 0 ;
2014-02-27 20:11:08 +04:00
}
2014-02-13 19:00:30 +04:00
} else {
Fix ROOT-7462 (extend fix for ROOT-6070)
Original problem:
set atlas shell environment
root.exe
TFile *_file0 = TFile::Open("atlasfile.root");
bunch of Warning about missing dictionary
c = TClass::GetClass("GaudiCommon<Algorithm>")
Error in <TProtoClass::FindDataMember>: data member with index 0 is not found in class GaudiUtils::Map<string,SmartIF<IService>,__gnu_cxx::hash_map<string,SmartIF<IService>,GaudiUtils::Hash<string>,equal_to<s
tring>,allocator<SmartIF<IService> > > >
Error in <CreateRealData>: Cannot find data member # 0 of class GaudiUtils::Map<string,SmartIF<IService>,__gnu_cxx::hash_map<string,SmartIF<IService>,GaudiUtils::Hash<string>,equal_to<string>,allocator<SmartI
F<IService> > > > for parent GaudiCommon<Algorithm>!
c->GetListOfRealData()->ls();
...
OBJ: TRealData m_services Description of persistent data members : 0 at: 0x9d46d70
OBJ: TRealData m_errors Description of persistent data members : 0 at: 0x9d47cb0
...
Tweak of the problem:
c = TClass::GetClass("GaudiCommon<Algorithm>");
c->GetListOfRealData()->ls();
...
OBJ: TRealData m_services Description of persistent data members : 0 at: 0x300ce10
OBJ: TRealData m_services. Description of persistent data members : 0 at: 0x300e9c0
OBJ: TRealData m_errors Description of persistent data members : 0 at: 0x300eaa0
...
Note: no error or warning but the ListOfRealData is 'wrong'.
Correct behavior:
TClass::GetClass("SmartIF<IService>");
TFile *_file0 = TFile::Open("atlasfile.root");
TClass::GetClass("GaudiUtils::Map<string,SmartIF<IService>,__gnu_cxx::hash_map<string,SmartIF<IService>,GaudiUtils::Hash<string>,equal_to<string>,allocator<SmartIF<IService> > > >");
c = TClass::GetClass("GaudiCommon<Algorithm>");
c->GetListOfRealData()->ls();
...
OBJ: TRealData m_services Description of persistent data members : 0 at: 0xc81c820
OBJ: TRealData m_services.m_map Description of persistent data members : 0 at: 0xc81dd00
OBJ: TRealData m_errors Description of persistent data members : 0 at: 0xc81ddb0
...
See autoparse for
unary_function<pair<const string,SmartIF<IService> >,const string>
SmartIF<IService>
Analysis:
1) Opening the file triggering the autoloading of a lots of libraries and the autoparsing of many files.
This includes the declaration of Gaudi::Map but *not* of SmartIF nor SmartIF<IService>.
[Side note: this autoloading is due to DataVector<xAOD::Jet_v1> not having a dictionary]
2) During TClass::GetClass("GaudiCommon<Algorithm>"), the TProtoClass::FillTClass is called and
disable autoloading and autoparsing and then request the GaudiUtils::Map
3) Since there is no dictionary for GaudiUtils::Map, findScope is invoked.
4) During findScope, the instantiation of GaudiUtils::Map fails with an error similar to:
error: field has incomplete type 'SmartIF<IService>'
5) The error handling code path in this case in findScope did *not* revert the transaction
and unload the 'invalid' decl for the GaudiUtils::Map
6) TClingClassInfo assume all decl are valid but finds and use the invalid decl
7) In this case, the invalidity of the decl leads to a lack of data members
8) Thus TProtoClass::FindDataMember complains about the discrepency between the TProtoClass
information and the information from the decl.
Requesting the TClass for the GaudiUtils::Map when autoloading and autoparsing are leads
to the proper instantiation and thus success.
Requesting the TClass for GaudiCommon<Algorithm> before loading the file means that
when the request for the TClass for GaudiUtils::Map is done, the declaration for
GaudiUtils::Map has not yet been parsed and thus findScope use a different error
handling code path (one where the instantiation is not even attempted).
In normal circunstances (all dictionary properly generated and loaded/loadable),
the missing name part in the list of real data member is not fatal (it would be
if it was the case during the initial gathering of information but as it is, all
the necessary information is already in the rootpcm files).
2015-08-09 21:59:21 +03:00
// NOTE: We cannot instantiate the scope: not a valid decl.
// Need to rollback transaction.
TransactionUnloader U ( & S , /*CodeGenerator*/ 0 ) ;
U . UnloadDecl ( TD ) ;
* setResultType = nullptr ;
2014-02-13 19:00:30 +04:00
return 0 ;
2012-09-05 13:37:39 +04:00
}
}
}
}
}
break ;
case clang : : NestedNameSpecifier : : Global : {
// Name was just "::" and nothing more.
TheDecl = Context . getTranslationUnitDecl ( ) ;
}
break ;
2015-01-15 17:13:14 +03:00
case NestedNameSpecifier : : Super :
// Microsoft's __super::
return 0 ;
2012-09-05 13:37:39 +04:00
}
return TheDecl ;
}
}
}
2012-10-26 17:32:41 +04:00
//
// Cleanup after failed parse as a nested-name-specifier.
//
2014-02-18 11:22:16 +04:00
P . SkipUntil ( clang : : tok : : eof ) ;
2014-04-01 12:51:50 +04:00
// Doesn't reset the diagnostic mappings
S . getDiagnostics ( ) . Reset ( /*soft=*/ true ) ;
2012-10-26 17:32:41 +04:00
//
// Setup to reparse as a type.
//
2013-02-19 13:25:04 +04:00
2015-01-15 17:13:14 +03:00
std : : unique_ptr < llvm : : MemoryBuffer >
SB ( llvm : : MemoryBuffer : : getMemBufferCopy ( className . str ( ) + " \n " ,
" lookup.type.file " ) ) ;
2014-09-15 14:16:36 +04:00
SourceLocation NewLoc = m_Interpreter - > getNextAvailableLoc ( ) ;
2015-01-15 17:13:14 +03:00
FileID FID = S . getSourceManager ( ) . createFileID ( std : : move ( SB ) ,
SrcMgr : : C_User ,
2014-09-15 14:16:36 +04:00
/*LoadedID*/ 0 ,
/*LoadedOffset*/ 0 , NewLoc ) ;
2014-08-01 18:36:54 +04:00
PP . EnterSourceFile ( FID , /*DirLookup*/ 0 , NewLoc ) ;
2013-02-19 13:25:04 +04:00
PP . Lex ( const_cast < clang : : Token & > ( P . getCurToken ( ) ) ) ;
2012-09-05 13:37:39 +04:00
//
// Now try to parse the name as a type.
//
2012-09-18 15:45:00 +04:00
if ( P . TryAnnotateTypeOrScopeToken ( false , false ) ) {
2012-09-05 13:37:39 +04:00
// error path
2014-09-15 14:16:36 +04:00
return 0 ;
2012-09-05 13:37:39 +04:00
}
if ( P . getCurToken ( ) . getKind ( ) = = tok : : annot_typename ) {
2012-09-18 15:45:00 +04:00
ParsedType T = P . getTypeAnnotation ( const_cast < Token & > ( P . getCurToken ( ) ) ) ;
2012-09-05 13:37:39 +04:00
// Only accept the parse if we consumed all of the name.
2013-02-19 13:30:00 +04:00
if ( P . NextToken ( ) . getKind ( ) = = clang : : tok : : eof )
if ( ! T . get ( ) . isNull ( ) ) {
TypeSourceInfo * TSI = 0 ;
clang : : QualType QT = clang : : Sema : : GetTypeFromParser ( T , & TSI ) ;
if ( const TagType * TT = QT - > getAs < TagType > ( ) ) {
TheDecl = TT - > getDecl ( ) - > getDefinition ( ) ;
* setResultType = QT . getTypePtr ( ) ;
}
2012-09-05 13:37:39 +04:00
}
}
return TheDecl ;
}
2014-02-19 11:31:45 +04:00
const ClassTemplateDecl * LookupHelper : : findClassTemplate ( llvm : : StringRef Name ,
DiagSetting diagOnOff ) const {
2012-12-01 11:22:56 +04:00
//
// Find a class template decl given its name.
//
2013-08-20 01:19:52 +04:00
if ( Name . empty ( ) ) return 0 ;
2012-12-01 11:22:56 +04:00
// Humm ... this seems to do the trick ... or does it? or is there a better way?
// Use P for shortness
Parser & P = * m_Parser ;
Sema & S = P . getActions ( ) ;
ASTContext & Context = S . getASTContext ( ) ;
ParserStateRAII ResetParserState ( P ) ;
2014-09-12 06:54:19 +04:00
prepareForParsing ( P , m_Interpreter ,
Name . str ( ) ,
2014-02-19 11:31:45 +04:00
llvm : : StringRef ( " lookup.class.by.name.file " ) , diagOnOff ) ;
2012-12-01 11:22:56 +04:00
//
// Prevent failing on an assert in TryAnnotateCXXScopeToken.
//
2013-08-03 09:48:28 +04:00
if ( ! P . getCurToken ( ) . is ( clang : : tok : : identifier )
& & ! P . getCurToken ( ) . is ( clang : : tok : : coloncolon )
& & ! ( P . getCurToken ( ) . is ( clang : : tok : : annot_template_id )
& & P . NextToken ( ) . is ( clang : : tok : : coloncolon ) )
2012-12-01 11:22:56 +04:00
& & ! P . getCurToken ( ) . is ( clang : : tok : : kw_decltype ) ) {
// error path
return 0 ;
}
//
// Now try to parse the name as a type.
//
if ( P . TryAnnotateTypeOrScopeToken ( false , false ) ) {
// error path
return 0 ;
}
DeclContext * where = 0 ;
if ( P . getCurToken ( ) . getKind ( ) = = tok : : annot_cxxscope ) {
CXXScopeSpec SS ;
S . RestoreNestedNameSpecifierAnnotation ( P . getCurToken ( ) . getAnnotationValue ( ) ,
P . getCurToken ( ) . getAnnotationRange ( ) ,
SS ) ;
if ( SS . isValid ( ) ) {
P . ConsumeToken ( ) ;
if ( ! P . getCurToken ( ) . is ( clang : : tok : : identifier ) ) {
return 0 ;
}
NestedNameSpecifier * nested = SS . getScopeRep ( ) ;
if ( ! nested ) return 0 ;
switch ( nested - > getKind ( ) ) {
case NestedNameSpecifier : : Global :
where = Context . getTranslationUnitDecl ( ) ;
break ;
case NestedNameSpecifier : : Namespace :
where = nested - > getAsNamespace ( ) ;
break ;
case NestedNameSpecifier : : NamespaceAlias :
case NestedNameSpecifier : : Identifier :
return 0 ;
case NestedNameSpecifier : : TypeSpec :
2013-08-03 09:48:28 +04:00
case NestedNameSpecifier : : TypeSpecWithTemplate :
2012-12-01 11:22:56 +04:00
{
const Type * ntype = nested - > getAsType ( ) ;
where = ntype - > getAsCXXRecordDecl ( ) ;
if ( ! where ) return 0 ;
break ;
}
2015-01-15 17:13:14 +03:00
case NestedNameSpecifier : : Super :
// Microsoft's __super::
return 0 ;
2012-12-01 11:22:56 +04:00
} ;
}
} else if ( P . getCurToken ( ) . is ( clang : : tok : : identifier ) ) {
// We have a single indentifier, let's look for it in the
// the global scope.
where = Context . getTranslationUnitDecl ( ) ;
}
if ( where ) {
// Great we now have a scope and something to search for,let's go ahead.
2015-03-10 13:55:30 +03:00
Interpreter : : PushTransactionRAII pushedT ( m_Interpreter ) ;
2013-08-03 09:48:28 +04:00
DeclContext : : lookup_result R
2013-04-24 20:28:08 +04:00
= where - > lookup ( P . getCurToken ( ) . getIdentifierInfo ( ) ) ;
for ( DeclContext : : lookup_iterator I = R . begin ( ) , E = R . end ( ) ;
I ! = E ; + + I ) {
ClassTemplateDecl * theDecl = dyn_cast < ClassTemplateDecl > ( * I ) ;
2012-12-01 11:22:56 +04:00
if ( theDecl )
return theDecl ;
}
}
return 0 ;
}
2013-11-06 07:47:48 +04:00
const ValueDecl * LookupHelper : : findDataMember ( const clang : : Decl * scopeDecl ,
2014-02-19 11:31:45 +04:00
llvm : : StringRef dataName ,
DiagSetting diagOnOff ) const {
2013-11-06 07:47:48 +04:00
// Lookup a data member based on its Decl(Context), name.
Parser & P = * m_Parser ;
Sema & S = P . getActions ( ) ;
Preprocessor & PP = S . getPreprocessor ( ) ;
2014-08-04 06:05:42 +04:00
2013-11-06 07:47:48 +04:00
IdentifierInfo * dataII = & PP . getIdentifierTable ( ) . get ( dataName ) ;
DeclarationName decl_name ( dataII ) ;
const clang : : DeclContext * dc = llvm : : cast < clang : : DeclContext > ( scopeDecl ) ;
2015-03-10 13:55:30 +03:00
Interpreter : : PushTransactionRAII pushedT ( m_Interpreter ) ;
2013-11-06 07:47:48 +04:00
DeclContext : : lookup_result lookup = const_cast < clang : : DeclContext * > ( dc ) - > lookup ( decl_name ) ;
for ( DeclContext : : lookup_iterator I = lookup . begin ( ) , E = lookup . end ( ) ;
I ! = E ; + + I ) {
const ValueDecl * result = dyn_cast < ValueDecl > ( * I ) ;
2013-11-22 23:09:17 +04:00
if ( result & & ! isa < FunctionDecl > ( result ) )
2013-11-06 07:47:48 +04:00
return result ;
}
return 0 ;
}
2013-08-03 09:48:28 +04:00
static
DeclContext * getContextAndSpec ( CXXScopeSpec & SS ,
const Decl * scopeDecl ,
ASTContext & Context , Sema & S ) {
2012-09-05 13:37:39 +04:00
//
2013-08-03 09:48:28 +04:00
// Convert the passed decl into a nested name specifier,
// a scope spec, and a decl context.
2012-09-05 13:37:39 +04:00
//
NestedNameSpecifier * classNNS = 0 ;
if ( const NamespaceDecl * NSD = dyn_cast < NamespaceDecl > ( scopeDecl ) ) {
classNNS = NestedNameSpecifier : : Create ( Context , 0 ,
const_cast < NamespaceDecl * > ( NSD ) ) ;
}
else if ( const RecordDecl * RD = dyn_cast < RecordDecl > ( scopeDecl ) ) {
const Type * T = Context . getRecordType ( RD ) . getTypePtr ( ) ;
classNNS = NestedNameSpecifier : : Create ( Context , 0 , false , T ) ;
}
else if ( llvm : : isa < TranslationUnitDecl > ( scopeDecl ) ) {
classNNS = NestedNameSpecifier : : GlobalSpecifier ( Context ) ;
}
else {
// Not a namespace or class, we cannot use it.
return 0 ;
}
DeclContext * foundDC = dyn_cast < DeclContext > ( const_cast < Decl * > ( scopeDecl ) ) ;
2013-08-03 09:48:28 +04:00
//
// Some validity checks on the passed decl.
//
if ( foundDC - > isDependentContext ( ) ) {
// Passed decl is a template, we cannot use it.
return 0 ;
}
2014-09-15 14:16:36 +04:00
// We pass a 'random' but valid source range.
SS . MakeTrivial ( Context , classNNS , scopeDecl - > getSourceRange ( ) ) ;
2013-08-03 09:48:28 +04:00
if ( S . RequireCompleteDeclContext ( SS , foundDC ) ) {
// Forward decl or instantiation failure, we cannot use it.
return 0 ;
}
2014-02-27 20:11:08 +04:00
if ( scopeDecl - > isInvalidDecl ( ) ) {
// if the decl is invalid try to clean up
2015-02-03 23:32:09 +03:00
TransactionUnloader U ( & S , /*CodeGenerator*/ 0 ) ;
2014-03-27 20:30:09 +04:00
U . UnloadDecl ( const_cast < Decl * > ( scopeDecl ) ) ;
2014-02-13 19:00:30 +04:00
return 0 ;
2014-02-27 20:11:08 +04:00
}
2013-08-03 09:48:28 +04:00
return foundDC ;
}
2013-11-13 17:51:48 +04:00
static bool FuncArgTypesMatch ( const ASTContext & C ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
2013-08-12 21:32:16 +04:00
const FunctionProtoType * FPT ) {
// FIXME: What if FTP->arg_size() != GivenArgTypes.size()?
2014-02-18 11:22:16 +04:00
FunctionProtoType : : param_type_iterator ATI = FPT - > param_type_begin ( ) ;
FunctionProtoType : : param_type_iterator E = FPT - > param_type_end ( ) ;
2014-04-01 19:50:31 +04:00
llvm : : SmallVectorImpl < Expr * > : : const_iterator GAI = GivenArgs . begin ( ) ;
2013-08-12 21:32:16 +04:00
for ( ; ATI & & ( ATI ! = E ) ; + + ATI , + + GAI ) {
2013-09-25 17:43:26 +04:00
if ( ( * GAI ) - > isLValue ( ) ) {
// If the user specified a reference we may have transform it into
// an LValue non reference (See getExprProto) to have it in a form
// useful for the lookup. So we are a bit sloppy per se here (maybe)
const ReferenceType * RefType = ( * ATI ) - > getAs < ReferenceType > ( ) ;
if ( RefType ) {
if ( ! C . hasSameType ( RefType - > getPointeeType ( ) , ( * GAI ) - > getType ( ) ) )
return false ;
} else if ( ! C . hasSameType ( * ATI , ( * GAI ) - > getType ( ) ) ) {
return false ;
}
} else if ( ! C . hasSameType ( * ATI , ( * GAI ) - > getType ( ) ) ) {
2013-08-12 21:32:16 +04:00
return false ;
}
}
return true ;
}
static bool IsOverload ( const ASTContext & C ,
const TemplateArgumentListInfo * FuncTemplateArgs ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
2013-08-12 22:30:55 +04:00
const FunctionDecl * FD ) {
2013-08-12 21:32:16 +04:00
//FunctionTemplateDecl* FTD = FD->getDescribedFunctionTemplate();
QualType FQT = C . getCanonicalType ( FD - > getType ( ) ) ;
if ( llvm : : isa < FunctionNoProtoType > ( FQT . getTypePtr ( ) ) ) {
// A K&R-style function (no prototype), is considered to match the args.
return false ;
}
const FunctionProtoType * FPT = llvm : : cast < FunctionProtoType > ( FQT ) ;
2014-02-18 11:22:16 +04:00
if ( ( GivenArgs . size ( ) ! = FPT - > getNumParams ( ) ) | |
2013-08-12 21:32:16 +04:00
//(GivenArgsAreEllipsis != FPT->isVariadic()) ||
2013-09-25 17:43:26 +04:00
! FuncArgTypesMatch ( C , GivenArgs , FPT ) ) {
2013-08-12 21:32:16 +04:00
return true ;
}
return false ;
}
2013-08-03 09:48:28 +04:00
static
const FunctionDecl * overloadFunctionSelector ( DeclContext * foundDC ,
2013-08-06 20:06:44 +04:00
bool objectIsConst ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
2013-08-03 09:48:28 +04:00
LookupResult & Result ,
DeclarationNameInfo & FuncNameInfo ,
const TemplateArgumentListInfo * FuncTemplateArgs ,
ASTContext & Context , Parser & P , Sema & S ) {
//
// Our return value.
//
FunctionDecl * TheDecl = 0 ;
2012-09-05 13:37:39 +04:00
//
2012-10-11 00:14:23 +04:00
// If we are looking up a member function, construct
// the implicit object argument.
//
// Note: For now this is always a non-CV qualified lvalue.
//
QualType ClassType ;
Expr : : Classification ObjExprClassification ;
if ( CXXRecordDecl * CRD = dyn_cast < CXXRecordDecl > ( foundDC ) ) {
2014-08-04 06:05:42 +04:00
if ( objectIsConst )
2013-08-06 20:06:44 +04:00
ClassType = Context . getTypeDeclType ( CRD ) . getCanonicalType ( ) . withConst ( ) ;
else ClassType = Context . getTypeDeclType ( CRD ) . getCanonicalType ( ) ;
2013-08-03 09:48:28 +04:00
OpaqueValueExpr ObjExpr ( SourceLocation ( ) ,
ClassType , VK_LValue ) ;
ObjExprClassification = ObjExpr . Classify ( Context ) ;
}
//
// Construct the overload candidate set.
//
2014-06-06 12:22:39 +04:00
OverloadCandidateSet Candidates ( FuncNameInfo . getLoc ( ) ,
OverloadCandidateSet : : CSK_Normal ) ;
2013-08-03 09:48:28 +04:00
for ( LookupResult : : iterator I = Result . begin ( ) , E = Result . end ( ) ;
I ! = E ; + + I ) {
NamedDecl * ND = * I ;
if ( FunctionDecl * FD = dyn_cast < FunctionDecl > ( ND ) ) {
if ( isa < CXXMethodDecl > ( FD ) & &
! cast < CXXMethodDecl > ( FD ) - > isStatic ( ) & &
! isa < CXXConstructorDecl > ( FD ) ) {
// Class method, not static, not a constructor, so has
// an implicit object argument.
CXXMethodDecl * MD = cast < CXXMethodDecl > ( FD ) ;
if ( FuncTemplateArgs & & ( FuncTemplateArgs - > size ( ) ! = 0 ) ) {
// Explicit template args were given, cannot use a plain func.
continue ;
}
S . AddMethodCandidate ( MD , I . getPair ( ) , MD - > getParent ( ) ,
/*ObjectType=*/ ClassType ,
/*ObjectClassification=*/ ObjExprClassification ,
llvm : : makeArrayRef < Expr * > ( GivenArgs . data ( ) , GivenArgs . size ( ) ) ,
Candidates ) ;
}
else {
const FunctionProtoType * Proto = dyn_cast < FunctionProtoType > (
FD - > getType ( ) - > getAs < clang : : FunctionType > ( ) ) ;
if ( ! Proto ) {
// Function has no prototype, cannot do overloading.
continue ;
}
if ( FuncTemplateArgs & & ( FuncTemplateArgs - > size ( ) ! = 0 ) ) {
// Explicit template args were given, cannot use a plain func.
continue ;
}
S . AddOverloadCandidate ( FD , I . getPair ( ) ,
llvm : : makeArrayRef < Expr * > ( GivenArgs . data ( ) , GivenArgs . size ( ) ) ,
Candidates ) ;
}
}
else if ( FunctionTemplateDecl * FTD =
dyn_cast < FunctionTemplateDecl > ( ND ) ) {
if ( isa < CXXMethodDecl > ( FTD - > getTemplatedDecl ( ) ) & &
! cast < CXXMethodDecl > ( FTD - > getTemplatedDecl ( ) ) - > isStatic ( ) & &
! isa < CXXConstructorDecl > ( FTD - > getTemplatedDecl ( ) ) ) {
// Class method template, not static, not a constructor, so has
// an implicit object argument.
S . AddMethodTemplateCandidate ( FTD , I . getPair ( ) ,
cast < CXXRecordDecl > ( FTD - > getDeclContext ( ) ) ,
const_cast < TemplateArgumentListInfo * > ( FuncTemplateArgs ) ,
/*ObjectType=*/ ClassType ,
/*ObjectClassification=*/ ObjExprClassification ,
llvm : : makeArrayRef < Expr * > ( GivenArgs . data ( ) , GivenArgs . size ( ) ) ,
Candidates ) ;
}
else {
S . AddTemplateOverloadCandidate ( FTD , I . getPair ( ) ,
const_cast < TemplateArgumentListInfo * > ( FuncTemplateArgs ) ,
llvm : : makeArrayRef < Expr * > ( GivenArgs . data ( ) , GivenArgs . size ( ) ) ,
Candidates , /*SuppressUserConversions=*/ false ) ;
}
}
else {
// Is there any other cases?
}
}
//
// Find the best viable function from the set.
//
{
OverloadCandidateSet : : iterator Best ;
OverloadingResult OR = Candidates . BestViableFunction ( S ,
Result . getNameLoc ( ) ,
Best ) ;
if ( OR = = OR_Success ) {
TheDecl = Best - > Function ;
// We prefer to get the canonical decl for consistency and ease
// of comparison.
TheDecl = TheDecl - > getCanonicalDecl ( ) ;
2013-11-04 10:07:51 +04:00
if ( TheDecl - > isTemplateInstantiation ( ) & & ! TheDecl - > isDefined ( ) )
2014-02-13 19:00:30 +04:00
S . InstantiateFunctionDefinition ( SourceLocation ( ) , TheDecl ,
true /*recursive instantiation*/ ) ;
2014-02-27 20:11:08 +04:00
if ( TheDecl - > isInvalidDecl ( ) ) {
// if the decl is invalid try to clean up
2015-02-03 23:32:09 +03:00
TransactionUnloader U ( & S , /*CodeGenerator*/ 0 ) ;
2014-03-27 20:30:09 +04:00
U . UnloadDecl ( const_cast < FunctionDecl * > ( TheDecl ) ) ;
2014-02-13 19:00:30 +04:00
return 0 ;
2014-02-27 20:11:08 +04:00
}
2013-08-03 09:48:28 +04:00
}
}
return TheDecl ;
}
2013-08-12 22:30:55 +04:00
static
const FunctionDecl * matchFunctionSelector ( DeclContext * foundDC ,
bool objectIsConst ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
2013-08-12 22:30:55 +04:00
LookupResult & Result ,
DeclarationNameInfo & FuncNameInfo ,
const TemplateArgumentListInfo * FuncTemplateArgs ,
ASTContext & Context , Parser & P , Sema & S ) {
//
// Our return value.
//
const FunctionDecl * TheDecl = overloadFunctionSelector ( foundDC , objectIsConst ,
GivenArgs , Result ,
FuncNameInfo ,
FuncTemplateArgs ,
Context , P , S ) ;
2014-08-04 06:05:42 +04:00
2013-08-12 22:30:55 +04:00
if ( TheDecl ) {
2013-11-02 03:40:29 +04:00
if ( IsOverload ( Context , FuncTemplateArgs , GivenArgs , TheDecl ) ) {
2013-08-12 22:30:55 +04:00
return 0 ;
} else {
// Double check const-ness.
if ( const clang : : CXXMethodDecl * md =
llvm : : dyn_cast < clang : : CXXMethodDecl > ( TheDecl ) ) {
if ( md - > getTypeQualifiers ( ) & clang : : Qualifiers : : Const ) {
if ( ! objectIsConst ) {
TheDecl = 0 ;
}
} else {
if ( objectIsConst ) {
TheDecl = 0 ;
}
}
}
}
}
return TheDecl ;
}
2013-08-21 06:27:35 +04:00
static bool ParseWithShortcuts ( DeclContext * foundDC , CXXScopeSpec & SS ,
2014-02-19 11:31:45 +04:00
llvm : : StringRef funcName ,
2014-08-01 18:36:54 +04:00
Interpreter * Interp ,
2014-02-19 11:31:45 +04:00
UnqualifiedId & FuncId ,
LookupHelper : : DiagSetting diagOnOff ) {
2014-08-04 06:05:42 +04:00
2013-08-21 06:27:35 +04:00
// Use a very simple parse step that dectect whether the name search (which
// is already supposed to be an unqualified name) is a simple identifier,
// a constructor name or a destructor name. In those 3 cases, we can easily
// create the UnqualifiedId object that would have resulted from the 'real'
// parse. By using this direct creation of the UnqualifiedId, we avoid the
// 'permanent' cost associated with creating a memory buffer and the
// associated FileID.
2014-08-04 06:05:42 +04:00
2013-08-21 06:27:35 +04:00
// If the name is a template or an operator, we revert to the regular parse
// (and its associated permanent cost).
2014-08-04 06:05:42 +04:00
2013-08-21 06:27:35 +04:00
// In the operator case, the additional work is in the case of a conversion
// operator where we would need to 'quickly' parse the type itself (if want
// to avoid the permanent cost).
2014-08-04 06:05:42 +04:00
2013-08-21 06:27:35 +04:00
// In the case with the template the problem gets a bit worse as we need to
// handle potentially arbitrary spaces and ordering
// ('const int' vs 'int const', etc.)
2014-08-04 06:05:42 +04:00
2014-08-01 18:36:54 +04:00
Parser & P = const_cast < Parser & > ( Interp - > getParser ( ) ) ;
Sema & S = Interp - > getSema ( ) ;
2013-08-21 06:27:35 +04:00
if ( funcName . size ( ) = = 0 ) return false ;
Preprocessor & PP = S . getPreprocessor ( ) ;
// See if we can avoid creating the buffer, for now we just look for
// simple indentifier, constructor and destructor.
2014-08-04 06:05:42 +04:00
2013-08-21 06:27:35 +04:00
if ( funcName . size ( ) > 8 & & strncmp ( funcName . data ( ) , " operator " , 8 ) = = 0
& & ( funcName [ 8 ] = = ' ' | | funcName [ 8 ] = = ' * '
| | funcName [ 8 ] = = ' % ' | | funcName [ 8 ] = = ' & '
2013-08-27 07:41:45 +04:00
| | funcName [ 8 ] = = ' | ' | | funcName [ 8 ] = = ' / '
2013-08-21 06:27:35 +04:00
| | funcName [ 8 ] = = ' + ' | | funcName [ 8 ] = = ' - '
| | funcName [ 8 ] = = ' ( ' | | funcName [ 8 ] = = ' [ '
| | funcName [ 8 ] = = ' = ' | | funcName [ 8 ] = = ' ! '
| | funcName [ 8 ] = = ' < ' | | funcName [ 8 ] = = ' > '
| | funcName [ 8 ] = = ' - ' | | funcName [ 8 ] = = ' ^ ' )
) {
// We have called:
// setOperatorFunctionId (SourceLocation OperatorLoc,
// OverloadedOperatorKind Op,
// SourceLocation SymbolLocations[3])
// or
// setConversionFunctionId (SourceLocation OperatorLoc,
// ParsedType Ty, SourceLocation EndLoc)
} else if ( funcName . find ( ' < ' ) ! = StringRef : : npos ) {
// We might have a template name,
// setTemplateId (TemplateIdAnnotation *TemplateId)
// or
// setConstructorTemplateId (TemplateIdAnnotation *TemplateId)
} else if ( funcName [ 0 ] = = ' ~ ' ) {
// Destructor.
// Let's see if this is our contructor.
TagDecl * decl = llvm : : dyn_cast < TagDecl > ( foundDC ) ;
if ( decl ) {
// We have a class or struct or something.
if ( funcName . substr ( 1 ) . equals ( decl - > getName ( ) ) ) {
ParsedType PT ;
QualType QT ( decl - > getTypeForDecl ( ) , 0 ) ;
PT . set ( QT ) ;
FuncId . setDestructorName ( SourceLocation ( ) , PT , SourceLocation ( ) ) ;
return true ;
}
}
// So it starts with ~ but is not followed by the name of
// a class or at least not the one that is the declaration context,
// let's try a real parsing, to see if we can do better.
} else {
// We either have a simple type or a constructor name
TagDecl * decl = llvm : : dyn_cast < TagDecl > ( foundDC ) ;
if ( decl ) {
// We have a class or struct or something.
if ( funcName . equals ( decl - > getName ( ) ) ) {
ParsedType PT ;
QualType QT ( decl - > getTypeForDecl ( ) , 0 ) ;
PT . set ( QT ) ;
FuncId . setConstructorName ( PT , SourceLocation ( ) , SourceLocation ( ) ) ;
} else {
IdentifierInfo * TypeInfoII = & PP . getIdentifierTable ( ) . get ( funcName ) ;
FuncId . setIdentifier ( TypeInfoII , SourceLocation ( ) ) ;
}
return true ;
} else {
// We have a namespace like context, it can't be a constructor
IdentifierInfo * TypeInfoII = & PP . getIdentifierTable ( ) . get ( funcName ) ;
FuncId . setIdentifier ( TypeInfoII , SourceLocation ( ) ) ;
return true ;
}
}
//
// Setup to reparse as a type.
//
//
// Create a fake file to parse the function name.
//
2013-11-20 13:09:48 +04:00
// FIXME:, TODO: Cleanup that complete mess.
2013-08-21 06:27:35 +04:00
{
2014-02-19 11:31:45 +04:00
PP . getDiagnostics ( ) . setSuppressAllDiagnostics ( diagOnOff = =
LookupHelper : : NoDiagnostics ) ;
2015-01-15 17:13:14 +03:00
std : : unique_ptr < llvm : : MemoryBuffer >
SB ( llvm : : MemoryBuffer : : getMemBufferCopy ( funcName . str ( ) + " \n " ,
" lookup.funcname.file " ) ) ;
2014-08-01 18:36:54 +04:00
SourceLocation NewLoc = Interp - > getNextAvailableLoc ( ) ;
2015-01-15 17:13:14 +03:00
FileID FID = S . getSourceManager ( ) . createFileID ( std : : move ( SB ) ,
SrcMgr : : C_User ,
2014-08-02 18:22:00 +04:00
/*LoadedID*/ 0 ,
/*LoadedOffset*/ 0 , NewLoc ) ;
2014-08-01 18:36:54 +04:00
PP . EnterSourceFile ( FID , /*DirLookup*/ 0 , NewLoc ) ;
2013-08-21 06:27:35 +04:00
PP . Lex ( const_cast < clang : : Token & > ( P . getCurToken ( ) ) ) ;
}
2014-08-04 06:05:42 +04:00
2013-08-21 06:27:35 +04:00
//
// Parse the function name.
//
SourceLocation TemplateKWLoc ;
if ( P . ParseUnqualifiedId ( SS , /*EnteringContext*/ false ,
/*AllowDestructorName*/ true ,
/*AllowConstructorName*/ true ,
ParsedType ( ) , TemplateKWLoc ,
FuncId ) ) {
// Failed parse, cleanup.
return false ;
}
return true ;
}
2013-08-03 09:48:28 +04:00
template < typename T >
T findFunction ( DeclContext * foundDC , CXXScopeSpec & SS ,
llvm : : StringRef funcName ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
2013-08-06 20:06:44 +04:00
bool objectIsConst ,
2014-08-01 18:36:54 +04:00
ASTContext & Context , Interpreter * Interp ,
2013-08-03 09:48:28 +04:00
T ( * functionSelector ) ( DeclContext * foundDC ,
2013-08-06 20:06:44 +04:00
bool objectIsConst ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
2013-08-03 09:48:28 +04:00
LookupResult & Result ,
DeclarationNameInfo & FuncNameInfo ,
const TemplateArgumentListInfo * FuncTemplateArgs ,
2014-02-19 11:31:45 +04:00
ASTContext & Context , Parser & P , Sema & S ) ,
LookupHelper : : DiagSetting diagOnOff
) {
2013-08-03 09:48:28 +04:00
// Given the correctly types arguments, etc. find the function itself.
//
// Make the class we are looking up the function
// in the current scope to please the constructor
// name lookup. We do not need to do this otherwise,
// and may be able to remove it in the future if
// the way constructors are looked up changes.
//
2014-08-01 18:36:54 +04:00
Parser & P = const_cast < Parser & > ( Interp - > getParser ( ) ) ;
Sema & S = Interp - > getSema ( ) ;
2014-02-18 11:22:16 +04:00
DeclContext * OldEntity = P . getCurScope ( ) - > getEntity ( ) ;
2013-08-03 09:48:28 +04:00
DeclContext * TUCtx = Context . getTranslationUnitDecl ( ) ;
P . getCurScope ( ) - > setEntity ( TUCtx ) ;
P . EnterScope ( Scope : : DeclScope ) ;
P . getCurScope ( ) - > setEntity ( foundDC ) ;
P . EnterScope ( Scope : : DeclScope ) ;
Sema : : ContextRAII SemaContext ( S , foundDC ) ;
S . EnterDeclaratorContext ( P . getCurScope ( ) , foundDC ) ;
2013-08-21 06:27:35 +04:00
2013-08-03 09:48:28 +04:00
UnqualifiedId FuncId ;
From Vassil and me: move RAII out of ParseWithShortcuts().
The RAII destructs TemplateIdAnnotations that are still needed by the caller, as pointed out by valgrind:
==4595== Invalid read of size 4
==4595== at 0x1C88E9A: clang::Sema::DecomposeUnqualifiedId(clang::UnqualifiedId const&, clang::TemplateArgumentListInfo&, clang::DeclarationNameInfo&, clang::TemplateArgumentListInfo const*&) (SemaExpr.cpp:1635)
==4595== by 0x147FF03: clang::FunctionDecl const* cling::findFunction<clang::FunctionDecl const*>(clang::DeclContext*, clang::CXXScopeSpec&, llvm::StringRef, llvm::SmallVector<clang::Expr*, 4u> const&, bool, clang::ASTContext&, clang::Parser&, clang::Sema&, clang::FunctionDecl const* (*)(clang::DeclContext*, bool, llvm::SmallVector<clang::Expr*, 4u> const&, clang::LookupResult&, clang::DeclarationNameInfo&, clang::TemplateArgumentListInfo const*, clang::ASTContext&, clang::Parser&, clang::Sema&)) (LookupHelper.cpp:819)
==4595== by 0x147DE1A: cling::LookupHelper::findFunctionArgs(clang::Decl const*, llvm::StringRef, llvm::StringRef, bool) const (LookupHelper.cpp:1374)
==4595== Address 0x8013e74 is 68 bytes inside a block of size 136 free'd
==4595== at 0x402B77D: free (vg_replace_malloc.c:468)
==4595== by 0x1484A11: clang::TemplateIdAnnotation::Destroy() (ParsedTemplate.h:205)
==4595== by 0x1484979: clang::DestroyTemplateIdAnnotationsRAIIObj::~DestroyTemplateIdAnnotationsRAIIObj() (RAIIObjectsForParser.h:446)
==4595== by 0x1484914: clang::DestroyTemplateIdAnnotationsRAIIObj::~DestroyTemplateIdAnnotationsRAIIObj() (RAIIObjectsForParser.h:442)
==4595== by 0x14848F8: cling::ParserStateRAII::~ParserStateRAII() (LookupHelper.cpp:67)
==4595== by 0x147F284: cling::ParserStateRAII::~ParserStateRAII() (LookupHelper.cpp:54)
==4595== by 0x147EDB1: cling::ParseWithShortcuts(clang::DeclContext*, clang::CXXScopeSpec&, llvm::StringRef, clang::Parser&, clang::Sema&, clang::UnqualifiedId&) (LookupHelper.cpp:765)
==4595== by 0x147FE5A: clang::FunctionDecl const* cling::findFunction<clang::FunctionDecl const*>(clang::DeclContext*, clang::CXXScopeSpec&, llvm::StringRef, llvm::SmallVector<clang::Expr*, 4u> const&, bool, clang::ASTContext&, clang::Parser&, clang::Sema&, clang::FunctionDecl const* (*)(clang::DeclContext*, bool, llvm::SmallVector<clang::Expr*, 4u> const&, clang::LookupResult&, clang::DeclarationNameInfo&, clang::TemplateArgumentListInfo const*, clang::ASTContext&, clang::Parser&, clang::Sema&)) (LookupHelper.cpp:801)
==4595== by 0x147DE1A: cling::LookupHelper::findFunctionArgs(clang::Decl const*, llvm::StringRef, llvm::StringRef, bool) const (LookupHelper.cpp:1374)
2013-11-22 18:35:12 +04:00
ParserStateRAII ResetParserState ( P ) ;
2014-08-01 18:36:54 +04:00
if ( ! ParseWithShortcuts ( foundDC , SS , funcName , Interp , FuncId , diagOnOff ) ) {
2013-08-03 09:48:28 +04:00
// Failed parse, cleanup.
// Destroy the scope we created first, and
// restore the original.
S . ExitDeclaratorContext ( P . getCurScope ( ) ) ;
P . ExitScope ( ) ;
P . ExitScope ( ) ;
P . getCurScope ( ) - > setEntity ( OldEntity ) ;
// Then exit.
2013-11-13 17:51:48 +04:00
return 0 ;
2013-08-03 09:48:28 +04:00
}
2013-08-21 06:27:35 +04:00
2013-08-03 09:48:28 +04:00
//
// Get any template args in the function name.
//
TemplateArgumentListInfo FuncTemplateArgsBuffer ;
DeclarationNameInfo FuncNameInfo ;
const TemplateArgumentListInfo * FuncTemplateArgs ;
S . DecomposeUnqualifiedId ( FuncId , FuncTemplateArgsBuffer , FuncNameInfo ,
FuncTemplateArgs ) ;
2013-08-21 06:27:35 +04:00
2013-08-03 09:48:28 +04:00
//
// Lookup the function name in the given class now.
//
DeclarationName FuncName = FuncNameInfo . getName ( ) ;
SourceLocation FuncNameLoc = FuncNameInfo . getLoc ( ) ;
LookupResult Result ( S , FuncName , FuncNameLoc , Sema : : LookupMemberName ,
Sema : : NotForRedeclaration ) ;
2013-12-02 17:15:19 +04:00
Result . suppressDiagnostics ( ) ;
2013-08-03 09:48:28 +04:00
if ( ! S . LookupQualifiedName ( Result , foundDC ) ) {
// Lookup failed.
// Destroy the scope we created first, and
// restore the original.
S . ExitDeclaratorContext ( P . getCurScope ( ) ) ;
P . ExitScope ( ) ;
P . ExitScope ( ) ;
P . getCurScope ( ) - > setEntity ( OldEntity ) ;
// Then cleanup and exit.
2013-11-13 17:51:48 +04:00
return 0 ;
2013-08-03 09:48:28 +04:00
}
2013-08-21 06:27:35 +04:00
2013-08-03 09:48:28 +04:00
//
// Destroy the scope we created, and restore the original.
//
S . ExitDeclaratorContext ( P . getCurScope ( ) ) ;
P . ExitScope ( ) ;
P . ExitScope ( ) ;
P . getCurScope ( ) - > setEntity ( OldEntity ) ;
//
// Check for lookup failure.
//
if ( Result . getResultKind ( ) ! = LookupResult : : Found & &
Result . getResultKind ( ) ! = LookupResult : : FoundOverloaded ) {
// Lookup failed.
2013-11-13 17:51:48 +04:00
return 0 ;
2013-08-03 09:48:28 +04:00
}
2013-08-06 20:06:44 +04:00
return functionSelector ( foundDC , objectIsConst , GivenArgs ,
2013-08-03 09:48:28 +04:00
Result ,
FuncNameInfo ,
FuncTemplateArgs ,
Context , P , S ) ;
}
2014-09-12 15:58:37 +04:00
template < typename DigestArgsInput , typename returnType >
returnType execFindFunction ( Parser & P ,
Interpreter * Interp ,
const clang : : Decl * scopeDecl ,
llvm : : StringRef funcName ,
const typename DigestArgsInput : : ArgsInput & funcArgs ,
bool objectIsConst ,
returnType ( * functionSelector ) ( DeclContext * foundDC ,
bool objectIsConst ,
const llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
LookupResult & Result ,
DeclarationNameInfo & FuncNameInfo ,
const TemplateArgumentListInfo * FuncTemplateArgs ,
ASTContext & Context , Parser & P , Sema & S ) ,
LookupHelper : : DiagSetting diagOnOff
)
2014-09-12 05:54:36 +04:00
{
assert ( scopeDecl & & " Decl cannot be null " ) ;
//
// Some utilities.
//
Sema & S = P . getActions ( ) ;
ASTContext & Context = S . getASTContext ( ) ;
//
// Convert the passed decl into a nested name specifier,
// a scope spec, and a decl context.
//
// Do this 'early' to save on the expansive parser setup,
// in case of failure.
//
CXXScopeSpec SS ;
DeclContext * foundDC = getContextAndSpec ( SS , scopeDecl , Context , S ) ;
if ( ! foundDC ) return 0 ;
2014-09-12 15:58:37 +04:00
DigestArgsInput inputEval ;
2014-09-12 05:54:36 +04:00
llvm : : SmallVector < Expr * , 4 > GivenArgs ;
2014-09-12 15:58:37 +04:00
if ( ! inputEval ( GivenArgs , funcArgs , diagOnOff , P , Interp ) ) return 0 ;
2014-09-12 05:54:36 +04:00
Interpreter : : PushTransactionRAII pushedT ( Interp ) ;
return findFunction ( foundDC , SS ,
funcName , GivenArgs , objectIsConst ,
Context , Interp , functionSelector ,
diagOnOff ) ;
}
2014-09-12 15:58:37 +04:00
struct NoParse {
2014-08-04 06:05:42 +04:00
2014-09-12 15:58:37 +04:00
typedef const char * ArgsInput ;
bool operator ( ) ( llvm : : SmallVectorImpl < Expr * > & /* GivenArgs */ ,
const ArgsInput & /* funcArgs */ ,
LookupHelper : : DiagSetting /* diagOnOff */ ,
Parser & /* P */ , const Interpreter * /* Interp */ )
{
return true ;
}
} ;
struct ExprFromTypes {
typedef llvm : : SmallVectorImpl < QualType > ArgsInput ;
llvm : : SmallVector < ExprAlloc , 4 > ExprMemory ;
bool operator ( ) ( llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
const ArgsInput & GivenTypes ,
LookupHelper : : DiagSetting /* diagOnOff */ ,
Parser & /* P */ , const Interpreter * /* Interp */ ) {
if ( GivenTypes . empty ( ) ) return true ;
else return getExprProto ( GivenArgs , GivenTypes ) ;
}
bool getExprProto ( llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
const llvm : : SmallVectorImpl < QualType > & GivenTypes ) {
//
// Create the array of Expr from the array of Types.
//
typedef llvm : : SmallVectorImpl < QualType > : : const_iterator iterator ;
for ( iterator iter = GivenTypes . begin ( ) , end = GivenTypes . end ( ) ;
iter ! = end ;
+ + iter ) {
const clang : : QualType QT = iter - > getCanonicalType ( ) ;
{
ExprValueKind VK = VK_RValue ;
if ( QT - > getAs < LValueReferenceType > ( ) ) {
VK = VK_LValue ;
}
clang : : QualType NonRefQT ( QT . getNonReferenceType ( ) ) ;
unsigned int slot = ExprMemory . size ( ) ;
ExprMemory . resize ( slot + 1 ) ;
Expr * val = new ( & ExprMemory [ slot ] ) OpaqueValueExpr ( SourceLocation ( ) ,
NonRefQT , VK ) ;
GivenArgs . push_back ( val ) ;
2013-08-25 10:16:29 +04:00
}
}
2014-09-12 15:58:37 +04:00
return true ;
2013-08-25 10:16:29 +04:00
}
2014-09-12 15:58:37 +04:00
} ;
2013-08-25 10:16:29 +04:00
2014-09-12 15:58:37 +04:00
struct ParseProto {
2013-08-03 09:48:28 +04:00
2014-09-12 15:58:37 +04:00
typedef llvm : : StringRef ArgsInput ;
llvm : : SmallVector < ExprAlloc , 4 > ExprMemory ;
bool operator ( ) ( llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
const ArgsInput & funcProto ,
LookupHelper : : DiagSetting diagOnOff ,
Parser & P , const Interpreter * Interp ) {
if ( funcProto . empty ( ) ) return true ;
else return Parse ( GivenArgs , funcProto , diagOnOff , P , Interp ) ;
}
bool Parse ( llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
const ArgsInput & funcProto ,
LookupHelper : : DiagSetting diagOnOff ,
Parser & P , const Interpreter * Interp ) {
//
// Parse the prototype now.
//
ParserStateRAII ResetParserState ( P ) ;
prepareForParsing ( P , Interp ,
funcProto , llvm : : StringRef ( " func.prototype.file " ) , diagOnOff ) ;
unsigned int nargs = 0 ;
while ( P . getCurToken ( ) . isNot ( tok : : eof ) ) {
TypeResult Res ( P . ParseTypeName ( ) ) ;
if ( ! Res . isUsable ( ) ) {
// Bad parse, done.
return false ;
2012-10-11 02:55:40 +04:00
}
2014-09-12 15:58:37 +04:00
TypeSourceInfo * TSI = 0 ;
clang : : QualType QT = clang : : Sema : : GetTypeFromParser ( Res . get ( ) , & TSI ) ;
QT = QT . getCanonicalType ( ) ;
{
ExprValueKind VK = VK_RValue ;
if ( QT - > getAs < LValueReferenceType > ( ) ) {
VK = VK_LValue ;
}
clang : : QualType NonRefQT ( QT . getNonReferenceType ( ) ) ;
ExprMemory . resize ( + + nargs ) ;
new ( & ExprMemory [ nargs - 1 ] ) OpaqueValueExpr ( TSI - > getTypeLoc ( ) . getLocStart ( ) ,
NonRefQT , VK ) ;
}
// Type names should be comma separated.
// FIXME: Here if we have type followed by name won't work. Eg int f, ...
if ( ! P . getCurToken ( ) . is ( clang : : tok : : comma ) ) {
break ;
}
// Eat the comma.
P . ConsumeToken ( ) ;
2012-09-05 13:37:39 +04:00
}
2014-09-12 15:58:37 +04:00
for ( unsigned int slot = 0 ; slot < nargs ; + + slot ) {
Expr * val = ( OpaqueValueExpr * ) ( & ExprMemory [ slot ] ) ;
GivenArgs . push_back ( val ) ;
2012-09-05 13:37:39 +04:00
}
2014-09-12 15:58:37 +04:00
if ( P . getCurToken ( ) . isNot ( tok : : eof ) ) {
// We did not consume all of the prototype, bad parse.
return false ;
}
//
// Cleanup after prototype parse.
//
P . SkipUntil ( clang : : tok : : eof ) ;
// Doesn't reset the diagnostic mappings
Sema & S = P . getActions ( ) ;
S . getDiagnostics ( ) . Reset ( /*soft=*/ true ) ;
2013-08-03 09:48:28 +04:00
2014-09-12 15:58:37 +04:00
return true ;
}
} ;
2013-08-03 09:48:28 +04:00
2013-11-13 17:51:48 +04:00
static
const FunctionTemplateDecl * findFunctionTemplateSelector ( DeclContext * ,
bool /* objectIsConst */ ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < Expr * > & ,
2013-11-13 17:51:48 +04:00
LookupResult & Result ,
DeclarationNameInfo & ,
const TemplateArgumentListInfo * ExplicitTemplateArgs ,
ASTContext & , Parser & ,
Sema & S ) {
//
// Check for lookup failure.
//
if ( Result . empty ( ) )
return 0 ;
if ( Result . isSingleResult ( ) )
return dyn_cast < FunctionTemplateDecl > ( Result . getFoundDecl ( ) ) ;
else {
for ( LookupResult : : iterator I = Result . begin ( ) , E = Result . end ( ) ;
I ! = E ; + + I ) {
NamedDecl * ND = * I ;
FunctionTemplateDecl * MethodTmpl = dyn_cast < FunctionTemplateDecl > ( ND ) ;
if ( MethodTmpl ) {
return MethodTmpl ;
}
}
return 0 ;
}
}
const FunctionTemplateDecl *
LookupHelper : : findFunctionTemplate ( const clang : : Decl * scopeDecl ,
llvm : : StringRef templateName ,
2014-02-19 11:31:45 +04:00
DiagSetting diagOnOff ,
bool objectIsConst ) const {
2013-11-13 17:51:48 +04:00
// Lookup a function template based on its Decl(Context), name.
2014-09-12 15:58:37 +04:00
return execFindFunction < NoParse > ( * m_Parser , m_Interpreter ,
scopeDecl ,
templateName , " " ,
objectIsConst ,
findFunctionTemplateSelector ,
diagOnOff ) ;
2013-11-13 17:51:48 +04:00
}
2013-11-02 03:40:29 +04:00
static
const FunctionDecl * findAnyFunctionSelector ( DeclContext * ,
bool /* objectIsConst */ ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < Expr * > & ,
2013-11-02 03:40:29 +04:00
LookupResult & Result ,
DeclarationNameInfo & ,
2013-11-04 09:22:41 +04:00
const TemplateArgumentListInfo * ExplicitTemplateArgs ,
ASTContext & , Parser & , Sema & S ) {
2013-11-02 03:40:29 +04:00
//
// Check for lookup failure.
//
if ( Result . empty ( ) )
return 0 ;
if ( Result . isSingleResult ( ) )
return dyn_cast < FunctionDecl > ( Result . getFoundDecl ( ) ) ;
2013-11-04 09:22:41 +04:00
else {
NamedDecl * aResult = * ( Result . begin ( ) ) ;
FunctionDecl * res = dyn_cast < FunctionDecl > ( aResult ) ;
if ( res ) return res ;
FunctionTemplateDecl * MethodTmpl = dyn_cast < FunctionTemplateDecl > ( aResult ) ;
if ( MethodTmpl ) {
2013-11-11 22:00:39 +04:00
if ( ! ExplicitTemplateArgs | | ExplicitTemplateArgs - > size ( ) = = 0 ) {
// Not argument was specified, any instantiation will do.
if ( MethodTmpl - > spec_begin ( ) ! = MethodTmpl - > spec_end ( ) ) {
return * ( MethodTmpl - > spec_begin ( ) ) ;
}
}
2013-11-04 09:22:41 +04:00
// pick a specialization that result match the given arguments
SourceLocation loc ;
sema : : TemplateDeductionInfo Info ( loc ) ;
FunctionDecl * fdecl = 0 ;
Sema : : TemplateDeductionResult Result
= S . DeduceTemplateArguments ( MethodTmpl ,
const_cast < TemplateArgumentListInfo * > ( ExplicitTemplateArgs ) ,
fdecl ,
Info ) ;
if ( Result ) {
2013-11-11 22:00:39 +04:00
// Deduction failure.
2013-11-04 09:22:41 +04:00
return 0 ;
} else {
2013-11-13 17:51:48 +04:00
// Instantiate the function if needed.
2013-11-04 09:47:27 +04:00
if ( ! fdecl - > isDefined ( ) )
2014-02-13 19:00:30 +04:00
S . InstantiateFunctionDefinition ( loc , fdecl ,
true /*recursive instantiation*/ ) ;
2014-02-27 20:11:08 +04:00
if ( fdecl - > isInvalidDecl ( ) ) {
// if the decl is invalid try to clean up
2015-02-03 23:32:09 +03:00
TransactionUnloader U ( & S , /*CodeGenerator*/ 0 ) ;
2014-03-27 20:30:09 +04:00
U . UnloadDecl ( fdecl ) ;
2014-02-13 19:00:30 +04:00
return 0 ;
2014-02-27 20:11:08 +04:00
}
2013-11-04 09:22:41 +04:00
return fdecl ;
}
}
return 0 ;
}
2013-11-02 03:40:29 +04:00
}
2013-11-04 09:22:41 +04:00
const FunctionDecl * LookupHelper : : findAnyFunction ( const clang : : Decl * scopeDecl ,
2013-11-02 03:40:29 +04:00
llvm : : StringRef funcName ,
2014-02-19 11:31:45 +04:00
DiagSetting diagOnOff ,
bool objectIsConst ) const {
2013-11-02 03:40:29 +04:00
2014-09-12 15:58:37 +04:00
return execFindFunction < NoParse > ( * m_Parser , m_Interpreter ,
scopeDecl ,
funcName , " " ,
objectIsConst ,
findAnyFunctionSelector ,
diagOnOff ) ;
2013-11-02 03:40:29 +04:00
}
2014-02-19 11:31:45 +04:00
const FunctionDecl *
LookupHelper : : findFunctionProto ( const Decl * scopeDecl ,
llvm : : StringRef funcName ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < QualType > & funcProto ,
2014-02-19 11:31:45 +04:00
DiagSetting diagOnOff , bool objectIsConst ) const {
2013-08-25 10:16:29 +04:00
assert ( scopeDecl & & " Decl cannot be null " ) ;
2014-09-12 15:58:37 +04:00
return execFindFunction < ExprFromTypes > ( * m_Parser , m_Interpreter ,
scopeDecl ,
funcName ,
funcProto ,
objectIsConst ,
overloadFunctionSelector ,
diagOnOff ) ;
2013-08-25 10:16:29 +04:00
}
2014-08-04 06:05:42 +04:00
2013-08-03 09:48:28 +04:00
const FunctionDecl * LookupHelper : : findFunctionProto ( const Decl * scopeDecl ,
llvm : : StringRef funcName ,
2013-08-06 20:06:44 +04:00
llvm : : StringRef funcProto ,
2014-02-19 11:31:45 +04:00
DiagSetting diagOnOff ,
bool objectIsConst ) const {
2013-08-03 09:48:28 +04:00
assert ( scopeDecl & & " Decl cannot be null " ) ;
2014-09-12 15:58:37 +04:00
return execFindFunction < ParseProto > ( * m_Parser , m_Interpreter ,
scopeDecl ,
funcName ,
funcProto ,
objectIsConst ,
overloadFunctionSelector ,
diagOnOff ) ;
2013-08-03 09:48:28 +04:00
}
2014-02-19 11:31:45 +04:00
const FunctionDecl *
LookupHelper : : matchFunctionProto ( const Decl * scopeDecl ,
llvm : : StringRef funcName ,
llvm : : StringRef funcProto ,
DiagSetting diagOnOff ,
bool objectIsConst ) const {
2013-08-12 22:30:55 +04:00
assert ( scopeDecl & & " Decl cannot be null " ) ;
2014-09-12 15:58:37 +04:00
return execFindFunction < ParseProto > ( * m_Parser , m_Interpreter ,
scopeDecl ,
funcName ,
funcProto ,
objectIsConst ,
matchFunctionSelector ,
diagOnOff ) ;
2013-08-12 22:30:55 +04:00
}
2014-02-19 11:31:45 +04:00
const FunctionDecl *
LookupHelper : : matchFunctionProto ( const Decl * scopeDecl ,
llvm : : StringRef funcName ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < QualType > & funcProto ,
2014-02-19 11:31:45 +04:00
DiagSetting diagOnOff ,
bool objectIsConst ) const {
2013-08-25 10:16:29 +04:00
assert ( scopeDecl & & " Decl cannot be null " ) ;
2014-08-04 06:05:42 +04:00
2014-09-12 15:58:37 +04:00
return execFindFunction < ExprFromTypes > ( * m_Parser , m_Interpreter ,
scopeDecl ,
funcName ,
funcProto ,
objectIsConst ,
matchFunctionSelector ,
diagOnOff ) ;
}
2014-08-04 06:05:42 +04:00
2014-09-12 15:58:37 +04:00
struct ParseArgs {
typedef llvm : : StringRef ArgsInput ;
2014-08-04 06:05:42 +04:00
2014-09-12 15:58:37 +04:00
bool operator ( ) ( llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
const ArgsInput & funcArgs ,
LookupHelper : : DiagSetting diagOnOff ,
Parser & P , const Interpreter * Interp ) {
2014-08-04 06:05:42 +04:00
2014-09-12 15:58:37 +04:00
if ( funcArgs . empty ( ) ) return true ;
else return Parse ( GivenArgs , funcArgs , diagOnOff , P , Interp ) ;
}
bool Parse ( llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
2014-09-12 06:54:19 +04:00
llvm : : StringRef funcArgs ,
LookupHelper : : DiagSetting diagOnOff ,
Parser & P , const Interpreter * Interp ) {
2013-08-03 09:48:28 +04:00
2014-09-12 15:58:37 +04:00
//
// Parse the arguments now.
//
2013-08-03 09:48:28 +04:00
2014-11-20 13:16:15 +03:00
Interpreter : : PushTransactionRAII TforDeser ( Interp ) ;
2014-09-12 15:58:37 +04:00
ParserStateRAII ResetParserState ( P ) ;
prepareForParsing ( P , Interp ,
funcArgs , llvm : : StringRef ( " func.args.file " ) , diagOnOff ) ;
2014-09-12 06:54:19 +04:00
2014-09-12 15:58:37 +04:00
Sema & S = P . getActions ( ) ;
ASTContext & Context = S . getASTContext ( ) ;
2014-09-12 06:54:19 +04:00
2014-09-12 15:58:37 +04:00
PrintingPolicy Policy ( Context . getPrintingPolicy ( ) ) ;
Policy . SuppressTagKeyword = true ;
Policy . SuppressUnwrittenScope = true ;
Policy . SuppressInitializers = true ;
Policy . AnonymousTagLocations = false ;
std : : string proto ;
{
bool first_time = true ;
while ( P . getCurToken ( ) . isNot ( tok : : eof ) ) {
ExprResult Res = P . ParseAssignmentExpression ( ) ;
if ( Res . isUsable ( ) ) {
Expr * expr = Res . get ( ) ;
GivenArgs . push_back ( expr ) ;
if ( first_time ) {
first_time = false ;
}
else {
proto + = ' , ' ;
}
std : : string empty ;
llvm : : raw_string_ostream tmp ( empty ) ;
expr - > printPretty ( tmp , /*PrinterHelper=*/ 0 , Policy ,
/*Indentation=*/ 0 ) ;
proto + = tmp . str ( ) ;
2012-09-05 13:37:39 +04:00
}
2014-09-12 15:58:37 +04:00
if ( ! P . getCurToken ( ) . is ( tok : : comma ) ) {
break ;
2012-10-11 00:14:23 +04:00
}
2014-09-12 15:58:37 +04:00
P . ConsumeToken ( ) ;
2012-09-05 13:37:39 +04:00
}
}
2014-09-12 15:58:37 +04:00
// For backward compatibility with CINT accept (for now?) a trailing close
// parenthesis.
if ( P . getCurToken ( ) . isNot ( tok : : eof ) & & P . getCurToken ( ) . isNot ( tok : : r_paren ) ) {
// We did not consume all of the arg list, bad parse.
return false ;
}
//
// Cleanup after the arg list parse.
//
P . SkipUntil ( clang : : tok : : eof ) ;
// Doesn't reset the diagnostic mappings
S . getDiagnostics ( ) . Reset ( /*soft=*/ true ) ;
return true ;
2012-09-05 13:37:39 +04:00
}
2014-09-12 15:58:37 +04:00
} ;
2012-09-05 13:37:39 +04:00
2014-02-19 11:31:45 +04:00
const FunctionDecl *
LookupHelper : : findFunctionArgs ( const Decl * scopeDecl ,
llvm : : StringRef funcName ,
llvm : : StringRef funcArgs ,
DiagSetting diagOnOff ,
bool objectIsConst ) const {
2013-08-03 09:48:28 +04:00
assert ( scopeDecl & & " Decl cannot be null " ) ;
2012-10-12 20:09:04 +04:00
2014-09-12 15:58:37 +04:00
return execFindFunction < ParseArgs > ( * m_Parser , m_Interpreter ,
scopeDecl ,
funcName ,
funcArgs ,
objectIsConst ,
overloadFunctionSelector ,
diagOnOff ) ;
2012-09-05 13:37:39 +04:00
}
void LookupHelper : : findArgList ( llvm : : StringRef argList ,
2014-04-01 19:50:31 +04:00
llvm : : SmallVectorImpl < Expr * > & argExprs ,
2014-02-19 11:31:45 +04:00
DiagSetting diagOnOff ) const {
2013-08-20 01:19:52 +04:00
if ( argList . empty ( ) ) return ;
2012-09-05 13:37:39 +04:00
//
// Some utilities.
//
// Use P for shortness
2014-08-04 06:05:42 +04:00
Parser & P = * m_Parser ;
2012-11-20 17:17:55 +04:00
ParserStateRAII ResetParserState ( P ) ;
2014-09-12 06:54:19 +04:00
prepareForParsing ( P , m_Interpreter ,
argList , llvm : : StringRef ( " arg.list.file " ) , diagOnOff ) ;
2012-10-14 15:44:16 +04:00
//
2012-09-05 13:37:39 +04:00
// Parse the arguments now.
//
{
bool hasUnusableResult = false ;
while ( P . getCurToken ( ) . isNot ( tok : : eof ) ) {
2012-09-18 15:45:00 +04:00
ExprResult Res = P . ParseAssignmentExpression ( ) ;
2012-09-05 13:37:39 +04:00
if ( Res . isUsable ( ) ) {
2014-06-06 12:23:36 +04:00
argExprs . push_back ( Res . get ( ) ) ;
2012-09-05 13:37:39 +04:00
}
else {
hasUnusableResult = true ;
break ;
}
if ( ! P . getCurToken ( ) . is ( tok : : comma ) ) {
break ;
}
2012-09-18 15:45:00 +04:00
P . ConsumeToken ( ) ;
2012-09-05 13:37:39 +04:00
}
if ( hasUnusableResult )
// if one of the arguments is not usable return empty.
argExprs . clear ( ) ;
}
}
2013-08-03 09:48:28 +04:00
static
bool hasFunctionSelector ( DeclContext * ,
2013-08-06 20:06:44 +04:00
bool /* objectIsConst */ ,
2014-04-01 19:50:31 +04:00
const llvm : : SmallVectorImpl < Expr * > & ,
2013-08-03 09:48:28 +04:00
LookupResult & Result ,
DeclarationNameInfo & ,
const TemplateArgumentListInfo * ,
ASTContext & , Parser & , Sema & ) {
//
// Check for lookup failure.
//
if ( Result . empty ( ) )
return false ;
if ( Result . isSingleResult ( ) )
return isa < FunctionDecl > ( Result . getFoundDecl ( ) ) ;
// We have many - those must be functions.
return true ;
}
2013-04-05 17:50:01 +04:00
bool LookupHelper : : hasFunction ( const clang : : Decl * scopeDecl ,
2014-02-19 11:31:45 +04:00
llvm : : StringRef funcName ,
DiagSetting diagOnOff ) const {
2013-04-05 17:50:01 +04:00
2014-09-12 15:58:37 +04:00
return execFindFunction < NoParse > ( * m_Parser , m_Interpreter ,
scopeDecl ,
funcName , " " ,
false /* objectIsConst */ ,
hasFunctionSelector ,
diagOnOff ) ;
2013-04-05 17:50:01 +04:00
}
2012-09-05 13:37:39 +04:00
} // end namespace cling