cling/lib/Interpreter/DeclExtractor.cpp

679 lines
26 KiB
C++
Raw Normal View History

//------------------------------------------------------------------------------
// 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.
//------------------------------------------------------------------------------
#include "DeclExtractor.h"
#include "cling/Utils/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
using namespace clang;
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);
}
}
}
namespace cling {
2014-08-03 21:05:42 -05:00
DeclExtractor::DeclExtractor(Sema* S)
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 14:49:28 +01:00
: WrapperTransformer(S), m_Context(&S->getASTContext()),
m_UniqueNameCounter(0)
{ }
// pin the vtable here
2014-08-03 21:05:42 -05:00
DeclExtractor::~DeclExtractor()
{ }
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
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");
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 14:49:28 +01:00
if (!ExtractDecl(FD))
return Result(nullptr, false);
return Result(FD, true);
}
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();
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
for (DeclStmt::decl_iterator J = DS->decl_begin();
J != DS->decl_end(); ++J) {
NamedDecl* ND = dyn_cast<NamedDecl>(*J);
if (isa<UsingDirectiveDecl>(*J))
continue; // FIXME: Here we should be more elegant.
if (ND) {
if (Stmts.size()) {
// We need to emit a new custom wrapper wrapping the stmts
EnforceInitOrder(Stmts);
assert(!Stmts.size() && "Stmt list must be flushed.");
}
DeclContext* OldDC = ND->getDeclContext();
// Make sure the decl is not found at its old possition
ND->getLexicalDeclContext()->removeDecl(ND);
if (Scope* S = m_Sema->getScopeForContext(OldDC)) {
S->RemoveDecl(ND);
if (utils::Analyze::isOnScopeChains(ND, *m_Sema))
m_Sema->IdResolver.RemoveDecl(ND);
}
// 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))
ND->setLexicalDeclContext(DC);
2014-08-03 21:05:42 -05:00
else
assert(0 && "Not implemented: Decl with different lexical context");
ND->setDeclContext(DC);
if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
VD->setStorageClass(SC_None);
}
clearLinkage(ND);
TouchedDecls.push_back(ND);
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 14:49:28 +01:00
Emit(DeclGroupRef(ND));
}
}
}
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;
m_Sema->PushOnScopeChains(TouchedDecls[i],
m_Sema->getScopeForContext(DC),
/*AddCurContext*/!isa<UsingDirectiveDecl>(TouchedDecls[i]));
2014-08-03 21:05:42 -05:00
// The transparent DeclContexts (eg. scopeless enum) doesn't have
// scopes. While extracting their contents we need to update the
// lookup tables and telling them to pick up the new possitions
// in the AST.
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(),
DE = InnerDC->decls_end(); DI != DE ; ++DI) {
if (NamedDecl* ND = dyn_cast<NamedDecl>(*DI))
InnerDC->makeDeclVisibleInContext(ND);
}
}
}
}
}
CS->setStmts(*m_Context, Stmts.data(), Stmts.size());
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
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);
}
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 14:49:28 +01:00
return hasNoErrors ? FD : 0;
}
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
// 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());
}
// 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);
FD->setBody(CS);
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 14:49:28 +01:00
Emit(FD);
2014-08-03 21:05:42 -05:00
// Create the VarDecl with the init
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,
SC_None);
LookupResult R(*m_Sema, FD->getDeclName(), Loc, Sema::LookupMemberName);
R.addDecl(FD);
CXXScopeSpec CSS;
Expr* UnresolvedLookup
= m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).get();
2014-08-03 21:05:42 -05:00
Expr* TheCall = m_Sema->ActOnCallExpr(TUScope, UnresolvedLookup, Loc,
MultiExprArg(), Loc).get();
assert(VD && TheCall && "Missing VD or its init!");
VD->setInit(TheCall);
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 14:49:28 +01:00
Emit(VD); // Add it to the transaction for codegenning
VD->setHidden(true);
TUDC->addHiddenDecl(VD);
Stmts.clear();
return;
}
llvm_unreachable("Must be able to enforce init order.");
}
///\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;
}
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;
// This var decl will likely get referenced later; claim that it's used.
VD->setIsUsed();
}
}
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