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"
2016-12-14 23:32:18 +03:00
# include "cling/Utils/Output.h"
2012-09-05 13:37:39 +04:00
2016-06-26 11:06:18 +03:00
# include "DeclUnloader.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"
2016-11-07 17:02:42 +03:00
# include "cling/Utils/ParserStateRAII.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"
using namespace clang ;
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 ) ] ;
} ;
2018-08-08 19:46:34 +03:00
class StartParsingRAII {
LookupHelper & m_LH ;
2019-05-03 18:38:18 +03:00
llvm : : SaveAndRestore < bool > SaveIsRecursivelyRunning ;
2019-09-06 19:02:07 +03:00
// Save and restore the state of the Parser and lexer.
2019-09-06 19:55:58 +03:00
// Note: ROOT::Internal::ParsingStateRAII also save and restore the state of
// Sema, including pending instantiation for example. It is not clear
// whether we need to do so here too or whether we need to also see the
// "on-going" semantic information ... For now, we leave Sema untouched.
2019-09-06 19:02:07 +03:00
clang : : Preprocessor : : CleanupAndRestoreCacheRAII fCleanupRAII ;
clang : : Parser : : ParserCurTokRestoreRAII fSavedCurToken ;
2018-08-08 19:46:34 +03:00
ParserStateRAII ResetParserState ;
Also capture SFINAE error counts (ROOT-10754, ROOT-10777):
When doing lookup on templates, instantiation can fail.
This can be triggered during template instantiation somewhere
in clang, autoloading, cling-lookup - and SFINAE errors that
occur in cling-lookup must not bubble up to clang, or else
clang will think that there was a problem (where there was
none - just e.g. ROOT trying to autoload a bogus template).
In this concrete case, a template specialized with a lambda
was not found by clang, was tried to be autoloaded, TMetaUtils
produced a broken normalized type name, lookup on the broken
type name failed with a SFINAE error - and that ended up being
swallowed by a clang SFINAETrap by the topmost lookup.
Instead, keep SFINAE errors to ourselves.
This is an improved version of 40673e583fceda8b362a0902c6aba371ddd0cfd8
which lowers the SFINAE-reset to Lookup, as AutoParse can still
see partial template specialization scopes. It fixes ROOT-10777.
2020-05-18 11:35:58 +03:00
clang : : Sema : : SFINAETrap fSFINAETrap ;
2018-08-08 19:46:34 +03:00
void prepareForParsing ( llvm : : StringRef code , llvm : : StringRef bufferName ,
LookupHelper : : DiagSetting diagOnOff ) ;
public :
StartParsingRAII ( LookupHelper & LH , llvm : : StringRef code ,
llvm : : StringRef bufferName ,
LookupHelper : : DiagSetting diagOnOff )
2019-09-06 19:55:58 +03:00
: m_LH ( LH ) , SaveIsRecursivelyRunning ( LH . IsRecursivelyRunning ) ,
2020-05-18 11:34:47 +03:00
fCleanupRAII ( LH . m_Parser - > getPreprocessor ( ) ) ,
fSavedCurToken ( * LH . m_Parser ) ,
ResetParserState ( * LH . m_Parser ,
Also capture SFINAE error counts (ROOT-10754, ROOT-10777):
When doing lookup on templates, instantiation can fail.
This can be triggered during template instantiation somewhere
in clang, autoloading, cling-lookup - and SFINAE errors that
occur in cling-lookup must not bubble up to clang, or else
clang will think that there was a problem (where there was
none - just e.g. ROOT trying to autoload a bogus template).
In this concrete case, a template specialized with a lambda
was not found by clang, was tried to be autoloaded, TMetaUtils
produced a broken normalized type name, lookup on the broken
type name failed with a SFINAE error - and that ended up being
swallowed by a clang SFINAETrap by the topmost lookup.
Instead, keep SFINAE errors to ourselves.
This is an improved version of 40673e583fceda8b362a0902c6aba371ddd0cfd8
which lowers the SFINAE-reset to Lookup, as AutoParse can still
see partial template specialization scopes. It fixes ROOT-10777.
2020-05-18 11:35:58 +03:00
! LH . IsRecursivelyRunning /*skipToEOF*/ ) ,
fSFINAETrap ( m_LH . m_Parser - > getActions ( ) ) {
2019-05-03 18:38:18 +03:00
LH . IsRecursivelyRunning = true ;
prepareForParsing ( code , bufferName , diagOnOff ) ;
}
2012-11-26 17:45:32 +04:00
2018-08-08 19:46:34 +03:00
~ StartParsingRAII ( ) { pop ( ) ; }
void pop ( ) const { }
} ;
2014-09-15 14:16:36 +04:00
2018-08-08 19:46:34 +03:00
void StartParsingRAII : : prepareForParsing ( llvm : : StringRef code ,
llvm : : StringRef bufferName ,
LookupHelper : : DiagSetting diagOnOff ) {
+ + m_LH . m_TotalParseRequests ;
2020-05-18 11:34:47 +03:00
Parser & P = * m_LH . m_Parser ;
2014-09-12 06:54:19 +04:00
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 ) ;
2015-09-09 08:08:52 +03:00
//
// Tell Sema we are not in the process of doing an instantiation.
Also capture SFINAE error counts (ROOT-10754, ROOT-10777):
When doing lookup on templates, instantiation can fail.
This can be triggered during template instantiation somewhere
in clang, autoloading, cling-lookup - and SFINAE errors that
occur in cling-lookup must not bubble up to clang, or else
clang will think that there was a problem (where there was
none - just e.g. ROOT trying to autoload a bogus template).
In this concrete case, a template specialized with a lambda
was not found by clang, was tried to be autoloaded, TMetaUtils
produced a broken normalized type name, lookup on the broken
type name failed with a SFINAE error - and that ended up being
swallowed by a clang SFINAETrap by the topmost lookup.
Instead, keep SFINAE errors to ourselves.
This is an improved version of 40673e583fceda8b362a0902c6aba371ddd0cfd8
which lowers the SFINAE-reset to Lookup, as AutoParse can still
see partial template specialization scopes. It fixes ROOT-10777.
2020-05-18 11:35:58 +03:00
// fSFINAETrap will reset any SFINAE error count of a SFINAE context from "above".
// fSFINAETrap will reset this value to the previous one; the line below is overwriting
// the value set by fSFINAETrap.
2015-09-09 08:08:52 +03:00
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 ;
2019-05-03 18:38:18 +03:00
assert ( ! code . empty ( ) & &
" prepareForParsing should only be called when need " ) ;
2014-09-12 13:20:29 +04:00
2018-08-08 19:46:34 +03:00
// Create a fake file to parse the type name.
FileID FID ;
llvm : : hash_code hashedCode = llvm : : hash_value ( code ) ;
auto cacheItr = m_LH . m_ParseBufferCache . find ( hashedCode ) ;
SourceLocation NewLoc ;
SourceManager & SM = S . getSourceManager ( ) ;
bool CacheIsValid = false ;
if ( cacheItr ! = m_LH . m_ParseBufferCache . end ( ) ) {
SourceLocation FileStartLoc =
SourceLocation : : getFromRawEncoding ( cacheItr - > second ) ;
FID = SM . getFileID ( FileStartLoc ) ;
bool Invalid = true ;
2022-02-08 01:28:09 +03:00
llvm : : StringRef FIDContents = SM . getBufferData ( FID , & Invalid ) ;
2018-08-08 19:46:34 +03:00
// A FileID is a (cached via ContentCache) SourceManager view of a
// FileManager::FileEntry (which is a wrapper on the file system file).
// In a subtle cases, code unloading can remove the cached region.
// However we are safe because it will empty the ContentCache and force
// the FileEntry to be re-read. It will keep the FileID intact and valid
// by design. When we reprocess the same (but modified) file it will get
// a new FileID. Then the Invalid flag will be false but the underlying
// buffer content will be empty. It will not compare equal to the lookup
// string and we will avoid using (a potentially broken) cache.
assert ( ! Invalid ) ;
// Compare the contents of the cached buffer and the string we should
// process. If there are hash collisions this assert should trigger
// making it easier to debug.
CacheIsValid = FIDContents . equals ( llvm : : StringRef ( code . str ( ) + " \n " ) ) ;
assert ( CacheIsValid & & " Hash collision! " ) ;
if ( CacheIsValid ) {
// We have already included this file once. Reuse the include loc.
NewLoc = SM . getIncludeLoc ( FID ) ;
// The Preprocessor will try to set the NumCreatedFIDs but we are
// reparsing and this value was already set. Force reset it to avoid
// triggering an assertion in the setNumCreatedFIDsForFileID routine.
SM . setNumCreatedFIDsForFileID ( FID , 0 , /*force*/ true ) ;
+ + m_LH . m_CacheHits ;
}
}
if ( ! CacheIsValid ) {
std : : unique_ptr < llvm : : MemoryBuffer > SB
= llvm : : MemoryBuffer : : getMemBufferCopy ( code . str ( ) + " \n " ,
bufferName . str ( ) ) ;
NewLoc = m_LH . m_Interpreter - > getNextAvailableLoc ( ) ;
FID = SM . createFileID ( std : : move ( SB ) , SrcMgr : : C_User , /*LoadedID*/ 0 ,
/*LoadedOffset*/ 0 , NewLoc ) ;
SourceLocation FileStartLoc = SM . getLocForStartOfFile ( FID ) ;
m_LH . m_ParseBufferCache [ hashedCode ] = FileStartLoc . getRawEncoding ( ) ;
}
2014-09-12 13:20:29 +04:00
//
// 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
}
2018-08-08 19:46:34 +03:00
// pin *tor here so that we can have clang::Parser defined and be able to call
// the dtor on the OwningPtr
LookupHelper : : LookupHelper ( clang : : Parser * P , Interpreter * interp )
: m_Parser ( P ) , m_Interpreter ( interp ) {
}
LookupHelper : : ~ LookupHelper ( ) { }
static
DeclContext * getCompleteContext ( const Decl * scopeDecl ,
ASTContext & Context , Sema & S ) ;
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 ) ;
ASTContext & Context = S . getASTContext ( ) ;
2016-04-28 18:31:32 +03:00
DeclContext * complete = getCompleteContext ( tobeCompleted , Context , S ) ;
2014-09-15 14:16:36 +04:00
PP . getDiagnostics ( ) . setSuppressAllDiagnostics ( OldSuppressAllDiagnostics ) ;
2016-09-12 22:34:29 +03:00
if ( ! complete )
return 0 ;
if ( const TagDecl * result = dyn_cast < TagDecl > ( complete ) )
2014-09-15 14:16:36 +04:00
return result - > getDefinition ( ) ;
2016-09-12 22:34:29 +03:00
return 0 ;
2014-09-15 14:16:36 +04:00
}
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 ) ;
2017-04-07 21:13:49 +03:00
if ( next = = ( void * ) - 1 ) {
// Ambiguous result, we need to go through the long path
return false ;
} else if ( next & & next ! = ( void * ) - 1 ) {
2015-09-26 12:59:59 +03:00
// 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,
2017-04-07 21:13:49 +03:00
// so 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 ) ;
2017-04-07 21:13:49 +03:00
// If there is an ambiguity, we need to go the long route.
if ( next = = ( void * ) - 1 ) return false ;
2015-09-26 12:59:59 +03:00
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 ;
2024-02-02 13:11:47 +03:00
if ( typeName . starts_with ( " signed " ) ) {
2015-09-28 20:05:27 +03:00
issigned = true ;
typeName = StringRef ( typeName . data ( ) + 7 , typeName . size ( ) - 7 ) ;
}
2024-02-02 13:11:47 +03:00
if ( ! issigned & & typeName . starts_with ( " unsigned " ) ) {
2015-09-28 20:05:27 +03:00
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 " ) ) {
2022-09-19 19:40:45 +03:00
if ( isunsigned ) return Context . UnsignedLongLongTy ;
return Context . LongLongTy ;
2015-09-28 20:05:27 +03:00
}
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 ;
2024-02-02 13:11:47 +03:00
if ( quickTypeName . starts_with ( " const " ) ) {
2015-09-29 01:47:15 +03:00
// Use this syntax to avoid the redudant tests in substr.
quickTypeName = StringRef ( quickTypeName . data ( ) + 6 ,
quickTypeName . size ( ) - 6 ) ;
innerConst = true ;
}
2016-09-06 02:34:40 +03:00
enum PointerType { kPointerType , kLRefType , kRRefType , } ;
2024-02-02 13:11:47 +03:00
if ( quickTypeName . ends_with ( " const " ) ) {
2015-09-29 01:47:15 +03:00
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 ) ;
}
}
2016-09-06 02:34:40 +03:00
std : : vector < PointerType > ptrref ;
2015-09-29 01:47:15 +03:00
for ( auto c = quickTypeName . end ( ) - 1 ; c ! = quickTypeName . begin ( ) ; - - c ) {
2016-09-06 02:34:40 +03:00
if ( * c = = ' * ' ) ptrref . push_back ( kPointerType ) ;
2015-09-29 01:47:15 +03:00
else if ( * c = = ' & ' ) {
if ( * ( c - 1 ) = = ' & ' ) {
- - c ;
2016-09-06 02:34:40 +03:00
ptrref . push_back ( kRRefType ) ;
2015-09-29 01:47:15 +03:00
} else
2016-09-06 02:34:40 +03:00
ptrref . push_back ( kLRefType ) ;
2015-09-29 01:47:15 +03:00
}
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 ) {
2016-09-06 02:34:40 +03:00
case kPointerType :
2015-09-29 01:47:15 +03:00
quickFind = Context . getPointerType ( quickFind ) ;
break ;
2016-09-06 02:34:40 +03:00
case kLRefType :
2015-09-29 01:47:15 +03:00
quickFind = Context . getLValueReferenceType ( quickFind ) ;
break ;
2016-09-06 02:34:40 +03:00
case kRRefType :
quickFind = Context . getRValueReferenceType ( quickFind ) ;
break ;
2015-09-29 01:47:15 +03:00
}
}
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 ;
2018-08-08 19:46:34 +03:00
StartParsingRAII ParseStarted ( const_cast < LookupHelper & > ( * this ) ,
typeName ,
llvm : : StringRef ( " lookup.type.by.name.file " ) ,
diagOnOff ) ;
2015-09-28 20:05:27 +03:00
//
// Try parsing the type name.
//
clang : : ParsedAttributes Attrs ( P . getAttrFactory ( ) ) ;
2020-03-17 17:38:09 +03:00
// FIXME: All arguments to ParseTypeName are the default arguments. Remove.
2022-02-08 01:35:39 +03:00
TypeResult Res ( P . ParseTypeName ( 0 , DeclaratorContext : : TypeName ,
2020-03-17 17:38:09 +03:00
clang : : AS_none , 0 , & Attrs ) ) ;
2015-09-28 20:05:27 +03:00
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 ,
2021-05-27 15:28:21 +03:00
const Type * * resultType /* = nullptr */ ,
2012-12-09 05:51:25 +04:00
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
2017-04-10 19:52:41 +03: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.
// Also quickFindDecl could trigger deserialization of decls.
Interpreter : : PushTransactionRAII pushedT ( m_Interpreter ) ;
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
}
}
}
}
2018-08-08 19:46:34 +03:00
StartParsingRAII ParseStarted ( const_cast < LookupHelper & > ( * this ) ,
className . str ( ) + " :: " ,
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.
2016-11-08 23:36:41 +03:00
DeclContext * ctxt = TD ;
if ( ! S . RequireCompleteDeclContext ( SS , ctxt ) ) {
2012-12-09 05:51:25 +04:00
// 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
2016-06-26 18:26:35 +03:00
UnloadDecl ( & S , 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.
2020-12-17 20:41:51 +03:00
// Need to unload it if this decl is a definition.
// But do not unload pre-existing fwd decls. Note that this might have failed
// because several other Decls failed to instantiate, leaving several Decls
// in invalid state. We should be unloading all of them, i.e. inload the
// current (possibly nested) transaction.
auto * T = const_cast < Transaction * > ( m_Interpreter - > getCurrentTransaction ( ) ) ;
2021-04-01 13:24:13 +03:00
// Must not unload the Transaction, which might delete
// it: the RAII above still points to it! Instead, just
// mark it as "erroneous" which causes the RAII to
// unload it in due time.
T - > setIssuedDiags ( Transaction : : kErrors ) ;
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 ;
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.
//
2017-05-18 16:16:30 +03:00
if ( P . TryAnnotateTypeOrScopeToken ( ) ) {
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 ) {
2022-02-08 01:37:33 +03:00
TypeResult 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 )
2022-02-08 01:37:33 +03:00
if ( ! T . get ( ) . get ( ) . isNull ( ) ) {
2013-02-19 13:30:00 +04:00
TypeSourceInfo * TSI = 0 ;
2022-02-08 01:37:33 +03:00
clang : : QualType QT =
clang : : Sema : : GetTypeFromParser ( T . get ( ) , & TSI ) ;
2013-02-19 13:30:00 +04:00
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 ( ) ;
2018-08-08 19:46:34 +03:00
StartParsingRAII ParseStarted ( const_cast < LookupHelper & > ( * this ) ,
Name . str ( ) ,
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.
//
2017-05-18 16:16:30 +03:00
if ( P . TryAnnotateTypeOrScopeToken ( ) ) {
2012-12-01 11:22:56 +04:00
// 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 ( ) ) {
2017-10-18 18:26:01 +03:00
P . ConsumeAnyToken ( ) ;
2012-12-01 11:22:56 +04:00
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
} ;
}
2017-06-26 18:12:12 +03:00
} else if ( P . getCurToken ( ) . is ( clang : : tok : : annot_typename ) ) {
2017-06-27 11:18:02 +03:00
// A deduced template?
2017-06-26 18:12:12 +03:00
// P.getTypeAnnotation() takes a non-const Token& until clang r306291.
//auto ParsedTy = P.getTypeAnnotation(P.getCurToken());
auto ParsedTy
= ParsedType : : getFromOpaquePtr ( P . getCurToken ( ) . getAnnotationValue ( ) ) ;
if ( ParsedTy ) {
QualType QT = ParsedTy . get ( ) ;
2017-06-27 11:18:02 +03:00
const Type * TyPtr = QT . getTypePtr ( ) ;
if ( const auto * LocInfoTy = dyn_cast < LocInfoType > ( TyPtr ) )
TyPtr = LocInfoTy - > getType ( ) . getTypePtr ( ) ;
TyPtr = TyPtr - > getUnqualifiedDesugaredType ( ) ;
2017-06-26 18:12:12 +03:00
if ( const auto * DTST
2017-06-27 11:18:02 +03:00
= dyn_cast < DeducedTemplateSpecializationType > ( TyPtr ) ) {
2017-06-26 18:12:12 +03:00
if ( auto TD = DTST - > getTemplateName ( ) . getAsTemplateDecl ( ) ) {
if ( auto CTD = dyn_cast < ClassTemplateDecl > ( TD ) )
return CTD ;
}
}
}
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 ,
2016-04-28 18:31:32 +03:00
const Decl * scopeDecl ,
ASTContext & Context , Sema & S ) {
//
// Some validity checks on the passed decl.
//
DeclContext * foundDC = dyn_cast < DeclContext > ( const_cast < Decl * > ( scopeDecl ) ) ;
if ( foundDC - > isDependentContext ( ) ) {
// Passed decl is a template, we cannot use it.
return 0 ;
}
if ( scopeDecl - > isInvalidDecl ( ) ) {
// if the decl is invalid try to clean up
2016-06-26 18:26:35 +03:00
UnloadDecl ( & S , const_cast < Decl * > ( scopeDecl ) ) ;
2016-04-28 18:31:32 +03:00
return 0 ;
}
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 ) ) ;
2016-04-28 18:31:32 +03:00
SS . MakeTrivial ( Context , classNNS , scopeDecl - > getSourceRange ( ) ) ;
return foundDC ;
2012-09-05 13:37:39 +04:00
}
else if ( const RecordDecl * RD = dyn_cast < RecordDecl > ( scopeDecl ) ) {
const Type * T = Context . getRecordType ( RD ) . getTypePtr ( ) ;
classNNS = NestedNameSpecifier : : Create ( Context , 0 , false , T ) ;
2016-04-28 18:31:32 +03:00
// We pass a 'random' but valid source range.
SS . MakeTrivial ( Context , classNNS , scopeDecl - > getSourceRange ( ) ) ;
if ( S . RequireCompleteDeclContext ( SS , foundDC ) ) {
// Forward decl or instantiation failure, we cannot use it.
return 0 ;
}
return foundDC ;
2012-09-05 13:37:39 +04:00
}
else if ( llvm : : isa < TranslationUnitDecl > ( scopeDecl ) ) {
2016-04-28 18:31:32 +03:00
// We pass a 'random' but valid source range.
SS . MakeGlobal ( Context , scopeDecl - > getLocation ( ) ) ;
return foundDC ;
2012-09-05 13:37:39 +04:00
}
2016-04-28 18:31:32 +03:00
// Not a namespace or class, we cannot use it.
return 0 ;
}
static
DeclContext * getCompleteContext ( const Decl * scopeDecl ,
ASTContext & Context , Sema & S ) {
2013-08-03 09:48:28 +04:00
//
// Some validity checks on the passed decl.
//
2016-04-28 18:31:32 +03:00
DeclContext * foundDC = dyn_cast < DeclContext > ( const_cast < Decl * > ( scopeDecl ) ) ;
2013-08-03 09:48:28 +04:00
if ( foundDC - > isDependentContext ( ) ) {
// Passed decl is a template, 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
2016-06-26 18:26:35 +03:00
UnloadDecl ( & S , const_cast < Decl * > ( scopeDecl ) ) ;
2014-02-13 19:00:30 +04:00
return 0 ;
2014-02-27 20:11:08 +04:00
}
2016-04-28 18:31:32 +03:00
//
// Convert the passed decl into a nested name specifier,
// a scope spec, and a decl context.
//
2016-04-29 21:20:49 +03:00
if ( isa < NamespaceDecl > ( scopeDecl ) ) {
2016-04-28 18:31:32 +03:00
return foundDC ;
}
else if ( const RecordDecl * RD = dyn_cast < RecordDecl > ( scopeDecl ) ) {
if ( RD - > getDefinition ( ) ) {
// We are already complete, we are done.
return foundDC ;
} else {
//const Type* T = Context.getRecordType(RD).getTypePtr();
const Type * T = Context . getTypeDeclType ( RD ) . getTypePtr ( ) ;
2019-01-10 12:17:07 +03:00
NestedNameSpecifier * classNNS = NestedNameSpecifier : : Create ( Context , 0 , false , T ) ;
2016-04-28 18:31:32 +03:00
// We pass a 'random' but valid source range.
CXXScopeSpec SS ;
SS . MakeTrivial ( Context , classNNS , scopeDecl - > getSourceRange ( ) ) ;
if ( S . RequireCompleteDeclContext ( SS , foundDC ) ) {
// Forward decl or instantiation failure, we cannot use it.
return 0 ;
}
}
}
else if ( llvm : : isa < TranslationUnitDecl > ( scopeDecl ) ) {
return dyn_cast < DeclContext > ( const_cast < Decl * > ( scopeDecl ) ) ;
}
else {
// Not a namespace or class, we cannot use it.
return 0 ;
}
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 ,
2017-09-04 18:30:06 +03:00
ASTContext & Context , Parser & P , Sema & S ,
LookupHelper : : DiagSetting diagOnOff ) {
2013-08-03 09:48:28 +04:00
//
// 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 ) ;
}
2021-04-20 13:28:09 +03:00
//
// Tell the diagnostic engine to ignore all diagnostics.
//
bool OldSuppressAllDiagnostics
= S . getDiagnostics ( ) . getSuppressAllDiagnostics ( ) ;
S . getDiagnostics ( ) . setSuppressAllDiagnostics (
diagOnOff = = LookupHelper : : NoDiagnostics ) ;
struct ResetDiagSuppression {
bool _Old ;
Sema & _S ;
ResetDiagSuppression ( Sema & S , bool Old ) : _Old ( Old ) , _S ( S ) { }
~ ResetDiagSuppression ( ) {
2022-02-08 11:27:01 +03:00
_S . getDiagnostics ( ) . setSuppressAllDiagnostics ( _Old ) ;
2021-04-20 13:28:09 +03:00
}
} DiagSuppressionRAII ( S , OldSuppressAllDiagnostics ) ;
2013-08-03 09:48:28 +04:00
//
// 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 ,
2023-12-12 19:04:04 +03:00
llvm : : ArrayRef < Expr * > ( GivenArgs . data ( ) ,
GivenArgs . size ( ) ) ,
Candidates ) ;
2013-08-03 09:48:28 +04:00
}
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 ( ) ,
2023-12-12 19:04:04 +03:00
llvm : : ArrayRef < Expr * > ( GivenArgs . data ( ) ,
GivenArgs . size ( ) ) ,
2013-08-03 09:48:28 +04:00
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.
2023-12-12 19:04:04 +03:00
S . AddMethodTemplateCandidate (
FTD , I . getPair ( ) , cast < CXXRecordDecl > ( FTD - > getDeclContext ( ) ) ,
const_cast < TemplateArgumentListInfo * > ( FuncTemplateArgs ) ,
/*ObjectType=*/ ClassType ,
/*ObjectClassification=*/ ObjExprClassification ,
llvm : : ArrayRef < Expr * > ( GivenArgs . data ( ) , GivenArgs . size ( ) ) ,
Candidates ) ;
2013-08-03 09:48:28 +04:00
}
else {
2023-12-12 19:04:04 +03:00
S . AddTemplateOverloadCandidate (
FTD , I . getPair ( ) ,
const_cast < TemplateArgumentListInfo * > ( FuncTemplateArgs ) ,
llvm : : ArrayRef < Expr * > ( GivenArgs . data ( ) , GivenArgs . size ( ) ) ,
Candidates , /*SuppressUserConversions=*/ false ) ;
2013-08-03 09:48:28 +04:00
}
}
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 ( ) ;
2017-09-04 18:30:06 +03:00
if ( TheDecl - > isTemplateInstantiation ( ) & & ! TheDecl - > isDefined ( ) ) {
2014-02-13 19:00:30 +04:00
S . InstantiateFunctionDefinition ( SourceLocation ( ) , TheDecl ,
true /*recursive instantiation*/ ) ;
2017-09-04 18:30:06 +03:00
}
2014-02-27 20:11:08 +04:00
if ( TheDecl - > isInvalidDecl ( ) ) {
// if the decl is invalid try to clean up
2016-06-26 18:26:35 +03:00
UnloadDecl ( & S , 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 ,
2017-09-04 18:30:06 +03:00
ASTContext & Context , Parser & P , Sema & S ,
LookupHelper : : DiagSetting diagOnOff ) {
2013-08-12 22:30:55 +04:00
//
// Our return value.
//
const FunctionDecl * TheDecl = overloadFunctionSelector ( foundDC , objectIsConst ,
GivenArgs , Result ,
FuncNameInfo ,
FuncTemplateArgs ,
2017-09-04 18:30:06 +03:00
Context , P , S ,
diagOnOff ) ;
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 ) ) {
2020-03-17 17:42:42 +03:00
if ( md - > getMethodQualifiers ( ) . hasConst ( ) ) {
2013-08-12 22:30:55 +04:00
if ( ! objectIsConst ) {
TheDecl = 0 ;
}
2020-03-17 17:42:42 +03:00
} else { // FIXME: The else should be attached to the if hasConst stmt
2013-08-12 22:30:55 +04:00
if ( objectIsConst ) {
TheDecl = 0 ;
}
}
}
}
}
return TheDecl ;
}
2016-04-28 18:31:32 +03:00
static bool ParseWithShortcuts ( DeclContext * foundDC , ASTContext & Context ,
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 ,
2019-09-06 19:02:07 +03:00
LookupHelper : : DiagSetting diagOnOff ,
ParserStateRAII & ResetParserState ) {
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.
2019-09-06 19:02:07 +03:00
ResetParserState . SetSkipToEOF ( true ) ;
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 ;
2016-04-28 18:31:32 +03:00
CXXScopeSpec SS ;
{
Decl * decl = llvm : : dyn_cast < Decl > ( foundDC ) ;
getContextAndSpec ( SS , decl , Context , S ) ;
}
2022-02-08 11:27:34 +03:00
if ( P . ParseUnqualifiedId ( SS , ParsedType ( ) ,
/*ObjectHadErrors=*/ false ,
/*EnteringContext*/ false ,
2013-08-21 06:27:35 +04:00
/*AllowDestructorName*/ true ,
/*AllowConstructorName*/ true ,
2017-05-18 16:16:30 +03:00
/*AllowDeductionGuide*/ false ,
2022-02-08 11:27:34 +03:00
& TemplateKWLoc ,
2013-08-21 06:27:35 +04:00
FuncId ) ) {
// Failed parse, cleanup.
return false ;
}
return true ;
}
2013-08-03 09:48:28 +04:00
template < typename T >
2016-04-28 18:31:32 +03:00
T findFunction ( DeclContext * foundDC ,
2013-08-03 09:48:28 +04:00
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 ,
2017-09-04 18:30:06 +03:00
ASTContext & Context , Parser & P , Sema & S ,
LookupHelper : : DiagSetting diagOnOff ) ,
2014-02-19 11:31:45 +04:00
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 ;
2019-09-06 19:02:07 +03:00
ParserStateRAII ResetParserState ( P , false /*skipToEOF*/ ) ;
2019-09-06 19:55:58 +03:00
if ( ! ParseWithShortcuts ( foundDC , Context , funcName , Interp , FuncId ,
diagOnOff , ResetParserState ) ) {
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 ( ) ;
2019-01-09 13:16:33 +03:00
bool LookupSuccess = true ;
if ( FuncTemplateArgsBuffer . size ( ) ) {
// It's a template. Calculate the NNS and do qualified template lookup.
NestedNameSpecifier * scopeNNS = nullptr ;
SourceRange scopeSrcRange ;
if ( isa < TranslationUnitDecl > ( foundDC ) ) {
scopeNNS = NestedNameSpecifier : : GlobalSpecifier ( Context ) ;
} else if ( const auto * foundNS = dyn_cast < NamespaceDecl > ( foundDC ) ) {
scopeNNS = NestedNameSpecifier : : Create ( Context , /*NNSPrefix*/ nullptr ,
foundNS ) ;
scopeSrcRange = foundNS - > getSourceRange ( ) ;
} else if ( const auto * foundRD = dyn_cast < RecordDecl > ( foundDC ) ) {
// a type
const Type * foundTy = Context . getTypeDeclType ( foundRD ) . getTypePtr ( ) ;
scopeNNS = NestedNameSpecifier : : Create ( Context , /*NNSPrefix*/ nullptr ,
/*Template*/ false , foundTy ) ;
scopeSrcRange = foundRD - > getSourceRange ( ) ;
}
CXXScopeSpec SS ;
if ( scopeNNS )
SS . MakeTrivial ( Context , scopeNNS , scopeSrcRange ) ;
bool MemberOfUnknownSpecialization ;
S . LookupTemplateName ( Result , P . getCurScope ( ) , SS , QualType ( ) ,
/*EnteringContext*/ false ,
MemberOfUnknownSpecialization ) ;
// "Translation" of the TemplateDecl to the specialization is done
// in findAnyFunctionSelector() given the ExplicitTemplateArgs.
if ( Result . empty ( ) )
LookupSuccess = false ;
} else {
LookupSuccess = S . LookupQualifiedName ( Result , foundDC ) ;
}
if ( ! LookupSuccess ) {
2013-08-03 09:48:28 +04:00
// 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 ,
2017-09-04 18:30:06 +03:00
Context , P , S , diagOnOff ) ;
2013-08-03 09:48:28 +04:00
}
2014-09-12 15:58:37 +04:00
template < typename DigestArgsInput , typename returnType >
returnType execFindFunction ( Parser & P ,
Interpreter * Interp ,
2018-08-08 19:46:34 +03:00
LookupHelper & LH ,
2014-09-12 15:58:37 +04:00
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 ,
2017-09-04 18:30:06 +03:00
ASTContext & Context , Parser & P , Sema & S ,
LookupHelper : : DiagSetting diagOnOff ) ,
2014-09-12 15:58:37 +04:00
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.
//
2016-04-28 18:31:32 +03:00
DeclContext * foundDC = getCompleteContext ( scopeDecl , Context , S ) ;
2014-09-12 05:54:36 +04:00
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 ;
2018-08-08 19:46:34 +03:00
if ( ! inputEval ( GivenArgs , funcArgs , diagOnOff , P , Interp , LH ) ) return 0 ;
2014-09-12 05:54:36 +04:00
2018-05-30 12:15:15 +03:00
Interpreter : : PushTransactionRAII pushedT ( Interp ) ;
2016-04-28 18:31:32 +03:00
return findFunction ( foundDC ,
2014-09-12 05:54:36 +04:00
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 */ ,
2018-08-08 19:46:34 +03:00
Parser & /* P */ , const Interpreter * /* Interp */ ,
const LookupHelper & /* LH */ )
2014-09-12 15:58:37 +04:00
{
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 */ ,
2018-08-08 19:46:34 +03:00
Parser & /* P */ , const Interpreter * /* Interp */ ,
LookupHelper & /* LH */ ) {
2014-09-12 15:58:37 +04:00
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.
//
2019-04-09 10:01:17 +03:00
assert ( ! ExprMemory . size ( ) & & " Size must be 0 " ) ;
ExprMemory . resize ( GivenTypes . size ( ) + 1 ) ;
for ( size_t i = 0 , e = GivenTypes . size ( ) ; i < e ; + + i ) {
const clang : : QualType QT = GivenTypes [ i ] . getCanonicalType ( ) ;
2014-09-12 15:58:37 +04:00
{
2022-02-08 01:00:28 +03:00
ExprValueKind VK = VK_PRValue ;
2014-09-12 15:58:37 +04:00
if ( QT - > getAs < LValueReferenceType > ( ) ) {
VK = VK_LValue ;
}
clang : : QualType NonRefQT ( QT . getNonReferenceType ( ) ) ;
2019-04-09 10:01:17 +03:00
Expr * val = new ( & ExprMemory [ i ] ) OpaqueValueExpr ( SourceLocation ( ) ,
NonRefQT , VK ) ;
2014-09-12 15:58:37 +04:00
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 ,
2018-08-08 19:46:34 +03:00
Parser & P , const Interpreter * Interp ,
LookupHelper & LH ) {
2014-09-12 15:58:37 +04:00
if ( funcProto . empty ( ) ) return true ;
2018-08-08 19:46:34 +03:00
else return Parse ( GivenArgs , funcProto , diagOnOff , P , Interp , LH ) ;
2014-09-12 15:58:37 +04:00
}
bool Parse ( llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
const ArgsInput & funcProto ,
LookupHelper : : DiagSetting diagOnOff ,
2018-08-08 19:46:34 +03:00
Parser & P , const Interpreter * Interp ,
LookupHelper & LH ) {
2014-09-12 15:58:37 +04:00
//
// Parse the prototype now.
//
2018-08-08 19:46:34 +03:00
StartParsingRAII ParseStarted ( LH , funcProto ,
llvm : : StringRef ( " func.prototype.file " ) ,
diagOnOff ) ;
2014-09-12 15:58:37 +04:00
2023-07-03 12:46:22 +03:00
// ParseTypeName might trigger deserialization.
Interpreter : : PushTransactionRAII TforDeser ( Interp ) ;
2014-09-12 15:58:37 +04:00
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 ( ) ;
{
2022-02-08 01:00:28 +03:00
ExprValueKind VK = VK_PRValue ;
2014-09-12 15:58:37 +04:00
if ( QT - > getAs < LValueReferenceType > ( ) ) {
VK = VK_LValue ;
}
2019-04-09 10:01:17 +03:00
// FIXME: This is potentially dangerous because if the capacity exceeds
// the reserved capacity of ExprMemory, it will reallocate and cause
// memory corruption on the OpaqueValueExpr. See ROOT-7749.
2014-09-12 15:58:37 +04:00
clang : : QualType NonRefQT ( QT . getNonReferenceType ( ) ) ;
ExprMemory . resize ( + + nargs ) ;
2020-03-15 15:30:01 +03:00
new ( & ExprMemory [ nargs - 1 ] ) OpaqueValueExpr ( TSI - > getTypeLoc ( ) . getBeginLoc ( ) ,
2014-09-12 15:58:37 +04:00
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 & ,
2017-09-04 18:30:06 +03:00
Sema & S ,
LookupHelper : : DiagSetting diagOnOff ) {
2013-11-13 17:51:48 +04:00
//
// 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 ,
2018-08-08 19:46:34 +03:00
const_cast < LookupHelper & > ( * this ) ,
2014-09-12 15:58:37 +04:00
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 ,
2017-09-04 18:30:06 +03:00
ASTContext & , Parser & , Sema & S ,
LookupHelper : : DiagSetting diagOnOff ) {
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 ;
2016-09-12 22:41:15 +03:00
Sema : : TemplateDeductionResult TemplDedResult
2013-11-04 09:22:41 +04:00
= S . DeduceTemplateArguments ( MethodTmpl ,
const_cast < TemplateArgumentListInfo * > ( ExplicitTemplateArgs ) ,
fdecl ,
Info ) ;
2016-09-12 22:41:15 +03:00
if ( TemplDedResult ! = Sema : : TDK_Success ) {
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
2016-06-26 18:26:35 +03:00
UnloadDecl ( & S , 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 ,
2018-08-08 19:46:34 +03:00
const_cast < LookupHelper & > ( * this ) ,
2014-09-12 15:58:37 +04:00
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 ,
2018-08-08 19:46:34 +03:00
const_cast < LookupHelper & > ( * this ) ,
2014-09-12 15:58:37 +04:00
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 ,
2018-08-08 19:46:34 +03:00
const_cast < LookupHelper & > ( * this ) ,
2014-09-12 15:58:37 +04:00
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 ,
2018-08-08 19:46:34 +03:00
const_cast < LookupHelper & > ( * this ) ,
2014-09-12 15:58:37 +04:00
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 ,
2018-08-08 19:46:34 +03:00
const_cast < LookupHelper & > ( * this ) ,
2014-09-12 15:58:37 +04:00
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 ,
2018-08-08 19:46:34 +03:00
Parser & P , const Interpreter * Interp ,
LookupHelper & LH ) {
2014-08-04 06:05:42 +04:00
2014-09-12 15:58:37 +04:00
if ( funcArgs . empty ( ) ) return true ;
2018-08-08 19:46:34 +03:00
else return Parse ( GivenArgs , funcArgs , diagOnOff , P , Interp , LH ) ;
2014-09-12 15:58:37 +04:00
}
bool Parse ( llvm : : SmallVectorImpl < Expr * > & GivenArgs ,
2018-08-08 19:46:34 +03:00
llvm : : StringRef funcArgs ,
LookupHelper : : DiagSetting diagOnOff ,
Parser & P , const Interpreter * Interp ,
LookupHelper & LH ) {
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 ) ;
2018-08-08 19:46:34 +03:00
StartParsingRAII ParseStarted ( LH , 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 + = ' , ' ;
}
2016-12-14 23:32:18 +03:00
stdstrstream tmp ;
2014-09-12 15:58:37 +04:00
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 ,
2018-08-08 19:46:34 +03:00
const_cast < LookupHelper & > ( * this ) ,
2014-09-12 15:58:37 +04:00
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 ;
2018-08-08 19:46:34 +03:00
StartParsingRAII ParseStarted ( const_cast < LookupHelper & > ( * this ) ,
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 * ,
2017-09-04 18:30:06 +03:00
ASTContext & , Parser & , Sema & ,
LookupHelper : : DiagSetting /*diagOnOff*/ ) {
2013-08-03 09:48:28 +04:00
//
// 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 ,
2018-08-08 19:46:34 +03:00
const_cast < LookupHelper & > ( * this ) ,
2014-09-12 15:58:37 +04:00
scopeDecl ,
funcName , " " ,
false /* objectIsConst */ ,
hasFunctionSelector ,
diagOnOff ) ;
2013-04-05 17:50:01 +04:00
}
2017-05-08 12:26:17 +03:00
2017-06-04 07:18:01 +03:00
static const clang : : Type * getType ( LookupHelper * LH , llvm : : StringRef Type ) {
QualType Qt = LH - > findType ( Type , LookupHelper : : WithDiagnostics ) ;
assert ( ! Qt . isNull ( ) & & " Type should exist " ) ;
return Qt . getTypePtr ( ) ;
}
LookupHelper : : StringType
LookupHelper : : getStringType ( const clang : : Type * Type ) {
assert ( Type & & " Type cannot be null " ) ;
2017-06-03 23:23:50 +03:00
const Transaction * & Cache = m_Interpreter - > getStdStringTransaction ( ) ;
2017-06-04 07:18:01 +03:00
if ( ! Cache | | ! m_StringTy [ kStdString ] ) {
2017-06-23 11:46:37 +03:00
// getStringType can be called multiple times with Cache being null, and
// the local cache should be discarded when that occurs.
if ( ! Cache )
2021-05-20 10:42:00 +03:00
m_StringTy = { { } } ;
2017-06-03 23:23:50 +03:00
QualType Qt = findType ( " std::string " , WithDiagnostics ) ;
2017-06-04 07:18:01 +03:00
m_StringTy [ kStdString ] = Qt . isNull ( ) ? nullptr : Qt . getTypePtr ( ) ;
if ( ! m_StringTy [ kStdString ] ) return kNotAString ;
Cache = m_Interpreter - > getLatestTransaction ( ) ;
m_StringTy [ kWCharString ] = getType ( this , " std::wstring " ) ;
const clang : : LangOptions & LO = m_Interpreter - > getCI ( ) - > getLangOpts ( ) ;
if ( LO . CPlusPlus11 ) {
m_StringTy [ kUTF16Str ] = getType ( this , " std::u16string " ) ;
m_StringTy [ kUTF32Str ] = getType ( this , " std::u32string " ) ;
}
}
ASTContext & Ctx = m_Interpreter - > getSema ( ) . getASTContext ( ) ;
for ( unsigned I = 0 ; I < kNumCachedStrings ; + + I ) {
if ( m_StringTy [ I ] & & Ctx . hasSameType ( Type , m_StringTy [ I ] ) )
return StringType ( I ) ;
2017-06-03 23:23:50 +03:00
}
2017-06-04 07:18:01 +03:00
return kNotAString ;
2017-05-08 12:26:17 +03:00
}
2018-08-08 19:46:34 +03:00
void LookupHelper : : printStats ( ) const {
llvm : : errs ( ) < < " Cached entries: " < < m_ParseBufferCache . size ( ) < < " \n " ;
llvm : : errs ( ) < < " Total parse requests: " < < m_TotalParseRequests < < " \n " ;
llvm : : errs ( ) < < " Cache hits: " < < m_CacheHits < < " \n " ;
}
2012-09-05 13:37:39 +04:00
} // end namespace cling