2012-09-05 09:37:39 +00:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
2014-01-07 11:08:37 +01:00
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
2012-09-05 09:37:39 +00:00
//------------------------------------------------------------------------------
# include "DeclExtractor.h"
2012-10-17 08:52:24 +00:00
# include "cling/Utils/AST.h"
2012-09-05 09:37:39 +00:00
# include "clang/AST/ASTContext.h"
# include "clang/AST/Decl.h"
2013-10-02 18:43:03 +02:00
# include "clang/AST/DeclTemplate.h"
2012-11-11 12:51:35 +00:00
# include "clang/Sema/Lookup.h"
2012-09-05 09:37:39 +00:00
# include "clang/Sema/Scope.h"
# include "clang/Sema/Sema.h"
# include "clang/Sema/SemaDiagnostic.h"
using namespace clang ;
2013-10-02 18:43:03 +02:00
namespace {
// Remove the linkage cache. On next access it will calculate it
// considering the new position of the declaration.
class BreakProtection : public clang : : NamedDecl {
public :
static void resetCachedLinkage ( clang : : NamedDecl * ND ) {
static_cast < BreakProtection * > ( ND ) - > CacheValidAndLinkage = 0 ; }
} ;
static void clearLinkageForClass ( const CXXRecordDecl * RD ) {
for ( DeclContext : : decl_iterator I = RD - > decls_begin ( ) ,
E = RD - > decls_end ( ) ; I ! = E ; + + I ) {
if ( NamedDecl * IND = dyn_cast < NamedDecl > ( * I ) )
BreakProtection : : resetCachedLinkage ( IND ) ;
}
}
static void clearLinkage ( NamedDecl * ND ) {
BreakProtection : : resetCachedLinkage ( ND ) ;
if ( const CXXRecordDecl * CXXRD = dyn_cast < CXXRecordDecl > ( ND ) )
clearLinkageForClass ( CXXRD ) ;
else
if ( ClassTemplateDecl * temp = dyn_cast < ClassTemplateDecl > ( ND ) ) {
// Clear linkage for the template pattern.
CXXRecordDecl * record = temp - > getTemplatedDecl ( ) ;
clearLinkageForClass ( record ) ;
// We need to clear linkage for specializations, too.
for ( ClassTemplateDecl : : spec_iterator
i = temp - > spec_begin ( ) , e = temp - > spec_end ( ) ; i ! = e ; + + i )
clearLinkage ( * i ) ;
} else
// Clear cached linkage for function template decls, too.
if ( FunctionTemplateDecl * temp = dyn_cast < FunctionTemplateDecl > ( ND ) ) {
clearLinkage ( temp - > getTemplatedDecl ( ) ) ;
for ( FunctionTemplateDecl : : spec_iterator
i = temp - > spec_begin ( ) , e = temp - > spec_end ( ) ; i ! = e ; + + i )
clearLinkage ( * i ) ;
}
}
}
2012-09-05 09:37:39 +00:00
namespace cling {
2014-08-03 21:05:42 -05:00
DeclExtractor : : DeclExtractor ( Sema * S )
2015-03-16 14:49:28 +01:00
: WrapperTransformer ( S ) , m_Context ( & S - > getASTContext ( ) ) ,
2012-12-19 10:56:30 +00:00
m_UniqueNameCounter ( 0 )
2012-09-05 09:37:39 +00:00
{ }
// pin the vtable here
2014-08-03 21:05:42 -05:00
DeclExtractor : : ~ DeclExtractor ( )
{ }
2012-09-05 09:37:39 +00:00
2015-03-16 14:49:28 +01:00
WrapperTransformer : : Result DeclExtractor : : Transform ( Decl * D ) {
if ( ! getCompilationOpts ( ) . DeclarationExtraction )
return Result ( D , true ) ;
FunctionDecl * FD = cast < FunctionDecl > ( D ) ;
assert ( utils : : Analyze : : IsWrapper ( FD ) & & " Expected wrapper " ) ;
2012-09-05 09:37:39 +00:00
2015-03-16 14:49:28 +01:00
if ( ! ExtractDecl ( FD ) )
return Result ( nullptr , false ) ;
return Result ( FD , true ) ;
2012-09-05 09:37:39 +00:00
}
2012-11-11 12:47:05 +00:00
bool DeclExtractor : : ExtractDecl ( FunctionDecl * FD ) {
llvm : : SmallVector < NamedDecl * , 4 > TouchedDecls ;
CompoundStmt * CS = dyn_cast < CompoundStmt > ( FD - > getBody ( ) ) ;
assert ( CS & & " Function body not a CompoundStmt? " ) ;
2015-04-04 20:56:15 +02:00
DeclContext * DC = m_Context - > getTranslationUnitDecl ( ) ;
2012-11-11 12:47:05 +00:00
Scope * TUScope = m_Sema - > TUScope ;
assert ( TUScope = = m_Sema - > getScopeForContext ( DC ) & & " TU scope from DC? " ) ;
llvm : : SmallVector < Stmt * , 4 > Stmts ;
for ( CompoundStmt : : body_iterator I = CS - > body_begin ( ) , EI = CS - > body_end ( ) ;
I ! = EI ; + + I ) {
DeclStmt * DS = dyn_cast < DeclStmt > ( * I ) ;
if ( ! DS ) {
Stmts . push_back ( * I ) ;
continue ;
}
2014-08-03 21:05:42 -05:00
2012-11-11 12:47:05 +00:00
for ( DeclStmt : : decl_iterator J = DS - > decl_begin ( ) ;
J ! = DS - > decl_end ( ) ; + + J ) {
NamedDecl * ND = dyn_cast < NamedDecl > ( * J ) ;
2012-12-07 13:20:45 +00:00
if ( isa < UsingDirectiveDecl > ( * J ) )
continue ; // FIXME: Here we should be more elegant.
2012-11-11 12:47:05 +00:00
if ( ND ) {
2012-12-19 10:56:30 +00:00
if ( Stmts . size ( ) ) {
// We need to emit a new custom wrapper wrapping the stmts
EnforceInitOrder ( Stmts ) ;
2013-10-10 09:03:17 +02:00
assert ( ! Stmts . size ( ) & & " Stmt list must be flushed. " ) ;
2012-12-19 10:56:30 +00:00
}
2012-11-11 12:47:05 +00:00
DeclContext * OldDC = ND - > getDeclContext ( ) ;
// Make sure the decl is not found at its old possition
2014-02-12 15:24:46 +01:00
ND - > getLexicalDeclContext ( ) - > removeDecl ( ND ) ;
2012-11-11 12:47:05 +00:00
if ( Scope * S = m_Sema - > getScopeForContext ( OldDC ) ) {
S - > RemoveDecl ( ND ) ;
2014-02-12 15:24:46 +01:00
if ( utils : : Analyze : : isOnScopeChains ( ND , * m_Sema ) )
m_Sema - > IdResolver . RemoveDecl ( ND ) ;
2012-11-11 12:47:05 +00:00
}
2012-09-05 09:37:39 +00:00
2014-02-12 14:42:19 +01:00
// For variable definitions causing var/function ambiguity such as:
// MyClass my();, C++ standard says it shall be resolved as a function
//
// In the particular context this definition is inside a function
// already, but clang thinks it as a lambda, so we need to ignore the
// check decl context vs lexical decl context.
if ( ND - > getDeclContext ( ) = = ND - > getLexicalDeclContext ( )
| | isa < FunctionDecl > ( ND ) )
2012-11-11 12:47:05 +00:00
ND - > setLexicalDeclContext ( DC ) ;
2014-08-03 21:05:42 -05:00
else
2012-12-06 19:17:32 +00:00
assert ( 0 & & " Not implemented: Decl with different lexical context " ) ;
2012-11-11 12:47:05 +00:00
ND - > setDeclContext ( DC ) ;
2012-09-05 09:37:39 +00:00
2012-11-11 12:47:05 +00:00
if ( VarDecl * VD = dyn_cast < VarDecl > ( ND ) ) {
VD - > setStorageClass ( SC_None ) ;
2012-09-05 09:37:39 +00:00
}
2013-10-02 18:43:03 +02:00
clearLinkage ( ND ) ;
2012-11-11 12:47:05 +00:00
TouchedDecls . push_back ( ND ) ;
2015-03-16 14:49:28 +01:00
Emit ( DeclGroupRef ( ND ) ) ;
2012-09-05 09:37:39 +00:00
}
}
2012-11-11 12:47:05 +00:00
}
bool hasNoErrors = ! CheckForClashingNames ( TouchedDecls , DC , TUScope ) ;
if ( hasNoErrors ) {
for ( size_t i = 0 ; i < TouchedDecls . size ( ) ; + + i ) {
2014-02-12 14:18:08 +01:00
// We should skip the checks for annonymous decls and we should not
// register them in the lookup.
if ( ! TouchedDecls [ i ] - > getDeclName ( ) )
continue ;
2014-02-06 17:05:22 +01:00
2012-11-11 12:47:05 +00:00
m_Sema - > PushOnScopeChains ( TouchedDecls [ i ] ,
m_Sema - > getScopeForContext ( DC ) ,
2012-09-05 09:37:39 +00:00
/*AddCurContext*/ ! isa < UsingDirectiveDecl > ( TouchedDecls [ i ] ) ) ;
2014-08-03 21:05:42 -05:00
// The transparent DeclContexts (eg. scopeless enum) doesn't have
2012-11-11 12:47:05 +00:00
// scopes. While extracting their contents we need to update the
// lookup tables and telling them to pick up the new possitions
2012-12-19 10:56:30 +00:00
// in the AST.
2012-11-11 12:47:05 +00:00
if ( DeclContext * InnerDC = dyn_cast < DeclContext > ( TouchedDecls [ i ] ) ) {
if ( InnerDC - > isTransparentContext ( ) ) {
// We can't PushDeclContext, because we don't have scope.
Sema : : ContextRAII pushedDC ( * m_Sema , InnerDC ) ;
2014-08-03 21:05:42 -05:00
for ( DeclContext : : decl_iterator DI = InnerDC - > decls_begin ( ) ,
2012-11-11 12:47:05 +00:00
DE = InnerDC - > decls_end ( ) ; DI ! = DE ; + + DI ) {
if ( NamedDecl * ND = dyn_cast < NamedDecl > ( * DI ) )
InnerDC - > makeDeclVisibleInContext ( ND ) ;
2012-09-05 09:37:39 +00:00
}
}
}
}
2012-11-11 12:47:05 +00:00
}
2012-09-05 09:37:39 +00:00
2012-11-11 12:47:05 +00:00
CS - > setStmts ( * m_Context , Stmts . data ( ) , Stmts . size ( ) ) ;
2012-09-05 09:37:39 +00:00
2015-03-16 14:49:28 +01:00
if ( hasNoErrors & & ! TouchedDecls . empty ( ) ) {
// Put the wrapper after its declarations. (Nice when AST dumping)
DC - > removeDecl ( FD ) ;
DC - > addDecl ( FD ) ;
}
2012-09-05 09:37:39 +00:00
2015-03-16 14:49:28 +01:00
return hasNoErrors ? FD : 0 ;
2012-09-05 09:37:39 +00:00
}
2012-12-19 10:56:30 +00:00
void DeclExtractor : : createUniqueName ( std : : string & out ) {
if ( out . empty ( ) )
out + = ' _ ' ;
out + = " _init_order " ;
out + = utils : : Synthesize : : UniquePrefix ;
llvm : : raw_string_ostream ( out ) < < m_UniqueNameCounter + + ;
}
void DeclExtractor : : EnforceInitOrder ( llvm : : SmallVectorImpl < Stmt * > & Stmts ) {
Scope * TUScope = m_Sema - > TUScope ;
DeclContext * TUDC = static_cast < DeclContext * > ( TUScope - > getEntity ( ) ) ;
// We can't PushDeclContext, because we don't have scope.
Sema : : ContextRAII pushedDC ( * m_Sema , TUDC ) ;
std : : string FunctionName = " __fd " ;
createUniqueName ( FunctionName ) ;
IdentifierInfo & IIFD = m_Context - > Idents . get ( FunctionName ) ;
SourceLocation Loc ;
NamedDecl * ND = m_Sema - > ImplicitlyDefineFunction ( Loc , IIFD , TUScope ) ;
if ( FunctionDecl * FD = dyn_cast_or_null < FunctionDecl > ( ND ) ) {
FD - > setImplicit ( false ) ; // Better for debugging
2013-04-24 16:28:08 +00:00
// Add a return statement if it doesn't exist
if ( ! isa < ReturnStmt > ( Stmts . back ( ) ) ) {
Sema : : ContextRAII pushedDC ( * m_Sema , FD ) ;
// Generate the return statement:
// First a literal 0, then the return taking that literal.
// One bit is enough:
llvm : : APInt ZeroInt ( m_Context - > getIntWidth ( m_Context - > IntTy ) , 0 ,
/*isSigned=*/ true ) ;
IntegerLiteral * ZeroLit
= IntegerLiteral : : Create ( * m_Context , ZeroInt , m_Context - > IntTy ,
SourceLocation ( ) ) ;
2014-08-03 21:05:42 -05:00
Stmts . push_back ( m_Sema - > ActOnReturnStmt ( ZeroLit - > getExprLoc ( ) ,
2014-06-27 16:21:13 +02:00
ZeroLit ,
m_Sema - > getCurScope ( ) ) . get ( ) ) ;
2013-04-24 16:28:08 +00:00
}
// Wrap Stmts into a function body.
llvm : : ArrayRef < Stmt * > StmtsRef ( Stmts . data ( ) , Stmts . size ( ) ) ;
CompoundStmt * CS = new ( * m_Context ) CompoundStmt ( * m_Context , StmtsRef ,
Loc , Loc ) ;
2012-12-19 10:56:30 +00:00
FD - > setBody ( CS ) ;
2015-03-16 14:49:28 +01:00
Emit ( FD ) ;
2012-12-19 10:56:30 +00:00
2014-08-03 21:05:42 -05:00
// Create the VarDecl with the init
2012-12-19 10:56:30 +00:00
std : : string VarName = " __vd " ;
createUniqueName ( VarName ) ;
IdentifierInfo & IIVD = m_Context - > Idents . get ( VarName ) ;
VarDecl * VD = VarDecl : : Create ( * m_Context , TUDC , Loc , Loc , & IIVD ,
2014-02-18 08:22:16 +01:00
FD - > getReturnType ( ) , ( TypeSourceInfo * ) 0 ,
2013-04-24 16:28:08 +00:00
SC_None ) ;
2012-12-19 10:56:30 +00:00
LookupResult R ( * m_Sema , FD - > getDeclName ( ) , Loc , Sema : : LookupMemberName ) ;
R . addDecl ( FD ) ;
CXXScopeSpec CSS ;
Expr * UnresolvedLookup
2014-06-06 10:18:32 +02:00
= m_Sema - > BuildDeclarationNameExpr ( CSS , R , /*ADL*/ false ) . get ( ) ;
2014-08-03 21:05:42 -05:00
Expr * TheCall = m_Sema - > ActOnCallExpr ( TUScope , UnresolvedLookup , Loc ,
2014-06-06 10:18:32 +02:00
MultiExprArg ( ) , Loc ) . get ( ) ;
2013-04-12 11:46:41 +00:00
assert ( VD & & TheCall & & " Missing VD or its init! " ) ;
2012-12-19 10:56:30 +00:00
VD - > setInit ( TheCall ) ;
2013-06-13 14:53:58 +02:00
2015-03-16 14:49:28 +01:00
Emit ( VD ) ; // Add it to the transaction for codegenning
2014-08-14 12:19:18 +02:00
VD - > setHidden ( true ) ;
2012-12-19 10:56:30 +00:00
TUDC - > addHiddenDecl ( VD ) ;
2013-10-10 09:03:17 +02:00
Stmts . clear ( ) ;
2012-12-19 10:56:30 +00:00
return ;
}
llvm_unreachable ( " Must be able to enforce init order. " ) ;
}
2012-09-05 09:37:39 +00:00
///\brief Checks for clashing names when trying to extract a declaration.
///
///\returns true if there is another declaration with the same name
bool DeclExtractor : : CheckForClashingNames (
const llvm : : SmallVector < NamedDecl * , 4 > & Decls ,
DeclContext * DC , Scope * S ) {
for ( size_t i = 0 ; i < Decls . size ( ) ; + + i ) {
NamedDecl * ND = Decls [ i ] ;
if ( TagDecl * TD = dyn_cast < TagDecl > ( ND ) ) {
LookupResult Previous ( * m_Sema , ND - > getDeclName ( ) , ND - > getLocation ( ) ,
Sema : : LookupTagName , Sema : : ForRedeclaration
) ;
m_Sema - > LookupName ( Previous , S ) ;
// There is no function diagnosing the redeclaration of tags (eg. enums).
// So either we have to do it by hand or we can call the top-most
// function that does the check. Currently the top-most clang function
// doing the checks creates an AST node, which we don't want.
2014-02-18 08:22:16 +01:00
if ( ! CheckTagDeclaration ( TD , Previous ) )
return true ;
2012-09-05 09:37:39 +00:00
}
else if ( VarDecl * VD = dyn_cast < VarDecl > ( ND ) ) {
LookupResult Previous ( * m_Sema , ND - > getDeclName ( ) , ND - > getLocation ( ) ,
Sema : : LookupOrdinaryName , Sema : : ForRedeclaration
) ;
m_Sema - > LookupName ( Previous , S ) ;
m_Sema - > CheckVariableDeclaration ( VD , Previous ) ;
2014-02-18 08:22:16 +01:00
if ( VD - > isInvalidDecl ( ) )
return true ;
2014-02-19 15:48:09 +01:00
// This var decl will likely get referenced later; claim that it's used.
VD - > setIsUsed ( ) ;
2012-09-05 09:37:39 +00:00
}
}
return false ;
}
bool DeclExtractor : : CheckTagDeclaration ( TagDecl * NewTD ,
LookupResult & Previous ) {
// If the decl is already known invalid, don't check it.
if ( NewTD - > isInvalidDecl ( ) )
return false ;
IdentifierInfo * Name = NewTD - > getIdentifier ( ) ;
// If this is not a definition, it must have a name.
assert ( ( Name ! = 0 | | NewTD - > isThisDeclarationADefinition ( ) ) & &
" Nameless record must be a definition! " ) ;
// Figure out the underlying type if this a enum declaration. We need to do
// this early, because it's needed to detect if this is an incompatible
// redeclaration.
TagDecl : : TagKind Kind = NewTD - > getTagKind ( ) ;
bool Invalid = false ;
assert ( NewTD - > getNumTemplateParameterLists ( ) = = 0
& & " Cannot handle that yet! " ) ;
bool isExplicitSpecialization = false ;
if ( Kind = = TTK_Enum ) {
EnumDecl * ED = cast < EnumDecl > ( NewTD ) ;
bool ScopedEnum = ED - > isScoped ( ) ;
const QualType QT = ED - > getIntegerType ( ) ;
if ( QT . isNull ( ) & & ScopedEnum )
// No underlying type explicitly specified, or we failed to parse the
// type, default to int.
; //EnumUnderlying = m_Context->IntTy.getTypePtr();
else if ( ! QT . isNull ( ) ) {
// C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an
// integral type; any cv-qualification is ignored.
SourceLocation UnderlyingLoc ;
TypeSourceInfo * TI = 0 ;
if ( ( TI = ED - > getIntegerTypeSourceInfo ( ) ) )
UnderlyingLoc = TI - > getTypeLoc ( ) . getBeginLoc ( ) ;
if ( ! QT - > isDependentType ( ) & & ! QT - > isIntegralType ( * m_Context ) ) {
m_Sema - > Diag ( UnderlyingLoc , diag : : err_enum_invalid_underlying )
< < QT ;
}
if ( TI )
m_Sema - > DiagnoseUnexpandedParameterPack ( UnderlyingLoc , TI ,
Sema : : UPPC_FixedUnderlyingType ) ;
}
}
DeclContext * SearchDC = m_Sema - > CurContext ;
DeclContext * DC = m_Sema - > CurContext ;
//bool isStdBadAlloc = false;
SourceLocation NameLoc = NewTD - > getLocation ( ) ;
// if (Name && SS.isNotEmpty()) {
// // We have a nested-name tag ('struct foo::bar').
// // Check for invalid 'foo::'.
// if (SS.isInvalid()) {
// Name = 0;
// goto CreateNewDecl;
// }
// // If this is a friend or a reference to a class in a dependent
// // context, don't try to make a decl for it.
// if (TUK == TUK_Friend || TUK == TUK_Reference) {
// DC = computeDeclContext(SS, false);
// if (!DC) {
// IsDependent = true;
// return 0;
// }
// } else {
// DC = computeDeclContext(SS, true);
// if (!DC) {
// Diag(SS.getRange().getBegin(),
// diag::err_dependent_nested_name_spec)
// << SS.getRange();
// return 0;
// }
// }
// if (RequireCompleteDeclContext(SS, DC))
// return 0;
// SearchDC = DC;
// // Look-up name inside 'foo::'.
// LookupQualifiedName(Previous, DC);
// if (Previous.isAmbiguous())
// return 0;
// if (Previous.empty()) {
// // Name lookup did not find anything. However, if the
// // nested-name-specifier refers to the current instantiation,
// // and that current instantiation has any dependent base
// // classes, we might find something at instantiation time: treat
// // this as a dependent elaborated-type-specifier.
// // But this only makes any sense for reference-like lookups.
// if (Previous.wasNotFoundInCurrentInstantiation() &&
// (TUK == TUK_Reference || TUK == TUK_Friend)) {
// IsDependent = true;
// return 0;
// }
// // A tag 'foo::bar' must already exist.
// Diag(NameLoc, diag::err_not_tag_in_scope)
// << Kind << Name << DC << SS.getRange();
// Name = 0;
// Invalid = true;
// goto CreateNewDecl;
// }
//} else
if ( Name ) {
// If this is a named struct, check to see if there was a previous forward
// declaration or definition.
// FIXME: We're looking into outer scopes here, even when we
// shouldn't be. Doing so can result in ambiguities that we
// shouldn't be diagnosing.
//LookupName(Previous, S);
if ( Previous . isAmbiguous ( ) ) {
LookupResult : : Filter F = Previous . makeFilter ( ) ;
while ( F . hasNext ( ) ) {
NamedDecl * ND = F . next ( ) ;
if ( ND - > getDeclContext ( ) - > getRedeclContext ( ) ! = SearchDC )
F . erase ( ) ;
}
F . done ( ) ;
}
// Note: there used to be some attempt at recovery here.
if ( Previous . isAmbiguous ( ) ) {
return false ;
}
if ( ! m_Sema - > getLangOpts ( ) . CPlusPlus ) {
// FIXME: This makes sure that we ignore the contexts associated
// with C structs, unions, and enums when looking for a matching
// tag declaration or definition. See the similar lookup tweak
// in Sema::LookupName; is there a better way to deal with this?
while ( isa < RecordDecl > ( SearchDC ) | | isa < EnumDecl > ( SearchDC ) )
SearchDC = SearchDC - > getParent ( ) ;
}
} else if ( m_Sema - > getScopeForContext ( m_Sema - > CurContext )
- > isFunctionPrototypeScope ( ) ) {
// If this is an enum declaration in function prototype scope, set its
// initial context to the translation unit.
SearchDC = m_Context - > getTranslationUnitDecl ( ) ;
}
if ( Previous . isSingleResult ( ) & &
Previous . getFoundDecl ( ) - > isTemplateParameter ( ) ) {
// Maybe we will complain about the shadowed template parameter.
m_Sema - > DiagnoseTemplateParameterShadow ( NameLoc , Previous . getFoundDecl ( ) ) ;
// Just pretend that we didn't see the previous declaration.
Previous . clear ( ) ;
}
if ( m_Sema - > getLangOpts ( ) . CPlusPlus & & Name & & DC & & m_Sema - > StdNamespace
& & DC - > Equals ( m_Sema - > getStdNamespace ( ) ) & & Name - > isStr ( " bad_alloc " ) ) {
// This is a declaration of or a reference to "std::bad_alloc".
//isStdBadAlloc = true;
if ( Previous . empty ( ) & & m_Sema - > StdBadAlloc ) {
// std::bad_alloc has been implicitly declared (but made invisible to
// name lookup). Fill in this implicit declaration as the previous
// declaration, so that the declarations get chained appropriately.
Previous . addDecl ( m_Sema - > getStdBadAlloc ( ) ) ;
}
}
if ( ! Previous . empty ( ) ) {
NamedDecl * PrevDecl = ( * Previous . begin ( ) ) - > getUnderlyingDecl ( ) ;
// It's okay to have a tag decl in the same scope as a typedef
// which hides a tag decl in the same scope. Finding this
// insanity with a redeclaration lookup can only actually happen
// in C++.
//
// This is also okay for elaborated-type-specifiers, which is
// technically forbidden by the current standard but which is
// okay according to the likely resolution of an open issue;
// see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407
if ( m_Sema - > getLangOpts ( ) . CPlusPlus ) {
if ( TypedefNameDecl * TD = dyn_cast < TypedefNameDecl > ( PrevDecl ) ) {
if ( const TagType * TT = TD - > getUnderlyingType ( ) - > getAs < TagType > ( ) ) {
TagDecl * Tag = TT - > getDecl ( ) ;
if ( Tag - > getDeclName ( ) = = Name & &
Tag - > getDeclContext ( ) - > getRedeclContext ( )
- > Equals ( TD - > getDeclContext ( ) - > getRedeclContext ( ) ) ) {
PrevDecl = Tag ;
Previous . clear ( ) ;
Previous . addDecl ( Tag ) ;
Previous . resolveKind ( ) ;
}
}
}
}
if ( TagDecl * PrevTagDecl = dyn_cast < TagDecl > ( PrevDecl ) ) {
// If this is a use of a previous tag, or if the tag is already declared
// in the same scope (so that the definition/declaration completes or
// rementions the tag), reuse the decl.
if ( m_Sema - > isDeclInScope ( PrevDecl , SearchDC ,
m_Sema - > getScopeForContext ( m_Sema - > CurContext ) ,
isExplicitSpecialization ) ) {
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
SourceLocation KWLoc = NewTD - > getLocStart ( ) ;
if ( ! m_Sema - > isAcceptableTagRedeclaration ( PrevTagDecl , Kind ,
NewTD - > isThisDeclarationADefinition ( ) ,
KWLoc , * Name ) ) {
bool SafeToContinue
= ( PrevTagDecl - > getTagKind ( ) ! = TTK_Enum & & Kind ! = TTK_Enum ) ;
if ( SafeToContinue )
m_Sema - > Diag ( KWLoc , diag : : err_use_with_wrong_tag )
< < Name
< < FixItHint : : CreateReplacement ( SourceRange ( KWLoc ) ,
PrevTagDecl - > getKindName ( ) ) ;
else
m_Sema - > Diag ( KWLoc , diag : : err_use_with_wrong_tag ) < < Name ;
m_Sema - > Diag ( PrevTagDecl - > getLocation ( ) , diag : : note_previous_use ) ;
if ( SafeToContinue )
Kind = PrevTagDecl - > getTagKind ( ) ;
else {
// Recover by making this an anonymous redefinition.
Name = 0 ;
Previous . clear ( ) ;
Invalid = true ;
}
}
if ( Kind = = TTK_Enum & & PrevTagDecl - > getTagKind ( ) = = TTK_Enum ) {
const EnumDecl * NewEnum = cast < EnumDecl > ( NewTD ) ;
const EnumDecl * PrevEnum = cast < EnumDecl > ( PrevTagDecl ) ;
// All conflicts with previous declarations are recovered by
// returning the previous declaration.
if ( NewEnum - > isScoped ( ) ! = PrevEnum - > isScoped ( ) ) {
m_Sema - > Diag ( KWLoc , diag : : err_enum_redeclare_scoped_mismatch )
< < PrevEnum - > isScoped ( ) ;
m_Sema - > Diag ( PrevTagDecl - > getLocation ( ) , diag : : note_previous_use ) ;
return false ;
}
else if ( PrevEnum - > isFixed ( ) ) {
QualType T = NewEnum - > getIntegerType ( ) ;
if ( ! m_Context - > hasSameUnqualifiedType ( T ,
PrevEnum - > getIntegerType ( ) ) ) {
m_Sema - > Diag ( NameLoc . isValid ( ) ? NameLoc : KWLoc ,
diag : : err_enum_redeclare_type_mismatch )
< < T
< < PrevEnum - > getIntegerType ( ) ;
m_Sema - > Diag ( PrevTagDecl - > getLocation ( ) ,
diag : : note_previous_use ) ;
return false ;
}
}
else if ( NewEnum - > isFixed ( ) ! = PrevEnum - > isFixed ( ) ) {
m_Sema - > Diag ( KWLoc , diag : : err_enum_redeclare_fixed_mismatch )
< < PrevEnum - > isFixed ( ) ;
m_Sema - > Diag ( PrevTagDecl - > getLocation ( ) , diag : : note_previous_use ) ;
return false ;
}
}
if ( ! Invalid ) {
// If this is a use, just return the declaration we found.
// Diagnose attempts to redefine a tag.
if ( NewTD - > isThisDeclarationADefinition ( ) ) {
if ( TagDecl * Def = PrevTagDecl - > getDefinition ( ) ) {
// If we're defining a specialization and the previous
// definition is from an implicit instantiation, don't emit an
// error here; we'll catch this in the general case below.
if ( ! isExplicitSpecialization | |
! isa < CXXRecordDecl > ( Def ) | |
cast < CXXRecordDecl > ( Def ) - > getTemplateSpecializationKind ( )
= = TSK_ExplicitSpecialization ) {
m_Sema - > Diag ( NameLoc , diag : : err_redefinition ) < < Name ;
m_Sema - > Diag ( Def - > getLocation ( ) ,
diag : : note_previous_definition ) ;
// If this is a redefinition, recover by making this
// struct be anonymous, which will make any later
// references get the previous definition.
Name = 0 ;
Previous . clear ( ) ;
Invalid = true ;
}
} else {
// If the type is currently being defined, complain
// about a nested redefinition.
const TagType * Tag
= cast < TagType > ( m_Context - > getTagDeclType ( PrevTagDecl ) ) ;
if ( Tag - > isBeingDefined ( ) ) {
m_Sema - > Diag ( NameLoc , diag : : err_nested_redefinition ) < < Name ;
m_Sema - > Diag ( PrevTagDecl - > getLocation ( ) ,
diag : : note_previous_definition ) ;
Name = 0 ;
Previous . clear ( ) ;
Invalid = true ;
}
}
// Okay, this is definition of a previously declared or referenced
// tag PrevDecl. We're going to create a new Decl for it.
}
}
// If we get here we have (another) forward declaration or we
// have a definition. Just create a new decl.
} else {
// If we get here, this is a definition of a new tag type in a nested
// scope, e.g. "struct foo; void bar() { struct foo; }", just create a
// new decl/type. We set PrevDecl to NULL so that the entities
// have distinct types.
Previous . clear ( ) ;
}
// If we get here, we're going to create a new Decl. If PrevDecl
// is non-NULL, it's a definition of the tag declared by
// PrevDecl. If it's NULL, we have a new definition.
// Otherwise, PrevDecl is not a tag, but was found with tag
// lookup. This is only actually possible in C++, where a few
// things like templates still live in the tag namespace.
} else {
assert ( m_Sema - > getLangOpts ( ) . CPlusPlus ) ;
// Diagnose if the declaration is in scope.
if ( ! m_Sema - > isDeclInScope ( PrevDecl , SearchDC ,
m_Sema - > getScopeForContext ( m_Sema - > CurContext ) ,
isExplicitSpecialization ) ) {
// do nothing
// Otherwise it's a declaration. Call out a particularly common
// case here.
} else if ( TypedefNameDecl * TND = dyn_cast < TypedefNameDecl > ( PrevDecl ) ) {
unsigned Kind = 0 ;
if ( isa < TypeAliasDecl > ( PrevDecl ) ) Kind = 1 ;
m_Sema - > Diag ( NameLoc , diag : : err_tag_definition_of_typedef )
< < Name < < Kind < < TND - > getUnderlyingType ( ) ;
m_Sema - > Diag ( PrevDecl - > getLocation ( ) ,
diag : : note_previous_decl ) < < PrevDecl ;
Invalid = true ;
// Otherwise, diagnose.
} else {
// The tag name clashes with something else in the target scope,
// issue an error and recover by making this tag be anonymous.
m_Sema - > Diag ( NameLoc , diag : : err_redefinition_different_kind ) < < Name ;
m_Sema - > Diag ( PrevDecl - > getLocation ( ) , diag : : note_previous_definition ) ;
Name = 0 ;
Invalid = true ;
}
// The existing declaration isn't relevant to us; we're in a
// new scope, so clear out the previous declaration.
Previous . clear ( ) ;
}
}
if ( Invalid ) {
return false ;
}
return true ;
}
} // namespace cling