summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/CFG.cpp1924
-rw-r--r--lib/Frontend/ResolveLocation.cpp322
-rw-r--r--lib/Sema/SemaInherit.cpp350
-rw-r--r--lib/Sema/SemaInherit.h248
-rw-r--r--lib/Sema/SemaNamedCast.cpp932
-rw-r--r--lib/Sema/SemaTemplateInstantiateExpr.cpp1350
-rw-r--r--lib/Sema/SemaTemplateInstantiateStmt.cpp450
-rw-r--r--utils/test/Makefile.multi21
-rwxr-xr-xutils/test/MultiTestRunner.py347
-rw-r--r--utils/test/ProgressBar.py227
-rwxr-xr-xutils/test/TestRunner.py296
11 files changed, 0 insertions, 6467 deletions
diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp
deleted file mode 100644
index 69852f5fea57d..0000000000000
--- a/lib/AST/CFG.cpp
+++ /dev/null
@@ -1,1924 +0,0 @@
-//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the CFG and CFGBuilder classes for representing and
-// building Control-Flow Graphs (CFGs) from ASTs.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/CFG.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/Support/GraphWriter.h"
-#include "llvm/Support/Streams.h"
-#include "llvm/Support/Compiler.h"
-#include <llvm/Support/Allocator.h>
-#include <llvm/Support/Format.h>
-
-using namespace clang;
-
-namespace {
-
-// SaveAndRestore - A utility class that uses RIIA to save and restore
-// the value of a variable.
-template<typename T>
-struct VISIBILITY_HIDDEN SaveAndRestore {
- SaveAndRestore(T& x) : X(x), old_value(x) {}
- ~SaveAndRestore() { X = old_value; }
- T get() { return old_value; }
-
- T& X;
- T old_value;
-};
-
-static SourceLocation GetEndLoc(Decl* D) {
- if (VarDecl* VD = dyn_cast<VarDecl>(D))
- if (Expr* Ex = VD->getInit())
- return Ex->getSourceRange().getEnd();
-
- return D->getLocation();
-}
-
-/// CFGBuilder - This class implements CFG construction from an AST.
-/// The builder is stateful: an instance of the builder should be used to only
-/// construct a single CFG.
-///
-/// Example usage:
-///
-/// CFGBuilder builder;
-/// CFG* cfg = builder.BuildAST(stmt1);
-///
-/// CFG construction is done via a recursive walk of an AST.
-/// We actually parse the AST in reverse order so that the successor
-/// of a basic block is constructed prior to its predecessor. This
-/// allows us to nicely capture implicit fall-throughs without extra
-/// basic blocks.
-///
-class VISIBILITY_HIDDEN CFGBuilder : public StmtVisitor<CFGBuilder,CFGBlock*> {
- CFG* cfg;
- CFGBlock* Block;
- CFGBlock* Succ;
- CFGBlock* ContinueTargetBlock;
- CFGBlock* BreakTargetBlock;
- CFGBlock* SwitchTerminatedBlock;
- CFGBlock* DefaultCaseBlock;
-
- // LabelMap records the mapping from Label expressions to their blocks.
- typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
- LabelMapTy LabelMap;
-
- // A list of blocks that end with a "goto" that must be backpatched to
- // their resolved targets upon completion of CFG construction.
- typedef std::vector<CFGBlock*> BackpatchBlocksTy;
- BackpatchBlocksTy BackpatchBlocks;
-
- // A list of labels whose address has been taken (for indirect gotos).
- typedef llvm::SmallPtrSet<LabelStmt*,5> LabelSetTy;
- LabelSetTy AddressTakenLabels;
-
-public:
- explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
- ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
- SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {
- // Create an empty CFG.
- cfg = new CFG();
- }
-
- ~CFGBuilder() { delete cfg; }
-
- // buildCFG - Used by external clients to construct the CFG.
- CFG* buildCFG(Stmt* Statement);
-
- // Visitors to walk an AST and construct the CFG. Called by
- // buildCFG. Do not call directly!
-
- CFGBlock* VisitBreakStmt(BreakStmt* B);
- CFGBlock* VisitCaseStmt(CaseStmt* Terminator);
- CFGBlock* VisitCompoundStmt(CompoundStmt* C);
- CFGBlock* VisitContinueStmt(ContinueStmt* C);
- CFGBlock* VisitDefaultStmt(DefaultStmt* D);
- CFGBlock* VisitDoStmt(DoStmt* D);
- CFGBlock* VisitForStmt(ForStmt* F);
- CFGBlock* VisitGotoStmt(GotoStmt* G);
- CFGBlock* VisitIfStmt(IfStmt* I);
- CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I);
- CFGBlock* VisitLabelStmt(LabelStmt* L);
- CFGBlock* VisitNullStmt(NullStmt* Statement);
- CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
- CFGBlock* VisitReturnStmt(ReturnStmt* R);
- CFGBlock* VisitStmt(Stmt* Statement);
- CFGBlock* VisitSwitchStmt(SwitchStmt* Terminator);
- CFGBlock* VisitWhileStmt(WhileStmt* W);
-
- // FIXME: Add support for ObjC-specific control-flow structures.
-
- // NYS == Not Yet Supported
- CFGBlock* NYS() {
- badCFG = true;
- return Block;
- }
-
- CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* S);
- CFGBlock* VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) {
- // FIXME: For now we pretend that @catch and the code it contains
- // does not exit.
- return Block;
- }
-
- // FIXME: This is not completely supported. We basically @throw like
- // a 'return'.
- CFGBlock* VisitObjCAtThrowStmt(ObjCAtThrowStmt* S);
-
- CFGBlock* VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S);
-
- // Blocks.
- CFGBlock* VisitBlockExpr(BlockExpr* E) { return NYS(); }
- CFGBlock* VisitBlockDeclRefExpr(BlockDeclRefExpr* E) { return NYS(); }
-
-private:
- CFGBlock* createBlock(bool add_successor = true);
- CFGBlock* addStmt(Stmt* Terminator);
- CFGBlock* WalkAST(Stmt* Terminator, bool AlwaysAddStmt);
- CFGBlock* WalkAST_VisitChildren(Stmt* Terminator);
- CFGBlock* WalkAST_VisitDeclSubExpr(Decl* D);
- CFGBlock* WalkAST_VisitStmtExpr(StmtExpr* Terminator);
- bool FinishBlock(CFGBlock* B);
-
- bool badCFG;
-};
-
-// FIXME: Add support for dependent-sized array types in C++?
-// Does it even make sense to build a CFG for an uninstantiated template?
-static VariableArrayType* FindVA(Type* t) {
- while (ArrayType* vt = dyn_cast<ArrayType>(t)) {
- if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt))
- if (vat->getSizeExpr())
- return vat;
-
- t = vt->getElementType().getTypePtr();
- }
-
- return 0;
-}
-
-/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can
-/// represent an arbitrary statement. Examples include a single expression
-/// or a function body (compound statement). The ownership of the returned
-/// CFG is transferred to the caller. If CFG construction fails, this method
-/// returns NULL.
-CFG* CFGBuilder::buildCFG(Stmt* Statement) {
- assert (cfg);
- if (!Statement) return NULL;
-
- badCFG = false;
-
- // Create an empty block that will serve as the exit block for the CFG.
- // Since this is the first block added to the CFG, it will be implicitly
- // registered as the exit block.
- Succ = createBlock();
- assert (Succ == &cfg->getExit());
- Block = NULL; // the EXIT block is empty. Create all other blocks lazily.
-
- // Visit the statements and create the CFG.
- CFGBlock* B = Visit(Statement);
- if (!B) B = Succ;
-
- if (B) {
- // Finalize the last constructed block. This usually involves
- // reversing the order of the statements in the block.
- if (Block) FinishBlock(B);
-
- // Backpatch the gotos whose label -> block mappings we didn't know
- // when we encountered them.
- for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
- E = BackpatchBlocks.end(); I != E; ++I ) {
-
- CFGBlock* B = *I;
- GotoStmt* G = cast<GotoStmt>(B->getTerminator());
- LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
-
- // If there is no target for the goto, then we are looking at an
- // incomplete AST. Handle this by not registering a successor.
- if (LI == LabelMap.end()) continue;
-
- B->addSuccessor(LI->second);
- }
-
- // Add successors to the Indirect Goto Dispatch block (if we have one).
- if (CFGBlock* B = cfg->getIndirectGotoBlock())
- for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
- E = AddressTakenLabels.end(); I != E; ++I ) {
-
- // Lookup the target block.
- LabelMapTy::iterator LI = LabelMap.find(*I);
-
- // If there is no target block that contains label, then we are looking
- // at an incomplete AST. Handle this by not registering a successor.
- if (LI == LabelMap.end()) continue;
-
- B->addSuccessor(LI->second);
- }
-
- Succ = B;
- }
-
- // Create an empty entry block that has no predecessors.
- cfg->setEntry(createBlock());
-
- if (badCFG) {
- delete cfg;
- cfg = NULL;
- return NULL;
- }
-
- // NULL out cfg so that repeated calls to the builder will fail and that
- // the ownership of the constructed CFG is passed to the caller.
- CFG* t = cfg;
- cfg = NULL;
- return t;
-}
-
-/// createBlock - Used to lazily create blocks that are connected
-/// to the current (global) succcessor.
-CFGBlock* CFGBuilder::createBlock(bool add_successor) {
- CFGBlock* B = cfg->createBlock();
- if (add_successor && Succ) B->addSuccessor(Succ);
- return B;
-}
-
-/// FinishBlock - When the last statement has been added to the block,
-/// we must reverse the statements because they have been inserted
-/// in reverse order.
-bool CFGBuilder::FinishBlock(CFGBlock* B) {
- if (badCFG)
- return false;
-
- assert (B);
- B->reverseStmts();
- return true;
-}
-
-/// addStmt - Used to add statements/expressions to the current CFGBlock
-/// "Block". This method calls WalkAST on the passed statement to see if it
-/// contains any short-circuit expressions. If so, it recursively creates
-/// the necessary blocks for such expressions. It returns the "topmost" block
-/// of the created blocks, or the original value of "Block" when this method
-/// was called if no additional blocks are created.
-CFGBlock* CFGBuilder::addStmt(Stmt* Terminator) {
- if (!Block) Block = createBlock();
- return WalkAST(Terminator,true);
-}
-
-/// WalkAST - Used by addStmt to walk the subtree of a statement and
-/// add extra blocks for ternary operators, &&, and ||. We also
-/// process "," and DeclStmts (which may contain nested control-flow).
-CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) {
- switch (Terminator->getStmtClass()) {
- case Stmt::ConditionalOperatorClass: {
- ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
-
- // Create the confluence block that will "merge" the results
- // of the ternary expression.
- CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock();
- ConfluenceBlock->appendStmt(C);
- if (!FinishBlock(ConfluenceBlock))
- return 0;
-
- // Create a block for the LHS expression if there is an LHS expression.
- // A GCC extension allows LHS to be NULL, causing the condition to
- // be the value that is returned instead.
- // e.g: x ?: y is shorthand for: x ? x : y;
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* LHSBlock = NULL;
- if (C->getLHS()) {
- LHSBlock = Visit(C->getLHS());
- if (!FinishBlock(LHSBlock))
- return 0;
- Block = NULL;
- }
-
- // Create the block for the RHS expression.
- Succ = ConfluenceBlock;
- CFGBlock* RHSBlock = Visit(C->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
-
- // Create the block that will contain the condition.
- Block = createBlock(false);
-
- if (LHSBlock)
- Block->addSuccessor(LHSBlock);
- else {
- // If we have no LHS expression, add the ConfluenceBlock as a direct
- // successor for the block containing the condition. Moreover,
- // we need to reverse the order of the predecessors in the
- // ConfluenceBlock because the RHSBlock will have been added to
- // the succcessors already, and we want the first predecessor to the
- // the block containing the expression for the case when the ternary
- // expression evaluates to true.
- Block->addSuccessor(ConfluenceBlock);
- assert (ConfluenceBlock->pred_size() == 2);
- std::reverse(ConfluenceBlock->pred_begin(),
- ConfluenceBlock->pred_end());
- }
-
- Block->addSuccessor(RHSBlock);
-
- Block->setTerminator(C);
- return addStmt(C->getCond());
- }
-
- case Stmt::ChooseExprClass: {
- ChooseExpr* C = cast<ChooseExpr>(Terminator);
-
- CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- ConfluenceBlock->appendStmt(C);
- if (!FinishBlock(ConfluenceBlock))
- return 0;
-
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* LHSBlock = Visit(C->getLHS());
- if (!FinishBlock(LHSBlock))
- return 0;
-
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* RHSBlock = Visit(C->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
-
- Block = createBlock(false);
- Block->addSuccessor(LHSBlock);
- Block->addSuccessor(RHSBlock);
- Block->setTerminator(C);
- return addStmt(C->getCond());
- }
-
- case Stmt::DeclStmtClass: {
- DeclStmt *DS = cast<DeclStmt>(Terminator);
- if (DS->isSingleDecl()) {
- Block->appendStmt(Terminator);
- return WalkAST_VisitDeclSubExpr(DS->getSingleDecl());
- }
-
- CFGBlock* B = 0;
-
- // FIXME: Add a reverse iterator for DeclStmt to avoid this
- // extra copy.
- typedef llvm::SmallVector<Decl*,10> BufTy;
- BufTy Buf(DS->decl_begin(), DS->decl_end());
-
- for (BufTy::reverse_iterator I=Buf.rbegin(), E=Buf.rend(); I!=E; ++I) {
- // Get the alignment of the new DeclStmt, padding out to >=8 bytes.
- unsigned A = llvm::AlignOf<DeclStmt>::Alignment < 8
- ? 8 : llvm::AlignOf<DeclStmt>::Alignment;
-
- // Allocate the DeclStmt using the BumpPtrAllocator. It will
- // get automatically freed with the CFG.
- DeclGroupRef DG(*I);
- Decl* D = *I;
- void* Mem = cfg->getAllocator().Allocate(sizeof(DeclStmt), A);
-
- DeclStmt* DS = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D));
-
- // Append the fake DeclStmt to block.
- Block->appendStmt(DS);
- B = WalkAST_VisitDeclSubExpr(D);
- }
- return B;
- }
-
- case Stmt::AddrLabelExprClass: {
- AddrLabelExpr* A = cast<AddrLabelExpr>(Terminator);
- AddressTakenLabels.insert(A->getLabel());
-
- if (AlwaysAddStmt) Block->appendStmt(Terminator);
- return Block;
- }
-
- case Stmt::StmtExprClass:
- return WalkAST_VisitStmtExpr(cast<StmtExpr>(Terminator));
-
- case Stmt::SizeOfAlignOfExprClass: {
- SizeOfAlignOfExpr* E = cast<SizeOfAlignOfExpr>(Terminator);
-
- // VLA types have expressions that must be evaluated.
- if (E->isArgumentType()) {
- for (VariableArrayType* VA = FindVA(E->getArgumentType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
- addStmt(VA->getSizeExpr());
- }
- // Expressions in sizeof/alignof are not evaluated and thus have no
- // control flow.
- else
- Block->appendStmt(Terminator);
-
- return Block;
- }
-
- case Stmt::BinaryOperatorClass: {
- BinaryOperator* B = cast<BinaryOperator>(Terminator);
-
- if (B->isLogicalOp()) { // && or ||
- CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock();
- ConfluenceBlock->appendStmt(B);
- if (!FinishBlock(ConfluenceBlock))
- return 0;
-
- // create the block evaluating the LHS
- CFGBlock* LHSBlock = createBlock(false);
- LHSBlock->setTerminator(B);
-
- // create the block evaluating the RHS
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* RHSBlock = Visit(B->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
-
- // Now link the LHSBlock with RHSBlock.
- if (B->getOpcode() == BinaryOperator::LOr) {
- LHSBlock->addSuccessor(ConfluenceBlock);
- LHSBlock->addSuccessor(RHSBlock);
- }
- else {
- assert (B->getOpcode() == BinaryOperator::LAnd);
- LHSBlock->addSuccessor(RHSBlock);
- LHSBlock->addSuccessor(ConfluenceBlock);
- }
-
- // Generate the blocks for evaluating the LHS.
- Block = LHSBlock;
- return addStmt(B->getLHS());
- }
- else if (B->getOpcode() == BinaryOperator::Comma) { // ,
- Block->appendStmt(B);
- addStmt(B->getRHS());
- return addStmt(B->getLHS());
- }
-
- break;
- }
-
- // Blocks: No support for blocks ... yet
- case Stmt::BlockExprClass:
- case Stmt::BlockDeclRefExprClass:
- return NYS();
-
- case Stmt::ParenExprClass:
- return WalkAST(cast<ParenExpr>(Terminator)->getSubExpr(), AlwaysAddStmt);
-
- default:
- break;
- };
-
- if (AlwaysAddStmt) Block->appendStmt(Terminator);
- return WalkAST_VisitChildren(Terminator);
-}
-
-/// WalkAST_VisitDeclSubExpr - Utility method to add block-level expressions
-/// for initializers in Decls.
-CFGBlock* CFGBuilder::WalkAST_VisitDeclSubExpr(Decl* D) {
- VarDecl* VD = dyn_cast<VarDecl>(D);
-
- if (!VD)
- return Block;
-
- Expr* Init = VD->getInit();
-
- if (Init) {
- // Optimization: Don't create separate block-level statements for literals.
- switch (Init->getStmtClass()) {
- case Stmt::IntegerLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::StringLiteralClass:
- break;
- default:
- Block = addStmt(Init);
- }
- }
-
- // If the type of VD is a VLA, then we must process its size expressions.
- for (VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); VA != 0;
- VA = FindVA(VA->getElementType().getTypePtr()))
- Block = addStmt(VA->getSizeExpr());
-
- return Block;
-}
-
-/// WalkAST_VisitChildren - Utility method to call WalkAST on the
-/// children of a Stmt.
-CFGBlock* CFGBuilder::WalkAST_VisitChildren(Stmt* Terminator) {
- CFGBlock* B = Block;
- for (Stmt::child_iterator I = Terminator->child_begin(),
- E = Terminator->child_end();
- I != E; ++I)
- if (*I) B = WalkAST(*I);
-
- return B;
-}
-
-/// WalkAST_VisitStmtExpr - Utility method to handle (nested) statement
-/// expressions (a GCC extension).
-CFGBlock* CFGBuilder::WalkAST_VisitStmtExpr(StmtExpr* Terminator) {
- Block->appendStmt(Terminator);
- return VisitCompoundStmt(Terminator->getSubStmt());
-}
-
-/// VisitStmt - Handle statements with no branching control flow.
-CFGBlock* CFGBuilder::VisitStmt(Stmt* Statement) {
- // We cannot assume that we are in the middle of a basic block, since
- // the CFG might only be constructed for this single statement. If
- // we have no current basic block, just create one lazily.
- if (!Block) Block = createBlock();
-
- // Simply add the statement to the current block. We actually
- // insert statements in reverse order; this order is reversed later
- // when processing the containing element in the AST.
- addStmt(Statement);
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitNullStmt(NullStmt* Statement) {
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
-
- CFGBlock* LastBlock = Block;
-
- for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
- I != E; ++I ) {
- LastBlock = Visit(*I);
- }
-
- return LastBlock;
-}
-
-CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
- // We may see an if statement in the middle of a basic block, or
- // it may be the first statement we are processing. In either case,
- // we create a new basic block. First, we create the blocks for
- // the then...else statements, and then we create the block containing
- // the if statement. If we were in the middle of a block, we
- // stop processing that block and reverse its statements. That block
- // is then the implicit successor for the "then" and "else" clauses.
-
- // The block we were proccessing is now finished. Make it the
- // successor block.
- if (Block) {
- Succ = Block;
- if (!FinishBlock(Block))
- return 0;
- }
-
- // Process the false branch. NULL out Block so that the recursive
- // call to Visit will create a new basic block.
- // Null out Block so that all successor
- CFGBlock* ElseBlock = Succ;
-
- if (Stmt* Else = I->getElse()) {
- SaveAndRestore<CFGBlock*> sv(Succ);
-
- // NULL out Block so that the recursive call to Visit will
- // create a new basic block.
- Block = NULL;
- ElseBlock = Visit(Else);
-
- if (!ElseBlock) // Can occur when the Else body has all NullStmts.
- ElseBlock = sv.get();
- else if (Block) {
- if (!FinishBlock(ElseBlock))
- return 0;
- }
- }
-
- // Process the true branch. NULL out Block so that the recursive
- // call to Visit will create a new basic block.
- // Null out Block so that all successor
- CFGBlock* ThenBlock;
- {
- Stmt* Then = I->getThen();
- assert (Then);
- SaveAndRestore<CFGBlock*> sv(Succ);
- Block = NULL;
- ThenBlock = Visit(Then);
-
- if (!ThenBlock) {
- // We can reach here if the "then" body has all NullStmts.
- // Create an empty block so we can distinguish between true and false
- // branches in path-sensitive analyses.
- ThenBlock = createBlock(false);
- ThenBlock->addSuccessor(sv.get());
- }
- else if (Block) {
- if (!FinishBlock(ThenBlock))
- return 0;
- }
- }
-
- // Now create a new block containing the if statement.
- Block = createBlock(false);
-
- // Set the terminator of the new block to the If statement.
- Block->setTerminator(I);
-
- // Now add the successors.
- Block->addSuccessor(ThenBlock);
- Block->addSuccessor(ElseBlock);
-
- // Add the condition as the last statement in the new block. This
- // may create new blocks as the condition may contain control-flow. Any
- // newly created blocks will be pointed to be "Block".
- return addStmt(I->getCond()->IgnoreParens());
-}
-
-
-CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
- // If we were in the middle of a block we stop processing that block
- // and reverse its statements.
- //
- // NOTE: If a "return" appears in the middle of a block, this means
- // that the code afterwards is DEAD (unreachable). We still
- // keep a basic block for that code; a simple "mark-and-sweep"
- // from the entry block will be able to report such dead
- // blocks.
- if (Block) FinishBlock(Block);
-
- // Create the new block.
- Block = createBlock(false);
-
- // The Exit block is the only successor.
- Block->addSuccessor(&cfg->getExit());
-
- // Add the return statement to the block. This may create new blocks
- // if R contains control-flow (short-circuit operations).
- return addStmt(R);
-}
-
-CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
- // Get the block of the labeled statement. Add it to our map.
- Visit(L->getSubStmt());
- CFGBlock* LabelBlock = Block;
-
- if (!LabelBlock) // This can happen when the body is empty, i.e.
- LabelBlock=createBlock(); // scopes that only contains NullStmts.
-
- assert (LabelMap.find(L) == LabelMap.end() && "label already in map");
- LabelMap[ L ] = LabelBlock;
-
- // Labels partition blocks, so this is the end of the basic block
- // we were processing (L is the block's label). Because this is
- // label (and we have already processed the substatement) there is no
- // extra control-flow to worry about.
- LabelBlock->setLabel(L);
- if (!FinishBlock(LabelBlock))
- return 0;
-
- // We set Block to NULL to allow lazy creation of a new block
- // (if necessary);
- Block = NULL;
-
- // This block is now the implicit successor of other blocks.
- Succ = LabelBlock;
-
- return LabelBlock;
-}
-
-CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) {
- // Goto is a control-flow statement. Thus we stop processing the
- // current block and create a new one.
- if (Block) FinishBlock(Block);
- Block = createBlock(false);
- Block->setTerminator(G);
-
- // If we already know the mapping to the label block add the
- // successor now.
- LabelMapTy::iterator I = LabelMap.find(G->getLabel());
-
- if (I == LabelMap.end())
- // We will need to backpatch this block later.
- BackpatchBlocks.push_back(Block);
- else
- Block->addSuccessor(I->second);
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
- // "for" is a control-flow statement. Thus we stop processing the
- // current block.
-
- CFGBlock* LoopSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- }
- else LoopSuccessor = Succ;
-
- // Because of short-circuit evaluation, the condition of the loop
- // can span multiple basic blocks. Thus we need the "Entry" and "Exit"
- // blocks that evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(F);
-
- // Now add the actual condition to the condition block. Because the
- // condition itself may contain control-flow, new blocks may be created.
- if (Stmt* C = F->getCond()) {
- Block = ExitConditionBlock;
- EntryConditionBlock = addStmt(C);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- }
- }
-
- // The condition block is the implicit successor for the loop body as
- // well as any code above the loop.
- Succ = EntryConditionBlock;
-
- // Now create the loop body.
- {
- assert (F->getBody());
-
- // Save the current values for Block, Succ, and continue and break targets
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
- save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
-
- // Create a new block to contain the (bottom) of the loop body.
- Block = NULL;
-
- if (Stmt* I = F->getInc()) {
- // Generate increment code in its own basic block. This is the target
- // of continue statements.
- Succ = Visit(I);
- }
- else {
- // No increment code. Create a special, empty, block that is used as
- // the target block for "looping back" to the start of the loop.
- assert(Succ == EntryConditionBlock);
- Succ = createBlock();
- }
-
- // Finish up the increment (or empty) block if it hasn't been already.
- if (Block) {
- assert(Block == Succ);
- if (!FinishBlock(Block))
- return 0;
- Block = 0;
- }
-
- ContinueTargetBlock = Succ;
-
- // The starting block for the loop increment is the block that should
- // represent the 'loop target' for looping back to the start of the loop.
- ContinueTargetBlock->setLoopTarget(F);
-
- // All breaks should go to the code following the loop.
- BreakTargetBlock = LoopSuccessor;
-
- // Now populate the body block, and in the process create new blocks
- // as we walk the body of the loop.
- CFGBlock* BodyBlock = Visit(F->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "for (...;...; ) ;"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // This new body block is a successor to our "exit" condition block.
- ExitConditionBlock->addSuccessor(BodyBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // If the loop contains initialization, create a new block for those
- // statements. This block can also contain statements that precede
- // the loop.
- if (Stmt* I = F->getInit()) {
- Block = createBlock();
- return addStmt(I);
- }
- else {
- // There is no loop initialization. We are thus basically a while
- // loop. NULL out Block to force lazy block construction.
- Block = NULL;
- Succ = EntryConditionBlock;
- return EntryConditionBlock;
- }
-}
-
-CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
- // Objective-C fast enumeration 'for' statements:
- // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC
- //
- // for ( Type newVariable in collection_expression ) { statements }
- //
- // becomes:
- //
- // prologue:
- // 1. collection_expression
- // T. jump to loop_entry
- // loop_entry:
- // 1. side-effects of element expression
- // 1. ObjCForCollectionStmt [performs binding to newVariable]
- // T. ObjCForCollectionStmt TB, FB [jumps to TB if newVariable != nil]
- // TB:
- // statements
- // T. jump to loop_entry
- // FB:
- // what comes after
- //
- // and
- //
- // Type existingItem;
- // for ( existingItem in expression ) { statements }
- //
- // becomes:
- //
- // the same with newVariable replaced with existingItem; the binding
- // works the same except that for one ObjCForCollectionStmt::getElement()
- // returns a DeclStmt and the other returns a DeclRefExpr.
- //
-
- CFGBlock* LoopSuccessor = 0;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- Block = 0;
- }
- else LoopSuccessor = Succ;
-
- // Build the condition blocks.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(S);
-
- // The last statement in the block should be the ObjCForCollectionStmt,
- // which performs the actual binding to 'element' and determines if there
- // are any more items in the collection.
- ExitConditionBlock->appendStmt(S);
- Block = ExitConditionBlock;
-
- // Walk the 'element' expression to see if there are any side-effects. We
- // generate new blocks as necesary. We DON'T add the statement by default
- // to the CFG unless it contains control-flow.
- EntryConditionBlock = WalkAST(S->getElement(), false);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- Block = 0;
- }
-
- // The condition block is the implicit successor for the loop body as
- // well as any code above the loop.
- Succ = EntryConditionBlock;
-
- // Now create the true branch.
- {
- // Save the current values for Succ, continue and break targets.
- SaveAndRestore<CFGBlock*> save_Succ(Succ),
- save_continue(ContinueTargetBlock), save_break(BreakTargetBlock);
-
- BreakTargetBlock = LoopSuccessor;
- ContinueTargetBlock = EntryConditionBlock;
-
- CFGBlock* BodyBlock = Visit(S->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // This new body block is a successor to our "exit" condition block.
- ExitConditionBlock->addSuccessor(BodyBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // Now create a prologue block to contain the collection expression.
- Block = createBlock();
- return addStmt(S->getCollection());
-}
-
-CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) {
- // FIXME: Add locking 'primitives' to CFG for @synchronized.
-
- // Inline the body.
- CFGBlock *SyncBlock = Visit(S->getSynchBody());
-
- // The sync body starts its own basic block. This makes it a little easier
- // for diagnostic clients.
- if (SyncBlock) {
- if (!FinishBlock(SyncBlock))
- return 0;
-
- Block = 0;
- }
-
- Succ = SyncBlock;
-
- // Inline the sync expression.
- return Visit(S->getSynchExpr());
-}
-
-CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) {
- return NYS();
-}
-
-CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
- // "while" is a control-flow statement. Thus we stop processing the
- // current block.
-
- CFGBlock* LoopSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- }
- else LoopSuccessor = Succ;
-
- // Because of short-circuit evaluation, the condition of the loop
- // can span multiple basic blocks. Thus we need the "Entry" and "Exit"
- // blocks that evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(W);
-
- // Now add the actual condition to the condition block. Because the
- // condition itself may contain control-flow, new blocks may be created.
- // Thus we update "Succ" after adding the condition.
- if (Stmt* C = W->getCond()) {
- Block = ExitConditionBlock;
- EntryConditionBlock = addStmt(C);
- assert(Block == EntryConditionBlock);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- }
- }
-
- // The condition block is the implicit successor for the loop body as
- // well as any code above the loop.
- Succ = EntryConditionBlock;
-
- // Process the loop body.
- {
- assert(W->getBody());
-
- // Save the current values for Block, Succ, and continue and break targets
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
- save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
-
- // Create an empty block to represent the transition block for looping
- // back to the head of the loop.
- Block = 0;
- assert(Succ == EntryConditionBlock);
- Succ = createBlock();
- Succ->setLoopTarget(W);
- ContinueTargetBlock = Succ;
-
- // All breaks should go to the code following the loop.
- BreakTargetBlock = LoopSuccessor;
-
- // NULL out Block to force lazy instantiation of blocks for the body.
- Block = NULL;
-
- // Create the body. The returned block is the entry to the loop body.
- CFGBlock* BodyBlock = Visit(W->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "while(...) ;"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // Add the loop body entry as a successor to the condition.
- ExitConditionBlock->addSuccessor(BodyBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // There can be no more statements in the condition block
- // since we loop back to this block. NULL out Block to force
- // lazy creation of another block.
- Block = NULL;
-
- // Return the condition block, which is the dominating block for the loop.
- Succ = EntryConditionBlock;
- return EntryConditionBlock;
-}
-
-CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) {
- // FIXME: This isn't complete. We basically treat @throw like a return
- // statement.
-
- // If we were in the middle of a block we stop processing that block
- // and reverse its statements.
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- }
-
- // Create the new block.
- Block = createBlock(false);
-
- // The Exit block is the only successor.
- Block->addSuccessor(&cfg->getExit());
-
- // Add the statement to the block. This may create new blocks
- // if S contains control-flow (short-circuit operations).
- return addStmt(S);
-}
-
-CFGBlock* CFGBuilder::VisitDoStmt(DoStmt* D) {
- // "do...while" is a control-flow statement. Thus we stop processing the
- // current block.
-
- CFGBlock* LoopSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- }
- else LoopSuccessor = Succ;
-
- // Because of short-circuit evaluation, the condition of the loop
- // can span multiple basic blocks. Thus we need the "Entry" and "Exit"
- // blocks that evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(D);
-
- // Now add the actual condition to the condition block. Because the
- // condition itself may contain control-flow, new blocks may be created.
- if (Stmt* C = D->getCond()) {
- Block = ExitConditionBlock;
- EntryConditionBlock = addStmt(C);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- }
- }
-
- // The condition block is the implicit successor for the loop body.
- Succ = EntryConditionBlock;
-
- // Process the loop body.
- CFGBlock* BodyBlock = NULL;
- {
- assert (D->getBody());
-
- // Save the current values for Block, Succ, and continue and break targets
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
- save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
-
- // All continues within this loop should go to the condition block
- ContinueTargetBlock = EntryConditionBlock;
-
- // All breaks should go to the code following the loop.
- BreakTargetBlock = LoopSuccessor;
-
- // NULL out Block to force lazy instantiation of blocks for the body.
- Block = NULL;
-
- // Create the body. The returned block is the entry to the loop body.
- BodyBlock = Visit(D->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // Add an intermediate block between the BodyBlock and the
- // ExitConditionBlock to represent the "loop back" transition.
- // Create an empty block to represent the transition block for looping
- // back to the head of the loop.
- // FIXME: Can we do this more efficiently without adding another block?
- Block = NULL;
- Succ = BodyBlock;
- CFGBlock *LoopBackBlock = createBlock();
- LoopBackBlock->setLoopTarget(D);
-
- // Add the loop body entry as a successor to the condition.
- ExitConditionBlock->addSuccessor(LoopBackBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // There can be no more statements in the body block(s)
- // since we loop back to the body. NULL out Block to force
- // lazy creation of another block.
- Block = NULL;
-
- // Return the loop body, which is the dominating block for the loop.
- Succ = BodyBlock;
- return BodyBlock;
-}
-
-CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) {
- // "continue" is a control-flow statement. Thus we stop processing the
- // current block.
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- }
-
- // Now create a new block that ends with the continue statement.
- Block = createBlock(false);
- Block->setTerminator(C);
-
- // If there is no target for the continue, then we are looking at an
- // incomplete AST. This means the CFG cannot be constructed.
- if (ContinueTargetBlock)
- Block->addSuccessor(ContinueTargetBlock);
- else
- badCFG = true;
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) {
- // "break" is a control-flow statement. Thus we stop processing the
- // current block.
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- }
-
- // Now create a new block that ends with the continue statement.
- Block = createBlock(false);
- Block->setTerminator(B);
-
- // If there is no target for the break, then we are looking at an
- // incomplete AST. This means that the CFG cannot be constructed.
- if (BreakTargetBlock)
- Block->addSuccessor(BreakTargetBlock);
- else
- badCFG = true;
-
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
- // "switch" is a control-flow statement. Thus we stop processing the
- // current block.
- CFGBlock* SwitchSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- SwitchSuccessor = Block;
- }
- else SwitchSuccessor = Succ;
-
- // Save the current "switch" context.
- SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
- save_break(BreakTargetBlock),
- save_default(DefaultCaseBlock);
-
- // Set the "default" case to be the block after the switch statement.
- // If the switch statement contains a "default:", this value will
- // be overwritten with the block for that code.
- DefaultCaseBlock = SwitchSuccessor;
-
- // Create a new block that will contain the switch statement.
- SwitchTerminatedBlock = createBlock(false);
-
- // Now process the switch body. The code after the switch is the implicit
- // successor.
- Succ = SwitchSuccessor;
- BreakTargetBlock = SwitchSuccessor;
-
- // When visiting the body, the case statements should automatically get
- // linked up to the switch. We also don't keep a pointer to the body,
- // since all control-flow from the switch goes to case/default statements.
- assert (Terminator->getBody() && "switch must contain a non-NULL body");
- Block = NULL;
- CFGBlock *BodyBlock = Visit(Terminator->getBody());
- if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // If we have no "default:" case, the default transition is to the
- // code following the switch body.
- SwitchTerminatedBlock->addSuccessor(DefaultCaseBlock);
-
- // Add the terminator and condition in the switch block.
- SwitchTerminatedBlock->setTerminator(Terminator);
- assert (Terminator->getCond() && "switch condition must be non-NULL");
- Block = SwitchTerminatedBlock;
-
- return addStmt(Terminator->getCond());
-}
-
-CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* Terminator) {
- // CaseStmts are essentially labels, so they are the
- // first statement in a block.
-
- if (Terminator->getSubStmt()) Visit(Terminator->getSubStmt());
- CFGBlock* CaseBlock = Block;
- if (!CaseBlock) CaseBlock = createBlock();
-
- // Cases statements partition blocks, so this is the top of
- // the basic block we were processing (the "case XXX:" is the label).
- CaseBlock->setLabel(Terminator);
- if (!FinishBlock(CaseBlock))
- return 0;
-
- // Add this block to the list of successors for the block with the
- // switch statement.
- assert (SwitchTerminatedBlock);
- SwitchTerminatedBlock->addSuccessor(CaseBlock);
-
- // We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
-
- // This block is now the implicit successor of other blocks.
- Succ = CaseBlock;
-
- return CaseBlock;
-}
-
-CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) {
- if (Terminator->getSubStmt()) Visit(Terminator->getSubStmt());
- DefaultCaseBlock = Block;
- if (!DefaultCaseBlock) DefaultCaseBlock = createBlock();
-
- // Default statements partition blocks, so this is the top of
- // the basic block we were processing (the "default:" is the label).
- DefaultCaseBlock->setLabel(Terminator);
- if (!FinishBlock(DefaultCaseBlock))
- return 0;
-
- // Unlike case statements, we don't add the default block to the
- // successors for the switch statement immediately. This is done
- // when we finish processing the switch statement. This allows for
- // the default case (including a fall-through to the code after the
- // switch statement) to always be the last successor of a switch-terminated
- // block.
-
- // We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
-
- // This block is now the implicit successor of other blocks.
- Succ = DefaultCaseBlock;
-
- return DefaultCaseBlock;
-}
-
-CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) {
- // Lazily create the indirect-goto dispatch block if there isn't one
- // already.
- CFGBlock* IBlock = cfg->getIndirectGotoBlock();
-
- if (!IBlock) {
- IBlock = createBlock(false);
- cfg->setIndirectGotoBlock(IBlock);
- }
-
- // IndirectGoto is a control-flow statement. Thus we stop processing the
- // current block and create a new one.
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- }
- Block = createBlock(false);
- Block->setTerminator(I);
- Block->addSuccessor(IBlock);
- return addStmt(I->getTarget());
-}
-
-
-} // end anonymous namespace
-
-/// createBlock - Constructs and adds a new CFGBlock to the CFG. The
-/// block has no successors or predecessors. If this is the first block
-/// created in the CFG, it is automatically set to be the Entry and Exit
-/// of the CFG.
-CFGBlock* CFG::createBlock() {
- bool first_block = begin() == end();
-
- // Create the block.
- Blocks.push_front(CFGBlock(NumBlockIDs++));
-
- // If this is the first block, set it as the Entry and Exit.
- if (first_block) Entry = Exit = &front();
-
- // Return the block.
- return &front();
-}
-
-/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
-/// CFG is returned to the caller.
-CFG* CFG::buildCFG(Stmt* Statement) {
- CFGBuilder Builder;
- return Builder.buildCFG(Statement);
-}
-
-/// reverseStmts - Reverses the orders of statements within a CFGBlock.
-void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); }
-
-//===----------------------------------------------------------------------===//
-// CFG: Queries for BlkExprs.
-//===----------------------------------------------------------------------===//
-
-namespace {
- typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
-}
-
-static void FindSubExprAssignments(Stmt* Terminator, llvm::SmallPtrSet<Expr*,50>& Set) {
- if (!Terminator)
- return;
-
- for (Stmt::child_iterator I=Terminator->child_begin(), E=Terminator->child_end(); I!=E; ++I) {
- if (!*I) continue;
-
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(*I))
- if (B->isAssignmentOp()) Set.insert(B);
-
- FindSubExprAssignments(*I, Set);
- }
-}
-
-static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
- BlkExprMapTy* M = new BlkExprMapTy();
-
- // Look for assignments that are used as subexpressions. These are the
- // only assignments that we want to *possibly* register as a block-level
- // expression. Basically, if an assignment occurs both in a subexpression
- // and at the block-level, it is a block-level expression.
- llvm::SmallPtrSet<Expr*,50> SubExprAssignments;
-
- for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
- for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI)
- FindSubExprAssignments(*BI, SubExprAssignments);
-
- for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
-
- // Iterate over the statements again on identify the Expr* and Stmt* at
- // the block-level that are block-level expressions.
-
- for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI)
- if (Expr* Exp = dyn_cast<Expr>(*BI)) {
-
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
- // Assignment expressions that are not nested within another
- // expression are really "statements" whose value is never
- // used by another expression.
- if (B->isAssignmentOp() && !SubExprAssignments.count(Exp))
- continue;
- }
- else if (const StmtExpr* Terminator = dyn_cast<StmtExpr>(Exp)) {
- // Special handling for statement expressions. The last statement
- // in the statement expression is also a block-level expr.
- const CompoundStmt* C = Terminator->getSubStmt();
- if (!C->body_empty()) {
- unsigned x = M->size();
- (*M)[C->body_back()] = x;
- }
- }
-
- unsigned x = M->size();
- (*M)[Exp] = x;
- }
-
- // Look at terminators. The condition is a block-level expression.
-
- Stmt* S = I->getTerminatorCondition();
-
- if (S && M->find(S) == M->end()) {
- unsigned x = M->size();
- (*M)[S] = x;
- }
- }
-
- return M;
-}
-
-CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) {
- assert(S != NULL);
- if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
-
- BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
- BlkExprMapTy::iterator I = M->find(S);
-
- if (I == M->end()) return CFG::BlkExprNumTy();
- else return CFG::BlkExprNumTy(I->second);
-}
-
-unsigned CFG::getNumBlkExprs() {
- if (const BlkExprMapTy* M = reinterpret_cast<const BlkExprMapTy*>(BlkExprMap))
- return M->size();
- else {
- // We assume callers interested in the number of BlkExprs will want
- // the map constructed if it doesn't already exist.
- BlkExprMap = (void*) PopulateBlkExprMap(*this);
- return reinterpret_cast<BlkExprMapTy*>(BlkExprMap)->size();
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Cleanup: CFG dstor.
-//===----------------------------------------------------------------------===//
-
-CFG::~CFG() {
- delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap);
-}
-
-//===----------------------------------------------------------------------===//
-// CFG pretty printing
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper {
-
- typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
- StmtMapTy StmtMap;
- signed CurrentBlock;
- unsigned CurrentStmt;
- const LangOptions &LangOpts;
-public:
-
- StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
- : CurrentBlock(0), CurrentStmt(0), LangOpts(LO) {
- for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
- unsigned j = 1;
- for (CFGBlock::const_iterator BI = I->begin(), BEnd = I->end() ;
- BI != BEnd; ++BI, ++j )
- StmtMap[*BI] = std::make_pair(I->getBlockID(),j);
- }
- }
-
- virtual ~StmtPrinterHelper() {}
-
- const LangOptions &getLangOpts() const { return LangOpts; }
- void setBlockID(signed i) { CurrentBlock = i; }
- void setStmtID(unsigned i) { CurrentStmt = i; }
-
- virtual bool handledStmt(Stmt* Terminator, llvm::raw_ostream& OS) {
-
- StmtMapTy::iterator I = StmtMap.find(Terminator);
-
- if (I == StmtMap.end())
- return false;
-
- if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock
- && I->second.second == CurrentStmt)
- return false;
-
- OS << "[B" << I->second.first << "." << I->second.second << "]";
- return true;
- }
-};
-} // end anonymous namespace
-
-
-namespace {
-class VISIBILITY_HIDDEN CFGBlockTerminatorPrint
- : public StmtVisitor<CFGBlockTerminatorPrint,void> {
-
- llvm::raw_ostream& OS;
- StmtPrinterHelper* Helper;
- PrintingPolicy Policy;
-
-public:
- CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper,
- const PrintingPolicy &Policy)
- : OS(os), Helper(helper), Policy(Policy) {}
-
- void VisitIfStmt(IfStmt* I) {
- OS << "if ";
- I->getCond()->printPretty(OS,Helper,Policy);
- }
-
- // Default case.
- void VisitStmt(Stmt* Terminator) { Terminator->printPretty(OS, Helper, Policy); }
-
- void VisitForStmt(ForStmt* F) {
- OS << "for (" ;
- if (F->getInit()) OS << "...";
- OS << "; ";
- if (Stmt* C = F->getCond()) C->printPretty(OS, Helper, Policy);
- OS << "; ";
- if (F->getInc()) OS << "...";
- OS << ")";
- }
-
- void VisitWhileStmt(WhileStmt* W) {
- OS << "while " ;
- if (Stmt* C = W->getCond()) C->printPretty(OS, Helper, Policy);
- }
-
- void VisitDoStmt(DoStmt* D) {
- OS << "do ... while ";
- if (Stmt* C = D->getCond()) C->printPretty(OS, Helper, Policy);
- }
-
- void VisitSwitchStmt(SwitchStmt* Terminator) {
- OS << "switch ";
- Terminator->getCond()->printPretty(OS, Helper, Policy);
- }
-
- void VisitConditionalOperator(ConditionalOperator* C) {
- C->getCond()->printPretty(OS, Helper, Policy);
- OS << " ? ... : ...";
- }
-
- void VisitChooseExpr(ChooseExpr* C) {
- OS << "__builtin_choose_expr( ";
- C->getCond()->printPretty(OS, Helper, Policy);
- OS << " )";
- }
-
- void VisitIndirectGotoStmt(IndirectGotoStmt* I) {
- OS << "goto *";
- I->getTarget()->printPretty(OS, Helper, Policy);
- }
-
- void VisitBinaryOperator(BinaryOperator* B) {
- if (!B->isLogicalOp()) {
- VisitExpr(B);
- return;
- }
-
- B->getLHS()->printPretty(OS, Helper, Policy);
-
- switch (B->getOpcode()) {
- case BinaryOperator::LOr:
- OS << " || ...";
- return;
- case BinaryOperator::LAnd:
- OS << " && ...";
- return;
- default:
- assert(false && "Invalid logical operator.");
- }
- }
-
- void VisitExpr(Expr* E) {
- E->printPretty(OS, Helper, Policy);
- }
-};
-} // end anonymous namespace
-
-
-static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
- Stmt* Terminator) {
- if (Helper) {
- // special printing for statement-expressions.
- if (StmtExpr* SE = dyn_cast<StmtExpr>(Terminator)) {
- CompoundStmt* Sub = SE->getSubStmt();
-
- if (Sub->child_begin() != Sub->child_end()) {
- OS << "({ ... ; ";
- Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS);
- OS << " })\n";
- return;
- }
- }
-
- // special printing for comma expressions.
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(Terminator)) {
- if (B->getOpcode() == BinaryOperator::Comma) {
- OS << "... , ";
- Helper->handledStmt(B->getRHS(),OS);
- OS << '\n';
- return;
- }
- }
- }
-
- Terminator->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts()));
-
- // Expressions need a newline.
- if (isa<Expr>(Terminator)) OS << '\n';
-}
-
-static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
- const CFGBlock& B,
- StmtPrinterHelper* Helper, bool print_edges) {
-
- if (Helper) Helper->setBlockID(B.getBlockID());
-
- // Print the header.
- OS << "\n [ B" << B.getBlockID();
-
- if (&B == &cfg->getEntry())
- OS << " (ENTRY) ]\n";
- else if (&B == &cfg->getExit())
- OS << " (EXIT) ]\n";
- else if (&B == cfg->getIndirectGotoBlock())
- OS << " (INDIRECT GOTO DISPATCH) ]\n";
- else
- OS << " ]\n";
-
- // Print the label of this block.
- if (Stmt* Terminator = const_cast<Stmt*>(B.getLabel())) {
-
- if (print_edges)
- OS << " ";
-
- if (LabelStmt* L = dyn_cast<LabelStmt>(Terminator))
- OS << L->getName();
- else if (CaseStmt* C = dyn_cast<CaseStmt>(Terminator)) {
- OS << "case ";
- C->getLHS()->printPretty(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
- if (C->getRHS()) {
- OS << " ... ";
- C->getRHS()->printPretty(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
- }
- }
- else if (isa<DefaultStmt>(Terminator))
- OS << "default";
- else
- assert(false && "Invalid label statement in CFGBlock.");
-
- OS << ":\n";
- }
-
- // Iterate through the statements in the block and print them.
- unsigned j = 1;
-
- for (CFGBlock::const_iterator I = B.begin(), E = B.end() ;
- I != E ; ++I, ++j ) {
-
- // Print the statement # in the basic block and the statement itself.
- if (print_edges)
- OS << " ";
-
- OS << llvm::format("%3d", j) << ": ";
-
- if (Helper)
- Helper->setStmtID(j);
-
- print_stmt(OS,Helper,*I);
- }
-
- // Print the terminator of this block.
- if (B.getTerminator()) {
- if (print_edges)
- OS << " ";
-
- OS << " T: ";
-
- if (Helper) Helper->setBlockID(-1);
-
- CFGBlockTerminatorPrint TPrinter(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
- TPrinter.Visit(const_cast<Stmt*>(B.getTerminator()));
- OS << '\n';
- }
-
- if (print_edges) {
- // Print the predecessors of this block.
- OS << " Predecessors (" << B.pred_size() << "):";
- unsigned i = 0;
-
- for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end();
- I != E; ++I, ++i) {
-
- if (i == 8 || (i-8) == 0)
- OS << "\n ";
-
- OS << " B" << (*I)->getBlockID();
- }
-
- OS << '\n';
-
- // Print the successors of this block.
- OS << " Successors (" << B.succ_size() << "):";
- i = 0;
-
- for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end();
- I != E; ++I, ++i) {
-
- if (i == 8 || (i-8) % 10 == 0)
- OS << "\n ";
-
- OS << " B" << (*I)->getBlockID();
- }
-
- OS << '\n';
- }
-}
-
-
-/// dump - A simple pretty printer of a CFG that outputs to stderr.
-void CFG::dump(const LangOptions &LO) const { print(llvm::errs(), LO); }
-
-/// print - A simple pretty printer of a CFG that outputs to an ostream.
-void CFG::print(llvm::raw_ostream &OS, const LangOptions &LO) const {
- StmtPrinterHelper Helper(this, LO);
-
- // Print the entry block.
- print_block(OS, this, getEntry(), &Helper, true);
-
- // Iterate through the CFGBlocks and print them one by one.
- for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
- // Skip the entry block, because we already printed it.
- if (&(*I) == &getEntry() || &(*I) == &getExit())
- continue;
-
- print_block(OS, this, *I, &Helper, true);
- }
-
- // Print the exit block.
- print_block(OS, this, getExit(), &Helper, true);
- OS.flush();
-}
-
-/// dump - A simply pretty printer of a CFGBlock that outputs to stderr.
-void CFGBlock::dump(const CFG* cfg, const LangOptions &LO) const {
- print(llvm::errs(), cfg, LO);
-}
-
-/// print - A simple pretty printer of a CFGBlock that outputs to an ostream.
-/// Generally this will only be called from CFG::print.
-void CFGBlock::print(llvm::raw_ostream& OS, const CFG* cfg,
- const LangOptions &LO) const {
- StmtPrinterHelper Helper(cfg, LO);
- print_block(OS, cfg, *this, &Helper, true);
-}
-
-/// printTerminator - A simple pretty printer of the terminator of a CFGBlock.
-void CFGBlock::printTerminator(llvm::raw_ostream &OS,
- const LangOptions &LO) const {
- CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO));
- TPrinter.Visit(const_cast<Stmt*>(getTerminator()));
-}
-
-Stmt* CFGBlock::getTerminatorCondition() {
-
- if (!Terminator)
- return NULL;
-
- Expr* E = NULL;
-
- switch (Terminator->getStmtClass()) {
- default:
- break;
-
- case Stmt::ForStmtClass:
- E = cast<ForStmt>(Terminator)->getCond();
- break;
-
- case Stmt::WhileStmtClass:
- E = cast<WhileStmt>(Terminator)->getCond();
- break;
-
- case Stmt::DoStmtClass:
- E = cast<DoStmt>(Terminator)->getCond();
- break;
-
- case Stmt::IfStmtClass:
- E = cast<IfStmt>(Terminator)->getCond();
- break;
-
- case Stmt::ChooseExprClass:
- E = cast<ChooseExpr>(Terminator)->getCond();
- break;
-
- case Stmt::IndirectGotoStmtClass:
- E = cast<IndirectGotoStmt>(Terminator)->getTarget();
- break;
-
- case Stmt::SwitchStmtClass:
- E = cast<SwitchStmt>(Terminator)->getCond();
- break;
-
- case Stmt::ConditionalOperatorClass:
- E = cast<ConditionalOperator>(Terminator)->getCond();
- break;
-
- case Stmt::BinaryOperatorClass: // '&&' and '||'
- E = cast<BinaryOperator>(Terminator)->getLHS();
- break;
-
- case Stmt::ObjCForCollectionStmtClass:
- return Terminator;
- }
-
- return E ? E->IgnoreParens() : NULL;
-}
-
-bool CFGBlock::hasBinaryBranchTerminator() const {
-
- if (!Terminator)
- return false;
-
- Expr* E = NULL;
-
- switch (Terminator->getStmtClass()) {
- default:
- return false;
-
- case Stmt::ForStmtClass:
- case Stmt::WhileStmtClass:
- case Stmt::DoStmtClass:
- case Stmt::IfStmtClass:
- case Stmt::ChooseExprClass:
- case Stmt::ConditionalOperatorClass:
- case Stmt::BinaryOperatorClass:
- return true;
- }
-
- return E ? E->IgnoreParens() : NULL;
-}
-
-
-//===----------------------------------------------------------------------===//
-// CFG Graphviz Visualization
-//===----------------------------------------------------------------------===//
-
-
-#ifndef NDEBUG
-static StmtPrinterHelper* GraphHelper;
-#endif
-
-void CFG::viewCFG(const LangOptions &LO) const {
-#ifndef NDEBUG
- StmtPrinterHelper H(this, LO);
- GraphHelper = &H;
- llvm::ViewGraph(this,"CFG");
- GraphHelper = NULL;
-#endif
-}
-
-namespace llvm {
-template<>
-struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
- static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph,
- bool ShortNames) {
-
-#ifndef NDEBUG
- std::string OutSStr;
- llvm::raw_string_ostream Out(OutSStr);
- print_block(Out,Graph, *Node, GraphHelper, false);
- std::string& OutStr = Out.str();
-
- if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
-
- // Process string output to make it nicer...
- for (unsigned i = 0; i != OutStr.length(); ++i)
- if (OutStr[i] == '\n') { // Left justify
- OutStr[i] = '\\';
- OutStr.insert(OutStr.begin()+i+1, 'l');
- }
-
- return OutStr;
-#else
- return "";
-#endif
- }
-};
-} // end namespace llvm
diff --git a/lib/Frontend/ResolveLocation.cpp b/lib/Frontend/ResolveLocation.cpp
deleted file mode 100644
index d7a9b4852a96f..0000000000000
--- a/lib/Frontend/ResolveLocation.cpp
+++ /dev/null
@@ -1,322 +0,0 @@
-//===--- ResolveLocation.cpp - Source location resolver ---------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines the ResolveLocationInAST function, which resolves a
-// source location into a <Decl *, Stmt *> pair.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/Utils.h"
-#include "clang/AST/DeclVisitor.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/Compiler.h"
-using namespace clang;
-
-namespace {
-
-/// \brief Base for the LocResolver classes. Mostly does source range checking.
-class VISIBILITY_HIDDEN LocResolverBase {
-protected:
- ASTContext &Ctx;
- SourceLocation Loc;
-
- Decl *Dcl;
- Stmt *Stm;
- bool PassedLoc;
-
- /// \brief Checks whether Loc is in the source range of 'D'.
- ///
- /// If it is, updates Dcl. If Loc is passed the source range, it sets
- /// PassedLoc, otherwise it does nothing.
- void CheckRange(Decl *D);
-
- /// \brief Checks whether Loc is in the source range of 'Node'.
- ///
- /// If it is, updates Stm. If Loc is passed the source range, it sets
- /// PassedLoc, otherwise it does nothing.
- void CheckRange(Stmt *Node);
-
- /// \brief Updates the end source range to cover the full length of the token
- /// positioned at the end of the source range.
- ///
- /// e.g.,
- /// @code
- /// int foo
- /// ^ ^
- /// @endcode
- /// will be updated to
- /// @code
- /// int foo
- /// ^ ^
- /// @endcode
- void FixRange(SourceRange &Range);
-
-public:
- LocResolverBase(ASTContext &ctx, SourceLocation loc)
- : Ctx(ctx), Loc(loc), Dcl(0), Stm(0), PassedLoc(0) {}
-
- /// \brief We found a AST node that corresponds to the source location.
- bool FoundIt() const { return Dcl != 0 || Stm != 0; }
-
- /// \brief We either found a AST node or we passed the source location while
- /// searching.
- bool Finished() const { return FoundIt() || PassedLoc; }
-
- Decl *getDecl() const { return Dcl; }
- Stmt *getStmt() const { return Stm; }
-
- std::pair<Decl *, Stmt *> getResult() const {
- return std::make_pair(getDecl(), getStmt());
- }
-
- /// \brief Debugging output.
- void print(Decl *D);
- /// \brief Debugging output.
- void print(Stmt *Node);
-};
-
-/// \brief Searches a statement for the AST node that corresponds to a source
-/// location.
-class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase,
- public StmtVisitor<StmtLocResolver> {
-public:
- StmtLocResolver(ASTContext &ctx, SourceLocation loc)
- : LocResolverBase(ctx, loc) {}
-
- void VisitDeclStmt(DeclStmt *Node);
- void VisitStmt(Stmt *Node);
-};
-
-/// \brief Searches a declaration for the AST node that corresponds to a source
-/// location.
-class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase,
- public DeclVisitor<DeclLocResolver> {
-public:
- DeclLocResolver(ASTContext &ctx, SourceLocation loc)
- : LocResolverBase(ctx, loc) {}
-
- void VisitDeclContext(DeclContext *DC);
- void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
- void VisitVarDecl(VarDecl *D);
- void VisitFunctionDecl(FunctionDecl *D);
- void VisitDecl(Decl *D);
-};
-
-} // anonymous namespace
-
-void StmtLocResolver::VisitDeclStmt(DeclStmt *Node) {
- CheckRange(Node);
- if (!FoundIt())
- return;
- assert(Stm == Node && "Result not updated ?");
-
- // Search all declarations of this DeclStmt. If we found the one corresponding
- // to the source location, update this StmtLocResolver's result.
- DeclLocResolver DLR(Ctx, Loc);
- for (DeclStmt::decl_iterator
- I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) {
- DLR.Visit(*I);
- if (DLR.Finished()) {
- if (DLR.FoundIt())
- llvm::tie(Dcl, Stm) = DLR.getResult();
- return;
- }
- }
-}
-
-void StmtLocResolver::VisitStmt(Stmt *Node) {
- CheckRange(Node);
- if (!FoundIt())
- return;
- assert(Stm == Node && "Result not updated ?");
-
- // Search the child statements.
- StmtLocResolver SLR(Ctx, Loc);
- for (Stmt::child_iterator
- I = Node->child_begin(), E = Node->child_end(); I != E; ++I) {
- SLR.Visit(*I);
- if (!SLR.Finished())
- continue;
-
- // We either found it or we passed the source location.
-
- if (SLR.FoundIt()) {
- // Only update Dcl if we found another more immediate 'parent' Decl for
- // the statement.
- if (SLR.getDecl())
- Dcl = SLR.getDecl();
- Stm = SLR.getStmt();
- }
-
- return;
- }
-}
-
-void DeclLocResolver::VisitDeclContext(DeclContext *DC) {
- DeclLocResolver DLR(Ctx, Loc);
- for (DeclContext::decl_iterator
- I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
- DLR.Visit(*I);
- if (DLR.Finished()) {
- if (DLR.FoundIt())
- llvm::tie(Dcl, Stm) = DLR.getResult();
- return;
- }
- }
-}
-
-void DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
- VisitDeclContext(TU);
-}
-
-void DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
- CheckRange(D);
- if (!FoundIt())
- return;
- assert(Dcl == D && "Result not updated ?");
-
- // First, search through the parameters of the function.
- DeclLocResolver ParmRes(Ctx, Loc);
- for (FunctionDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I) {
- ParmRes.Visit(*I);
- if (ParmRes.Finished()) {
- if (ParmRes.FoundIt())
- llvm::tie(Dcl, Stm) = ParmRes.getResult();
- return;
- }
- }
-
- // We didn't found the location in the parameters and we didn't get passed it.
-
- // Second, search through the declarations that are part of the function.
- // If we find he location there, we won't have to search through its body.
- DeclLocResolver DLR(Ctx, Loc);
- DLR.VisitDeclContext(D);
- if (DLR.FoundIt()) {
- llvm::tie(Dcl, Stm) = DLR.getResult();
- return;
- }
-
- // We didn't find a declaration that corresponds to the source location.
-
- // Finally, search through the body of the function.
- if (D->isThisDeclarationADefinition()) {
- StmtLocResolver SLR(Ctx, Loc);
- SLR.Visit(D->getBody());
- if (SLR.FoundIt()) {
- llvm::tie(Dcl, Stm) = SLR.getResult();
- // If we didn't find a more immediate 'parent' declaration for the
- // statement, set the function as the parent.
- if (Dcl == 0)
- Dcl = D;
- }
- }
-}
-
-void DeclLocResolver::VisitVarDecl(VarDecl *D) {
- CheckRange(D);
- if (!FoundIt())
- return;
- assert(Dcl == D && "Result not updated ?");
-
- // Check whether the location points to the init expression.
- if (D->getInit()) {
- StmtLocResolver SLR(Ctx, Loc);
- SLR.Visit(D->getInit());
- Stm = SLR.getStmt();
- }
-}
-
-void DeclLocResolver::VisitDecl(Decl *D) {
- CheckRange(D);
-}
-
-void LocResolverBase::CheckRange(Decl *D) {
- SourceRange Range = D->getSourceRange();
- if (!Range.isValid())
- return;
-
- FixRange(Range);
-
- SourceManager &SourceMgr = Ctx.getSourceManager();
- if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
- return;
-
- if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
- PassedLoc = true;
- else
- Dcl = D;
-}
-
-void LocResolverBase::CheckRange(Stmt *Node) {
- SourceRange Range = Node->getSourceRange();
- if (!Range.isValid())
- return;
-
- FixRange(Range);
-
- SourceManager &SourceMgr = Ctx.getSourceManager();
- if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc))
- return;
-
- if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin()))
- PassedLoc = true;
- else
- Stm = Node;
-}
-
-void LocResolverBase::FixRange(SourceRange &Range) {
- if (!Range.isValid())
- return;
-
- unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
- Ctx.getSourceManager(),
- Ctx.getLangOptions());
- Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1));
-}
-
-void LocResolverBase::print(Decl *D) {
- llvm::raw_ostream &OS = llvm::outs();
- OS << "#### DECL ####\n";
- D->print(OS);
- OS << " <";
- D->getLocStart().print(OS, Ctx.getSourceManager());
- OS << " > - <";
- D->getLocEnd().print(OS, Ctx.getSourceManager());
- OS << ">\n\n";
- OS.flush();
-}
-
-void LocResolverBase::print(Stmt *Node) {
- llvm::raw_ostream &OS = llvm::outs();
- OS << "#### STMT ####\n";
- Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions()));
- OS << " <";
- Node->getLocStart().print(OS, Ctx.getSourceManager());
- OS << " > - <";
- Node->getLocEnd().print(OS, Ctx.getSourceManager());
- OS << ">\n\n";
- OS.flush();
-}
-
-
-/// \brief Returns the AST node that a source location points to.
-///
-std::pair<Decl *, Stmt *>
-clang::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc) {
- if (Loc.isInvalid())
- return std::make_pair((Decl*)0, (Stmt*)0);
-
- DeclLocResolver DLR(Ctx, Loc);
- DLR.Visit(Ctx.getTranslationUnitDecl());
- return DLR.getResult();
-}
diff --git a/lib/Sema/SemaInherit.cpp b/lib/Sema/SemaInherit.cpp
deleted file mode 100644
index 2f914f14a81fa..0000000000000
--- a/lib/Sema/SemaInherit.cpp
+++ /dev/null
@@ -1,350 +0,0 @@
-//===---- SemaInherit.cpp - C++ Inheritance ---------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file provides Sema routines for C++ inheritance semantics,
-// including searching the inheritance hierarchy.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SemaInherit.h"
-#include "Sema.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeOrdering.h"
-#include <algorithm>
-#include <memory>
-#include <set>
-#include <string>
-
-using namespace clang;
-
-/// \brief Computes the set of declarations referenced by these base
-/// paths.
-void BasePaths::ComputeDeclsFound() {
- assert(NumDeclsFound == 0 && !DeclsFound &&
- "Already computed the set of declarations");
-
- std::set<NamedDecl *> Decls;
- for (BasePaths::paths_iterator Path = begin(), PathEnd = end();
- Path != PathEnd; ++Path)
- Decls.insert(*Path->Decls.first);
-
- NumDeclsFound = Decls.size();
- DeclsFound = new NamedDecl * [NumDeclsFound];
- std::copy(Decls.begin(), Decls.end(), DeclsFound);
-}
-
-BasePaths::decl_iterator BasePaths::found_decls_begin() {
- if (NumDeclsFound == 0)
- ComputeDeclsFound();
- return DeclsFound;
-}
-
-BasePaths::decl_iterator BasePaths::found_decls_end() {
- if (NumDeclsFound == 0)
- ComputeDeclsFound();
- return DeclsFound + NumDeclsFound;
-}
-
-/// isAmbiguous - Determines whether the set of paths provided is
-/// ambiguous, i.e., there are two or more paths that refer to
-/// different base class subobjects of the same type. BaseType must be
-/// an unqualified, canonical class type.
-bool BasePaths::isAmbiguous(QualType BaseType) {
- assert(BaseType->isCanonical() && "Base type must be the canonical type");
- assert(BaseType.getCVRQualifiers() == 0 && "Base type must be unqualified");
- std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType];
- return Subobjects.second + (Subobjects.first? 1 : 0) > 1;
-}
-
-/// clear - Clear out all prior path information.
-void BasePaths::clear() {
- Paths.clear();
- ClassSubobjects.clear();
- ScratchPath.clear();
- DetectedVirtual = 0;
-}
-
-/// @brief Swaps the contents of this BasePaths structure with the
-/// contents of Other.
-void BasePaths::swap(BasePaths &Other) {
- std::swap(Origin, Other.Origin);
- Paths.swap(Other.Paths);
- ClassSubobjects.swap(Other.ClassSubobjects);
- std::swap(FindAmbiguities, Other.FindAmbiguities);
- std::swap(RecordPaths, Other.RecordPaths);
- std::swap(DetectVirtual, Other.DetectVirtual);
- std::swap(DetectedVirtual, Other.DetectedVirtual);
-}
-
-/// IsDerivedFrom - Determine whether the type Derived is derived from
-/// the type Base, ignoring qualifiers on Base and Derived. This
-/// routine does not assess whether an actual conversion from a
-/// Derived* to a Base* is legal, because it does not account for
-/// ambiguous conversions or conversions to private/protected bases.
-bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
- BasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
- /*DetectVirtual=*/false);
- return IsDerivedFrom(Derived, Base, Paths);
-}
-
-/// IsDerivedFrom - Determine whether the type Derived is derived from
-/// the type Base, ignoring qualifiers on Base and Derived. This
-/// routine does not assess whether an actual conversion from a
-/// Derived* to a Base* is legal, because it does not account for
-/// ambiguous conversions or conversions to private/protected
-/// bases. This routine will use Paths to determine if there are
-/// ambiguous paths (if @c Paths.isFindingAmbiguities()) and record
-/// information about all of the paths (if @c Paths.isRecordingPaths()).
-bool Sema::IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths) {
- Derived = Context.getCanonicalType(Derived).getUnqualifiedType();
- Base = Context.getCanonicalType(Base).getUnqualifiedType();
-
- if (!Derived->isRecordType() || !Base->isRecordType())
- return false;
-
- if (Derived == Base)
- return false;
-
- Paths.setOrigin(Derived);
- return LookupInBases(cast<CXXRecordDecl>(Derived->getAsRecordType()->getDecl()),
- MemberLookupCriteria(Base), Paths);
-}
-
-/// LookupInBases - Look for something that meets the specified
-/// Criteria within the base classes of Class (or any of its base
-/// classes, transitively). This routine populates BasePaths with the
-/// list of paths that one can take to find the entity that meets the
-/// search criteria, and returns true if any such entity is found. The
-/// various options passed to the BasePath constructor will affect the
-/// behavior of this lookup, e.g., whether it finds ambiguities,
-/// records paths, or attempts to detect the use of virtual base
-/// classes.
-bool Sema::LookupInBases(CXXRecordDecl *Class,
- const MemberLookupCriteria& Criteria,
- BasePaths &Paths) {
- bool FoundPath = false;
-
- for (CXXRecordDecl::base_class_const_iterator BaseSpec = Class->bases_begin(),
- BaseSpecEnd = Class->bases_end();
- BaseSpec != BaseSpecEnd; ++BaseSpec) {
- // Find the record of the base class subobjects for this type.
- QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
- BaseType = BaseType.getUnqualifiedType();
-
- // If a base class of the class template depends on a template-parameter,
- // the base class scope is not examined during unqualified name lookup.
- // [temp.dep]p3.
- if (BaseType->isDependentType())
- continue;
-
- // Determine whether we need to visit this base class at all,
- // updating the count of subobjects appropriately.
- std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
- bool VisitBase = true;
- bool SetVirtual = false;
- if (BaseSpec->isVirtual()) {
- VisitBase = !Subobjects.first;
- Subobjects.first = true;
- if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
- // If this is the first virtual we find, remember it. If it turns out
- // there is no base path here, we'll reset it later.
- Paths.DetectedVirtual = BaseType->getAsRecordType();
- SetVirtual = true;
- }
- } else
- ++Subobjects.second;
-
- if (Paths.isRecordingPaths()) {
- // Add this base specifier to the current path.
- BasePathElement Element;
- Element.Base = &*BaseSpec;
- Element.Class = Class;
- if (BaseSpec->isVirtual())
- Element.SubobjectNumber = 0;
- else
- Element.SubobjectNumber = Subobjects.second;
- Paths.ScratchPath.push_back(Element);
- }
-
- CXXRecordDecl *BaseRecord
- = cast<CXXRecordDecl>(BaseSpec->getType()->getAsRecordType()->getDecl());
-
- // Either look at the base class type or look into the base class
- // type to see if we've found a member that meets the search
- // criteria.
- bool FoundPathToThisBase = false;
- switch (Criteria.Kind) {
- case MemberLookupCriteria::LK_Base:
- FoundPathToThisBase
- = (Context.getCanonicalType(BaseSpec->getType()) == Criteria.Base);
- break;
- case MemberLookupCriteria::LK_NamedMember:
- Paths.ScratchPath.Decls = BaseRecord->lookup(Criteria.Name);
- while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) {
- if (isAcceptableLookupResult(*Paths.ScratchPath.Decls.first,
- Criteria.NameKind, Criteria.IDNS)) {
- FoundPathToThisBase = true;
- break;
- }
- ++Paths.ScratchPath.Decls.first;
- }
- break;
- case MemberLookupCriteria::LK_OverriddenMember:
- Paths.ScratchPath.Decls =
- BaseRecord->lookup(Criteria.Method->getDeclName());
- while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) {
- if (CXXMethodDecl *MD =
- dyn_cast<CXXMethodDecl>(*Paths.ScratchPath.Decls.first)) {
- OverloadedFunctionDecl::function_iterator MatchedDecl;
- if (MD->isVirtual() &&
- !IsOverload(Criteria.Method, MD, MatchedDecl)) {
- FoundPathToThisBase = true;
- break;
- }
- }
-
- ++Paths.ScratchPath.Decls.first;
- }
- break;
- }
-
- if (FoundPathToThisBase) {
- // We've found a path that terminates that this base.
- FoundPath = true;
- if (Paths.isRecordingPaths()) {
- // We have a path. Make a copy of it before moving on.
- Paths.Paths.push_back(Paths.ScratchPath);
- } else if (!Paths.isFindingAmbiguities()) {
- // We found a path and we don't care about ambiguities;
- // return immediately.
- return FoundPath;
- }
- }
- // C++ [class.member.lookup]p2:
- // A member name f in one sub-object B hides a member name f in
- // a sub-object A if A is a base class sub-object of B. Any
- // declarations that are so hidden are eliminated from
- // consideration.
- else if (VisitBase && LookupInBases(BaseRecord, Criteria, Paths)) {
- // There is a path to a base class that meets the criteria. If we're not
- // collecting paths or finding ambiguities, we're done.
- FoundPath = true;
- if (!Paths.isFindingAmbiguities())
- return FoundPath;
- }
-
- // Pop this base specifier off the current path (if we're
- // collecting paths).
- if (Paths.isRecordingPaths())
- Paths.ScratchPath.pop_back();
- // If we set a virtual earlier, and this isn't a path, forget it again.
- if (SetVirtual && !FoundPath) {
- Paths.DetectedVirtual = 0;
- }
- }
-
- return FoundPath;
-}
-
-/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
-/// conversion (where Derived and Base are class types) is
-/// well-formed, meaning that the conversion is unambiguous (and
-/// that all of the base classes are accessible). Returns true
-/// and emits a diagnostic if the code is ill-formed, returns false
-/// otherwise. Loc is the location where this routine should point to
-/// if there is an error, and Range is the source range to highlight
-/// if there is an error.
-bool
-Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
- unsigned AmbigiousBaseConvID,
- SourceLocation Loc, SourceRange Range,
- DeclarationName Name) {
- // First, determine whether the path from Derived to Base is
- // ambiguous. This is slightly more expensive than checking whether
- // the Derived to Base conversion exists, because here we need to
- // explore multiple paths to determine if there is an ambiguity.
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
- bool DerivationOkay = IsDerivedFrom(Derived, Base, Paths);
- assert(DerivationOkay &&
- "Can only be used with a derived-to-base conversion");
- (void)DerivationOkay;
-
- if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- // Check that the base class can be accessed.
- return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
- Name);
- }
-
- // We know that the derived-to-base conversion is ambiguous, and
- // we're going to produce a diagnostic. Perform the derived-to-base
- // search just one more time to compute all of the possible paths so
- // that we can print them out. This is more expensive than any of
- // the previous derived-to-base checks we've done, but at this point
- // performance isn't as much of an issue.
- Paths.clear();
- Paths.setRecordingPaths(true);
- bool StillOkay = IsDerivedFrom(Derived, Base, Paths);
- assert(StillOkay && "Can only be used with a derived-to-base conversion");
- (void)StillOkay;
-
- // Build up a textual representation of the ambiguous paths, e.g.,
- // D -> B -> A, that will be used to illustrate the ambiguous
- // conversions in the diagnostic. We only print one of the paths
- // to each base class subobject.
- std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
-
- Diag(Loc, AmbigiousBaseConvID)
- << Derived << Base << PathDisplayStr << Range << Name;
- return true;
-}
-
-bool
-Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- SourceLocation Loc, SourceRange Range) {
- return CheckDerivedToBaseConversion(Derived, Base,
- diag::err_conv_to_inaccessible_base,
- diag::err_ambiguous_derived_to_base_conv,
- Loc, Range, DeclarationName());
-}
-
-
-/// @brief Builds a string representing ambiguous paths from a
-/// specific derived class to different subobjects of the same base
-/// class.
-///
-/// This function builds a string that can be used in error messages
-/// to show the different paths that one can take through the
-/// inheritance hierarchy to go from the derived class to different
-/// subobjects of a base class. The result looks something like this:
-/// @code
-/// struct D -> struct B -> struct A
-/// struct D -> struct C -> struct A
-/// @endcode
-std::string Sema::getAmbiguousPathsDisplayString(BasePaths &Paths) {
- std::string PathDisplayStr;
- std::set<unsigned> DisplayedPaths;
- for (BasePaths::paths_iterator Path = Paths.begin();
- Path != Paths.end(); ++Path) {
- if (DisplayedPaths.insert(Path->back().SubobjectNumber).second) {
- // We haven't displayed a path to this particular base
- // class subobject yet.
- PathDisplayStr += "\n ";
- PathDisplayStr += Paths.getOrigin().getAsString();
- for (BasePath::const_iterator Element = Path->begin();
- Element != Path->end(); ++Element)
- PathDisplayStr += " -> " + Element->Base->getType().getAsString();
- }
- }
-
- return PathDisplayStr;
-}
diff --git a/lib/Sema/SemaInherit.h b/lib/Sema/SemaInherit.h
deleted file mode 100644
index b1e791a17ba34..0000000000000
--- a/lib/Sema/SemaInherit.h
+++ /dev/null
@@ -1,248 +0,0 @@
-//===------ SemaInherit.h - C++ Inheritance ---------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file provides Sema data structures that help analyse C++
-// inheritance semantics, including searching the inheritance
-// hierarchy.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_SEMA_INHERIT_H
-#define LLVM_CLANG_SEMA_INHERIT_H
-
-#include "Sema.h"
-#include "clang/AST/DeclarationName.h"
-#include "clang/AST/DeclBase.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeOrdering.h"
-#include "llvm/ADT/SmallVector.h"
-#include <list>
-#include <map>
-
-namespace clang {
- class CXXBaseSpecifier;
-
- /// BasePathElement - An element in a path from a derived class to a
- /// base class. Each step in the path references the link from a
- /// derived class to one of its direct base classes, along with a
- /// base "number" that identifies which base subobject of the
- /// original derived class we are referencing.
- struct BasePathElement {
- /// Base - The base specifier that states the link from a derived
- /// class to a base class, which will be followed by this base
- /// path element.
- const CXXBaseSpecifier *Base;
-
- /// Class - The record decl of the class that the base is a base of.
- const CXXRecordDecl *Class;
-
- /// SubobjectNumber - Identifies which base class subobject (of type
- /// @c Base->getType()) this base path element refers to. This
- /// value is only valid if @c !Base->isVirtual(), because there
- /// is no base numbering for the zero or one virtual bases of a
- /// given type.
- int SubobjectNumber;
- };
-
- /// BasePath - Represents a path from a specific derived class
- /// (which is not represented as part of the path) to a particular
- /// (direct or indirect) base class subobject that contains some
- /// number of declarations with the same name. Individual elements
- /// in the path are described by the BasePathElement structure,
- /// which captures both the link from a derived class to one of its
- /// direct bases and identification describing which base class
- /// subobject is being used.
- struct BasePath : public llvm::SmallVector<BasePathElement, 4> {
- /// Decls - The set of declarations found inside this base class
- /// subobject.
- DeclContext::lookup_result Decls;
- };
-
- /// BasePaths - Represents the set of paths from a derived class to
- /// one of its (direct or indirect) bases. For example, given the
- /// following class hierachy:
- ///
- /// @code
- /// class A { };
- /// class B : public A { };
- /// class C : public A { };
- /// class D : public B, public C{ };
- /// @endcode
- ///
- /// There are two potential BasePaths to represent paths from D to a
- /// base subobject of type A. One path is (D,0) -> (B,0) -> (A,0)
- /// and another is (D,0)->(C,0)->(A,1). These two paths actually
- /// refer to two different base class subobjects of the same type,
- /// so the BasePaths object refers to an ambiguous path. On the
- /// other hand, consider the following class hierarchy:
- ///
- /// @code
- /// class A { };
- /// class B : public virtual A { };
- /// class C : public virtual A { };
- /// class D : public B, public C{ };
- /// @endcode
- ///
- /// Here, there are two potential BasePaths again, (D, 0) -> (B, 0)
- /// -> (A,v) and (D, 0) -> (C, 0) -> (A, v), but since both of them
- /// refer to the same base class subobject of type A (the virtual
- /// one), there is no ambiguity.
- class BasePaths {
- /// Origin - The type from which this search originated.
- QualType Origin;
-
- /// Paths - The actual set of paths that can be taken from the
- /// derived class to the same base class.
- std::list<BasePath> Paths;
-
- /// ClassSubobjects - Records the class subobjects for each class
- /// type that we've seen. The first element in the pair says
- /// whether we found a path to a virtual base for that class type,
- /// while the element contains the number of non-virtual base
- /// class subobjects for that class type. The key of the map is
- /// the cv-unqualified canonical type of the base class subobject.
- std::map<QualType, std::pair<bool, unsigned>, QualTypeOrdering>
- ClassSubobjects;
-
- /// FindAmbiguities - Whether Sema::IsDerivedFrom should try find
- /// ambiguous paths while it is looking for a path from a derived
- /// type to a base type.
- bool FindAmbiguities;
-
- /// RecordPaths - Whether Sema::IsDerivedFrom should record paths
- /// while it is determining whether there are paths from a derived
- /// type to a base type.
- bool RecordPaths;
-
- /// DetectVirtual - Whether Sema::IsDerivedFrom should abort the search
- /// if it finds a path that goes across a virtual base. The virtual class
- /// is also recorded.
- bool DetectVirtual;
-
- /// ScratchPath - A BasePath that is used by Sema::IsDerivedFrom
- /// to help build the set of paths.
- BasePath ScratchPath;
-
- /// DetectedVirtual - The base class that is virtual.
- const RecordType *DetectedVirtual;
-
- /// \brief Array of the declarations that have been found. This
- /// array is constructed only if needed, e.g., to iterate over the
- /// results within LookupResult.
- NamedDecl **DeclsFound;
- unsigned NumDeclsFound;
-
- friend class Sema;
-
- void ComputeDeclsFound();
-
- public:
- typedef std::list<BasePath>::const_iterator paths_iterator;
- typedef NamedDecl **decl_iterator;
-
- /// BasePaths - Construct a new BasePaths structure to record the
- /// paths for a derived-to-base search.
- explicit BasePaths(bool FindAmbiguities = true,
- bool RecordPaths = true,
- bool DetectVirtual = true)
- : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
- DetectVirtual(DetectVirtual), DetectedVirtual(0), DeclsFound(0),
- NumDeclsFound(0)
- {}
-
- ~BasePaths() { delete [] DeclsFound; }
-
- paths_iterator begin() const { return Paths.begin(); }
- paths_iterator end() const { return Paths.end(); }
-
- BasePath& front() { return Paths.front(); }
- const BasePath& front() const { return Paths.front(); }
-
- decl_iterator found_decls_begin();
- decl_iterator found_decls_end();
-
- bool isAmbiguous(QualType BaseType);
-
- /// isFindingAmbiguities - Whether we are finding multiple paths
- /// to detect ambiguities.
- bool isFindingAmbiguities() const { return FindAmbiguities; }
-
- /// isRecordingPaths - Whether we are recording paths.
- bool isRecordingPaths() const { return RecordPaths; }
-
- /// setRecordingPaths - Specify whether we should be recording
- /// paths or not.
- void setRecordingPaths(bool RP) { RecordPaths = RP; }
-
- /// isDetectingVirtual - Whether we are detecting virtual bases.
- bool isDetectingVirtual() const { return DetectVirtual; }
-
- /// getDetectedVirtual - The virtual base discovered on the path.
- const RecordType* getDetectedVirtual() const {
- return DetectedVirtual;
- }
-
- /// @brief Retrieve the type from which this base-paths search
- /// began
- QualType getOrigin() const { return Origin; }
- void setOrigin(QualType Type) { Origin = Type; }
-
- void clear();
-
- void swap(BasePaths &Other);
- };
-
- /// MemberLookupCriteria - Criteria for performing lookup of a
- /// member of a C++ class. Objects of this type are used to direct
- /// Sema::LookupCXXClassMember.
- struct MemberLookupCriteria {
- /// LookupKind - the kind of lookup we're doing.
- enum LookupKind {
- LK_Base,
- LK_NamedMember,
- LK_OverriddenMember
- };
-
- /// MemberLookupCriteria - Constructs member lookup criteria to
- /// search for a base class of type Base.
- explicit MemberLookupCriteria(QualType Base)
- : Kind(LK_Base), Base(Base) { }
-
- /// MemberLookupCriteria - Constructs member lookup criteria to
- /// search for a class member with the given Name.
- explicit MemberLookupCriteria(DeclarationName Name,
- Sema::LookupNameKind NameKind,
- unsigned IDNS)
- : Kind(LK_NamedMember), Name(Name), NameKind(NameKind), IDNS(IDNS) { }
-
- explicit MemberLookupCriteria(CXXMethodDecl *MD)
- : Kind(LK_OverriddenMember), Method(MD) { }
-
- /// Kind - The kind of lookup we're doing.
- /// LK_Base if we are looking for a base class (whose
- /// type is Base). LK_NamedMember if we are looking for a named member of
- /// the class (with the name Name).
- LookupKind Kind;
-
- /// Base - The type of the base class we're searching for, if
- /// LookupBase is true.
- QualType Base;
-
- /// Name - The name of the member we're searching for, if
- /// LookupBase is false.
- DeclarationName Name;
-
- Sema::LookupNameKind NameKind;
- unsigned IDNS;
-
- CXXMethodDecl *Method;
- };
-}
-
-#endif
diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp
deleted file mode 100644
index daf6800ea0c0f..0000000000000
--- a/lib/Sema/SemaNamedCast.cpp
+++ /dev/null
@@ -1,932 +0,0 @@
-//===--- SemaNamedCast.cpp - Semantic Analysis for Named Casts ------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements semantic analysis for C++ named casts.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Sema.h"
-#include "SemaInherit.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ASTContext.h"
-#include "llvm/ADT/SmallVector.h"
-#include <set>
-using namespace clang;
-
-enum TryStaticCastResult {
- TSC_NotApplicable, ///< The cast method is not applicable.
- TSC_Success, ///< The cast method is appropriate and successful.
- TSC_Failed ///< The cast method is appropriate, but failed. A
- ///< diagnostic has been emitted.
-};
-
-static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
- const SourceRange &OpRange,
- const SourceRange &DestRange);
-static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
- const SourceRange &OpRange,
- const SourceRange &DestRange);
-static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
- const SourceRange &OpRange);
-static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
- const SourceRange &OpRange,
- const SourceRange &DestRange);
-
-static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
-static TryStaticCastResult TryLValueToRValueCast(
- Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange);
-static TryStaticCastResult TryStaticReferenceDowncast(
- Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange);
-static TryStaticCastResult TryStaticPointerDowncast(
- Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange);
-static TryStaticCastResult TryStaticMemberPointerUpcast(
- Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange);
-static TryStaticCastResult TryStaticDowncast(Sema &Self, QualType SrcType,
- QualType DestType,
- const SourceRange &OpRange,
- QualType OrigSrcType,
- QualType OrigDestType);
-static TryStaticCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr,
- QualType DestType,
- const SourceRange &OpRange);
-
-/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
-Action::OwningExprResult
-Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
- SourceLocation LAngleBracketLoc, TypeTy *Ty,
- SourceLocation RAngleBracketLoc,
- SourceLocation LParenLoc, ExprArg E,
- SourceLocation RParenLoc) {
- Expr *Ex = E.takeAs<Expr>();
- QualType DestType = QualType::getFromOpaquePtr(Ty);
- SourceRange OpRange(OpLoc, RParenLoc);
- SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc);
-
- // If the type is dependent, we won't do the semantic analysis now.
- // FIXME: should we check this in a more fine-grained manner?
- bool TypeDependent = DestType->isDependentType() || Ex->isTypeDependent();
-
- switch (Kind) {
- default: assert(0 && "Unknown C++ cast!");
-
- case tok::kw_const_cast:
- if (!TypeDependent)
- CheckConstCast(*this, Ex, DestType, OpRange, DestRange);
- return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(),
- Ex, DestType, OpLoc));
-
- case tok::kw_dynamic_cast:
- if (!TypeDependent)
- CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange);
- return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
- Ex, DestType, OpLoc));
-
- case tok::kw_reinterpret_cast:
- if (!TypeDependent)
- CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange);
- return Owned(new (Context) CXXReinterpretCastExpr(
- DestType.getNonReferenceType(),
- Ex, DestType, OpLoc));
-
- case tok::kw_static_cast:
- if (!TypeDependent)
- CheckStaticCast(*this, Ex, DestType, OpRange);
- return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
- Ex, DestType, OpLoc));
- }
-
- return ExprError();
-}
-
-/// CheckConstCast - Check that a const_cast\<DestType\>(SrcExpr) is valid.
-/// Refer to C++ 5.2.11 for details. const_cast is typically used in code
-/// like this:
-/// const char *str = "literal";
-/// legacy_function(const_cast\<char*\>(str));
-void
-CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
- const SourceRange &OpRange, const SourceRange &DestRange)
-{
- QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
-
- DestType = Self.Context.getCanonicalType(DestType);
- QualType SrcType = SrcExpr->getType();
- if (const LValueReferenceType *DestTypeTmp =
- DestType->getAsLValueReferenceType()) {
- if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
- // Cannot cast non-lvalue to lvalue reference type.
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
- << "const_cast" << OrigDestType << SrcExpr->getSourceRange();
- return;
- }
-
- // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2
- // [...] if a pointer to T1 can be [cast] to the type pointer to T2.
- DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
- SrcType = Self.Context.getPointerType(SrcType);
- } else {
- // C++ 5.2.11p1: Otherwise, the result is an rvalue and the
- // lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard
- // conversions are performed on the expression.
- Self.DefaultFunctionArrayConversion(SrcExpr);
- SrcType = SrcExpr->getType();
- }
-
- // C++ 5.2.11p5: For a const_cast involving pointers to data members [...]
- // the rules for const_cast are the same as those used for pointers.
-
- if (!DestType->isPointerType() && !DestType->isMemberPointerType()) {
- // Cannot cast to non-pointer, non-reference type. Note that, if DestType
- // was a reference type, we converted it to a pointer above.
- // The status of rvalue references isn't entirely clear, but it looks like
- // conversion to them is simply invalid.
- // C++ 5.2.11p3: For two pointer types [...]
- Self.Diag(OpRange.getBegin(), diag::err_bad_const_cast_dest)
- << OrigDestType << DestRange;
- return;
- }
- if (DestType->isFunctionPointerType() ||
- DestType->isMemberFunctionPointerType()) {
- // Cannot cast direct function pointers.
- // C++ 5.2.11p2: [...] where T is any object type or the void type [...]
- // T is the ultimate pointee of source and target type.
- Self.Diag(OpRange.getBegin(), diag::err_bad_const_cast_dest)
- << OrigDestType << DestRange;
- return;
- }
- SrcType = Self.Context.getCanonicalType(SrcType);
-
- // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are
- // completely equal.
- // FIXME: const_cast should probably not be able to convert between pointers
- // to different address spaces.
- // C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers
- // in multi-level pointers may change, but the level count must be the same,
- // as must be the final pointee type.
- while (SrcType != DestType &&
- Self.UnwrapSimilarPointerTypes(SrcType, DestType)) {
- SrcType = SrcType.getUnqualifiedType();
- DestType = DestType.getUnqualifiedType();
- }
-
- // Doug Gregor said to disallow this until users complain.
-#if 0
- // If we end up with constant arrays of equal size, unwrap those too. A cast
- // from const int [N] to int (&)[N] is invalid by my reading of the
- // standard, but g++ accepts it even with -ansi -pedantic.
- // No more than one level, though, so don't embed this in the unwrap loop
- // above.
- const ConstantArrayType *SrcTypeArr, *DestTypeArr;
- if ((SrcTypeArr = Self.Context.getAsConstantArrayType(SrcType)) &&
- (DestTypeArr = Self.Context.getAsConstantArrayType(DestType)))
- {
- if (SrcTypeArr->getSize() != DestTypeArr->getSize()) {
- // Different array sizes.
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
- << "const_cast" << OrigDestType << OrigSrcType << OpRange;
- return;
- }
- SrcType = SrcTypeArr->getElementType().getUnqualifiedType();
- DestType = DestTypeArr->getElementType().getUnqualifiedType();
- }
-#endif
-
- // Since we're dealing in canonical types, the remainder must be the same.
- if (SrcType != DestType) {
- // Cast between unrelated types.
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
- << "const_cast" << OrigDestType << OrigSrcType << OpRange;
- return;
- }
-}
-
-/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
-/// valid.
-/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
-/// like this:
-/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
-void
-CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
- const SourceRange &OpRange, const SourceRange &DestRange)
-{
- QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
-
- DestType = Self.Context.getCanonicalType(DestType);
- QualType SrcType = SrcExpr->getType();
- if (const LValueReferenceType *DestTypeTmp =
- DestType->getAsLValueReferenceType()) {
- if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
- // Cannot cast non-lvalue to reference type.
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
- << "reinterpret_cast" << OrigDestType << SrcExpr->getSourceRange();
- return;
- }
-
- // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
- // same effect as the conversion *reinterpret_cast<T*>(&x) with the
- // built-in & and * operators.
- // This code does this transformation for the checked types.
- DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
- SrcType = Self.Context.getPointerType(SrcType);
- } else if (const RValueReferenceType *DestTypeTmp =
- DestType->getAsRValueReferenceType()) {
- // Both the reference conversion and the rvalue rules apply.
- Self.DefaultFunctionArrayConversion(SrcExpr);
- SrcType = SrcExpr->getType();
-
- DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
- SrcType = Self.Context.getPointerType(SrcType);
- } else {
- // C++ 5.2.10p1: [...] the lvalue-to-rvalue, array-to-pointer, and
- // function-to-pointer standard conversions are performed on the
- // expression v.
- Self.DefaultFunctionArrayConversion(SrcExpr);
- SrcType = SrcExpr->getType();
- }
-
- // Canonicalize source for comparison.
- SrcType = Self.Context.getCanonicalType(SrcType);
-
- const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(),
- *SrcMemPtr = SrcType->getAsMemberPointerType();
- if (DestMemPtr && SrcMemPtr) {
- // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1"
- // can be explicitly converted to an rvalue of type "pointer to member
- // of Y of type T2" if T1 and T2 are both function types or both object
- // types.
- if (DestMemPtr->getPointeeType()->isFunctionType() !=
- SrcMemPtr->getPointeeType()->isFunctionType()) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
- << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
- return;
- }
-
- // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away
- // constness.
- if (CastsAwayConstness(Self, SrcType, DestType)) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
- << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
- return;
- }
-
- // A valid member pointer cast.
- return;
- }
-
- // See below for the enumeral issue.
- if (SrcType->isNullPtrType() && DestType->isIntegralType() &&
- !DestType->isEnumeralType()) {
- // C++0x 5.2.10p4: A pointer can be explicitly converted to any integral
- // type large enough to hold it. A value of std::nullptr_t can be
- // converted to an integral type; the conversion has the same meaning
- // and validity as a conversion of (void*)0 to the integral type.
- if (Self.Context.getTypeSize(SrcType) >
- Self.Context.getTypeSize(DestType)) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int)
- << OrigDestType << DestRange;
- }
- return;
- }
-
- bool destIsPtr = DestType->isPointerType();
- bool srcIsPtr = SrcType->isPointerType();
- if (!destIsPtr && !srcIsPtr) {
- // Except for std::nullptr_t->integer and lvalue->reference, which are
- // handled above, at least one of the two arguments must be a pointer.
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
- << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
- return;
- }
-
- if (SrcType == DestType) {
- // C++ 5.2.10p2 has a note that mentions that, subject to all other
- // restrictions, a cast to the same type is allowed. The intent is not
- // entirely clear here, since all other paragraphs explicitly forbid casts
- // to the same type. However, the behavior of compilers is pretty consistent
- // on this point: allow same-type conversion if the involved types are
- // pointers, disallow otherwise.
- return;
- }
-
- // Note: Clang treats enumeration types as integral types. If this is ever
- // changed for C++, the additional check here will be redundant.
- if (DestType->isIntegralType() && !DestType->isEnumeralType()) {
- assert(srcIsPtr && "One type must be a pointer");
- // C++ 5.2.10p4: A pointer can be explicitly converted to any integral
- // type large enough to hold it.
- if (Self.Context.getTypeSize(SrcType) >
- Self.Context.getTypeSize(DestType)) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int)
- << OrigDestType << DestRange;
- }
- return;
- }
-
- if (SrcType->isIntegralType() || SrcType->isEnumeralType()) {
- assert(destIsPtr && "One type must be a pointer");
- // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly
- // converted to a pointer.
- return;
- }
-
- if (!destIsPtr || !srcIsPtr) {
- // With the valid non-pointer conversions out of the way, we can be even
- // more stringent.
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
- << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
- return;
- }
-
- // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
- if (CastsAwayConstness(Self, SrcType, DestType)) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
- << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
- return;
- }
-
- // Not casting away constness, so the only remaining check is for compatible
- // pointer categories.
-
- if (SrcType->isFunctionPointerType()) {
- if (DestType->isFunctionPointerType()) {
- // C++ 5.2.10p6: A pointer to a function can be explicitly converted to
- // a pointer to a function of a different type.
- return;
- }
-
- // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to
- // an object type or vice versa is conditionally-supported.
- // Compilers support it in C++03 too, though, because it's necessary for
- // casting the return value of dlsym() and GetProcAddress().
- // FIXME: Conditionally-supported behavior should be configurable in the
- // TargetInfo or similar.
- if (!Self.getLangOptions().CPlusPlus0x) {
- Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj)
- << OpRange;
- }
- return;
- }
-
- if (DestType->isFunctionPointerType()) {
- // See above.
- if (!Self.getLangOptions().CPlusPlus0x) {
- Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj)
- << OpRange;
- }
- return;
- }
-
- // C++ 5.2.10p7: A pointer to an object can be explicitly converted to
- // a pointer to an object of different type.
- // Void pointers are not specified, but supported by every compiler out there.
- // So we finish by allowing everything that remains - it's got to be two
- // object pointers.
-}
-
-/// CastsAwayConstness - Check if the pointer conversion from SrcType to
-/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by
-/// the cast checkers. Both arguments must denote pointer (possibly to member)
-/// types.
-bool
-CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType)
-{
- // Casting away constness is defined in C++ 5.2.11p8 with reference to
- // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
- // the rules are non-trivial. So first we construct Tcv *...cv* as described
- // in C++ 5.2.11p8.
- assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) &&
- "Source type is not pointer or pointer to member.");
- assert((DestType->isPointerType() || DestType->isMemberPointerType()) &&
- "Destination type is not pointer or pointer to member.");
-
- QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType;
- llvm::SmallVector<unsigned, 8> cv1, cv2;
-
- // Find the qualifications.
- while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
- cv1.push_back(UnwrappedSrcType.getCVRQualifiers());
- cv2.push_back(UnwrappedDestType.getCVRQualifiers());
- }
- assert(cv1.size() > 0 && "Must have at least one pointer level.");
-
- // Construct void pointers with those qualifiers (in reverse order of
- // unwrapping, of course).
- QualType SrcConstruct = Self.Context.VoidTy;
- QualType DestConstruct = Self.Context.VoidTy;
- for (llvm::SmallVector<unsigned, 8>::reverse_iterator i1 = cv1.rbegin(),
- i2 = cv2.rbegin();
- i1 != cv1.rend(); ++i1, ++i2)
- {
- SrcConstruct = Self.Context.getPointerType(
- SrcConstruct.getQualifiedType(*i1));
- DestConstruct = Self.Context.getPointerType(
- DestConstruct.getQualifiedType(*i2));
- }
-
- // Test if they're compatible.
- return SrcConstruct != DestConstruct &&
- !Self.IsQualificationConversion(SrcConstruct, DestConstruct);
-}
-
-/// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid.
-/// Refer to C++ 5.2.9 for details. Static casts are mostly used for making
-/// implicit conversions explicit and getting rid of data loss warnings.
-void
-CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
- const SourceRange &OpRange)
-{
- // The order the tests is not entirely arbitrary. There is one conversion
- // that can be handled in two different ways. Given:
- // struct A {};
- // struct B : public A {
- // B(); B(const A&);
- // };
- // const A &a = B();
- // the cast static_cast<const B&>(a) could be seen as either a static
- // reference downcast, or an explicit invocation of the user-defined
- // conversion using B's conversion constructor.
- // DR 427 specifies that the downcast is to be applied here.
-
- // FIXME: With N2812, casts to rvalue refs will change.
-
- // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
- if (DestType->isVoidType()) {
- return;
- }
-
- // C++ 5.2.9p5, reference downcast.
- // See the function for details.
- // DR 427 specifies that this is to be applied before paragraph 2.
- if (TryStaticReferenceDowncast(Self, SrcExpr, DestType, OpRange)
- > TSC_NotApplicable) {
- return;
- }
-
- // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
- // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
- if (TryLValueToRValueCast(Self, SrcExpr, DestType, OpRange) >
- TSC_NotApplicable) {
- return;
- }
-
- // C++ 5.2.9p2: An expression e can be explicitly converted to a type T
- // [...] if the declaration "T t(e);" is well-formed, [...].
- if (TryStaticImplicitCast(Self, SrcExpr, DestType, OpRange) >
- TSC_NotApplicable) {
- return;
- }
-
- // C++ 5.2.9p6: May apply the reverse of any standard conversion, except
- // lvalue-to-rvalue, array-to-pointer, function-to-pointer, and boolean
- // conversions, subject to further restrictions.
- // Also, C++ 5.2.9p1 forbids casting away constness, which makes reversal
- // of qualification conversions impossible.
-
- // The lvalue-to-rvalue, array-to-pointer and function-to-pointer conversions
- // are applied to the expression.
- QualType OrigSrcType = SrcExpr->getType();
- Self.DefaultFunctionArrayConversion(SrcExpr);
-
- QualType SrcType = Self.Context.getCanonicalType(SrcExpr->getType());
-
- // Reverse integral promotion/conversion. All such conversions are themselves
- // again integral promotions or conversions and are thus already handled by
- // p2 (TryDirectInitialization above).
- // (Note: any data loss warnings should be suppressed.)
- // The exception is the reverse of enum->integer, i.e. integer->enum (and
- // enum->enum). See also C++ 5.2.9p7.
- // The same goes for reverse floating point promotion/conversion and
- // floating-integral conversions. Again, only floating->enum is relevant.
- if (DestType->isEnumeralType()) {
- if (SrcType->isComplexType() || SrcType->isVectorType()) {
- // Fall through - these cannot be converted.
- } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) {
- return;
- }
- }
-
- // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
- // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance.
- if (TryStaticPointerDowncast(Self, SrcType, DestType, OpRange)
- > TSC_NotApplicable) {
- return;
- }
-
- // Reverse member pointer conversion. C++ 4.11 specifies member pointer
- // conversion. C++ 5.2.9p9 has additional information.
- // DR54's access restrictions apply here also.
- if (TryStaticMemberPointerUpcast(Self, SrcType, DestType, OpRange)
- > TSC_NotApplicable) {
- return;
- }
-
- // Reverse pointer conversion to void*. C++ 4.10.p2 specifies conversion to
- // void*. C++ 5.2.9p10 specifies additional restrictions, which really is
- // just the usual constness stuff.
- if (const PointerType *SrcPointer = SrcType->getAsPointerType()) {
- QualType SrcPointee = SrcPointer->getPointeeType();
- if (SrcPointee->isVoidType()) {
- if (const PointerType *DestPointer = DestType->getAsPointerType()) {
- QualType DestPointee = DestPointer->getPointeeType();
- if (DestPointee->isIncompleteOrObjectType()) {
- // This is definitely the intended conversion, but it might fail due
- // to a const violation.
- if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
- << "static_cast" << DestType << OrigSrcType << OpRange;
- }
- return;
- }
- }
- }
- }
-
- // We tried everything. Everything! Nothing works! :-(
- // FIXME: Error reporting could be a lot better. Should store the reason why
- // every substep failed and, at the end, select the most specific and report
- // that.
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
- << "static_cast" << DestType << OrigSrcType
- << OpRange;
-}
-
-/// Tests whether a conversion according to N2844 is valid.
-TryStaticCastResult
-TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
- const SourceRange &OpRange)
-{
- // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
- // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
- const RValueReferenceType *R = DestType->getAsRValueReferenceType();
- if (!R)
- return TSC_NotApplicable;
-
- if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid)
- return TSC_NotApplicable;
-
- // Because we try the reference downcast before this function, from now on
- // this is the only cast possibility, so we issue an error if we fail now.
- bool DerivedToBase;
- if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(),
- DerivedToBase) <
- Sema::Ref_Compatible_With_Added_Qualification) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_lvalue_to_rvalue_cast)
- << SrcExpr->getType() << R->getPointeeType() << OpRange;
- return TSC_Failed;
- }
-
- // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation
- // than nothing.
- return TSC_Success;
-}
-
-/// Tests whether a conversion according to C++ 5.2.9p5 is valid.
-TryStaticCastResult
-TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
- const SourceRange &OpRange)
-{
- // C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be
- // cast to type "reference to cv2 D", where D is a class derived from B,
- // if a valid standard conversion from "pointer to D" to "pointer to B"
- // exists, cv2 >= cv1, and B is not a virtual base class of D.
- // In addition, DR54 clarifies that the base must be accessible in the
- // current context. Although the wording of DR54 only applies to the pointer
- // variant of this rule, the intent is clearly for it to apply to the this
- // conversion as well.
-
- if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
- return TSC_NotApplicable;
- }
-
- const ReferenceType *DestReference = DestType->getAsReferenceType();
- if (!DestReference) {
- return TSC_NotApplicable;
- }
- QualType DestPointee = DestReference->getPointeeType();
-
- return TryStaticDowncast(Self, SrcExpr->getType(), DestPointee, OpRange,
- SrcExpr->getType(), DestType);
-}
-
-/// Tests whether a conversion according to C++ 5.2.9p8 is valid.
-TryStaticCastResult
-TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
- const SourceRange &OpRange)
-{
- // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class
- // type, can be converted to an rvalue of type "pointer to cv2 D", where D
- // is a class derived from B, if a valid standard conversion from "pointer
- // to D" to "pointer to B" exists, cv2 >= cv1, and B is not a virtual base
- // class of D.
- // In addition, DR54 clarifies that the base must be accessible in the
- // current context.
-
- const PointerType *SrcPointer = SrcType->getAsPointerType();
- if (!SrcPointer) {
- return TSC_NotApplicable;
- }
-
- const PointerType *DestPointer = DestType->getAsPointerType();
- if (!DestPointer) {
- return TSC_NotApplicable;
- }
-
- return TryStaticDowncast(Self, SrcPointer->getPointeeType(),
- DestPointer->getPointeeType(),
- OpRange, SrcType, DestType);
-}
-
-/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and
-/// TryStaticPointerDowncast. Tests whether a static downcast from SrcType to
-/// DestType, both of which must be canonical, is possible and allowed.
-TryStaticCastResult
-TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
- const SourceRange &OpRange, QualType OrigSrcType,
- QualType OrigDestType)
-{
- // Downcast can only happen in class hierarchies, so we need classes.
- if (!DestType->isRecordType() || !SrcType->isRecordType()) {
- return TSC_NotApplicable;
- }
-
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
- /*DetectVirtual=*/true);
- if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) {
- return TSC_NotApplicable;
- }
-
- // Target type does derive from source type. Now we're serious. If an error
- // appears now, it's not ignored.
- // This may not be entirely in line with the standard. Take for example:
- // struct A {};
- // struct B : virtual A {
- // B(A&);
- // };
- //
- // void f()
- // {
- // (void)static_cast<const B&>(*((A*)0));
- // }
- // As far as the standard is concerned, p5 does not apply (A is virtual), so
- // p2 should be used instead - "const B& t(*((A*)0));" is perfectly valid.
- // However, both GCC and Comeau reject this example, and accepting it would
- // mean more complex code if we're to preserve the nice error message.
- // FIXME: Being 100% compliant here would be nice to have.
-
- // Must preserve cv, as always.
- if (!DestType.isAtLeastAsQualifiedAs(SrcType)) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
- << "static_cast" << OrigDestType << OrigSrcType << OpRange;
- return TSC_Failed;
- }
-
- if (Paths.isAmbiguous(SrcType.getUnqualifiedType())) {
- // This code is analoguous to that in CheckDerivedToBaseConversion, except
- // that it builds the paths in reverse order.
- // To sum up: record all paths to the base and build a nice string from
- // them. Use it to spice up the error message.
- Paths.clear();
- Paths.setRecordingPaths(true);
- Self.IsDerivedFrom(DestType, SrcType, Paths);
- std::string PathDisplayStr;
- std::set<unsigned> DisplayedPaths;
- for (BasePaths::paths_iterator Path = Paths.begin();
- Path != Paths.end(); ++Path) {
- if (DisplayedPaths.insert(Path->back().SubobjectNumber).second) {
- // We haven't displayed a path to this particular base
- // class subobject yet.
- PathDisplayStr += "\n ";
- for (BasePath::const_reverse_iterator Element = Path->rbegin();
- Element != Path->rend(); ++Element)
- PathDisplayStr += Element->Base->getType().getAsString() + " -> ";
- PathDisplayStr += DestType.getAsString();
- }
- }
-
- Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast)
- << SrcType.getUnqualifiedType() << DestType.getUnqualifiedType()
- << PathDisplayStr << OpRange;
- return TSC_Failed;
- }
-
- if (Paths.getDetectedVirtual() != 0) {
- QualType VirtualBase(Paths.getDetectedVirtual(), 0);
- Self.Diag(OpRange.getBegin(), diag::err_static_downcast_via_virtual)
- << OrigSrcType << OrigDestType << VirtualBase << OpRange;
- return TSC_Failed;
- }
-
- // FIXME: Test accessibility.
-
- return TSC_Success;
-}
-
-/// TryStaticMemberPointerUpcast - Tests whether a conversion according to
-/// C++ 5.2.9p9 is valid:
-///
-/// An rvalue of type "pointer to member of D of type cv1 T" can be
-/// converted to an rvalue of type "pointer to member of B of type cv2 T",
-/// where B is a base class of D [...].
-///
-TryStaticCastResult
-TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
- const SourceRange &OpRange)
-{
- const MemberPointerType *SrcMemPtr = SrcType->getAsMemberPointerType();
- if (!SrcMemPtr)
- return TSC_NotApplicable;
- const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType();
- if (!DestMemPtr)
- return TSC_NotApplicable;
-
- // T == T, modulo cv
- if (Self.Context.getCanonicalType(
- SrcMemPtr->getPointeeType().getUnqualifiedType()) !=
- Self.Context.getCanonicalType(DestMemPtr->getPointeeType().
- getUnqualifiedType()))
- return TSC_NotApplicable;
-
- // B base of D
- QualType SrcClass(SrcMemPtr->getClass(), 0);
- QualType DestClass(DestMemPtr->getClass(), 0);
- BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
- /*DetectVirtual=*/true);
- if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
- return TSC_NotApplicable;
- }
-
- // B is a base of D. But is it an allowed base? If not, it's a hard error.
- if (Paths.isAmbiguous(DestClass)) {
- Paths.clear();
- Paths.setRecordingPaths(true);
- bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths);
- assert(StillOkay);
- StillOkay = StillOkay;
- std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths);
- Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv)
- << 1 << SrcClass << DestClass << PathDisplayStr << OpRange;
- return TSC_Failed;
- }
-
- if (const RecordType *VBase = Paths.getDetectedVirtual()) {
- Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual)
- << SrcClass << DestClass << QualType(VBase, 0) << OpRange;
- return TSC_Failed;
- }
-
- // FIXME: Test accessibility.
-
- return TSC_Success;
-}
-
-/// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2
-/// is valid:
-///
-/// An expression e can be explicitly converted to a type T using a
-/// @c static_cast if the declaration "T t(e);" is well-formed [...].
-TryStaticCastResult
-TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
- const SourceRange &OpRange)
-{
- if (DestType->isReferenceType()) {
- // At this point of CheckStaticCast, if the destination is a reference,
- // this has to work. There is no other way that works.
- return Self.CheckReferenceInit(SrcExpr, DestType) ?
- TSC_Failed : TSC_Success;
- }
- if (DestType->isRecordType()) {
- // FIXME: Use an implementation of C++ [over.match.ctor] for this.
- return TSC_NotApplicable;
- }
-
- // FIXME: To get a proper error from invalid conversions here, we need to
- // reimplement more of this.
- ImplicitConversionSequence ICS = Self.TryImplicitConversion(
- SrcExpr, DestType);
- return ICS.ConversionKind == ImplicitConversionSequence::BadConversion ?
- TSC_NotApplicable : TSC_Success;
-}
-
-/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
-/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
-/// checked downcasts in class hierarchies.
-void
-CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
- const SourceRange &OpRange,
- const SourceRange &DestRange)
-{
- QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
- DestType = Self.Context.getCanonicalType(DestType);
-
- // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type,
- // or "pointer to cv void".
-
- QualType DestPointee;
- const PointerType *DestPointer = DestType->getAsPointerType();
- const ReferenceType *DestReference = DestType->getAsReferenceType();
- if (DestPointer) {
- DestPointee = DestPointer->getPointeeType();
- } else if (DestReference) {
- DestPointee = DestReference->getPointeeType();
- } else {
- Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr)
- << OrigDestType << DestRange;
- return;
- }
-
- const RecordType *DestRecord = DestPointee->getAsRecordType();
- if (DestPointee->isVoidType()) {
- assert(DestPointer && "Reference to void is not possible");
- } else if (DestRecord) {
- if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
- diag::err_bad_dynamic_cast_incomplete,
- DestRange))
- return;
- } else {
- Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
- << DestPointee.getUnqualifiedType() << DestRange;
- return;
- }
-
- // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to
- // complete class type, [...]. If T is an lvalue reference type, v shall be
- // an lvalue of a complete class type, [...]. If T is an rvalue reference
- // type, v shall be an expression having a complete effective class type,
- // [...]
-
- QualType SrcType = Self.Context.getCanonicalType(OrigSrcType);
- QualType SrcPointee;
- if (DestPointer) {
- if (const PointerType *SrcPointer = SrcType->getAsPointerType()) {
- SrcPointee = SrcPointer->getPointeeType();
- } else {
- Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr)
- << OrigSrcType << SrcExpr->getSourceRange();
- return;
- }
- } else if (DestReference->isLValueReferenceType()) {
- if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
- << "dynamic_cast" << OrigDestType << OpRange;
- }
- SrcPointee = SrcType;
- } else {
- SrcPointee = SrcType;
- }
-
- const RecordType *SrcRecord = SrcPointee->getAsRecordType();
- if (SrcRecord) {
- if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
- diag::err_bad_dynamic_cast_incomplete,
- SrcExpr->getSourceRange()))
- return;
- } else {
- Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
- << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
- return;
- }
-
- assert((DestPointer || DestReference) &&
- "Bad destination non-ptr/ref slipped through.");
- assert((DestRecord || DestPointee->isVoidType()) &&
- "Bad destination pointee slipped through.");
- assert(SrcRecord && "Bad source pointee slipped through.");
-
- // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness.
- if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
- << "dynamic_cast" << OrigDestType << OrigSrcType << OpRange;
- return;
- }
-
- // C++ 5.2.7p3: If the type of v is the same as the required result type,
- // [except for cv].
- if (DestRecord == SrcRecord) {
- return;
- }
-
- // C++ 5.2.7p5
- // Upcasts are resolved statically.
- if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
- Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
- OpRange.getBegin(), OpRange);
- // Diagnostic already emitted on error.
- return;
- }
-
- // C++ 5.2.7p6: Otherwise, v shall be [polymorphic].
- const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context);
- assert(SrcDecl && "Definition missing");
- if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
- Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
- << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange();
- }
-
- // Done. Everything else is run-time checks.
-}
diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp
deleted file mode 100644
index c82e1a7da3c92..0000000000000
--- a/lib/Sema/SemaTemplateInstantiateExpr.cpp
+++ /dev/null
@@ -1,1350 +0,0 @@
-//===--- SemaTemplateInstantiateExpr.cpp - C++ Template Expr Instantiation ===/
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//===----------------------------------------------------------------------===/
-//
-// This file implements C++ template instantiation for expressions.
-//
-//===----------------------------------------------------------------------===/
-#include "Sema.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/Parse/DeclSpec.h"
-#include "clang/Parse/Designator.h"
-#include "clang/Lex/Preprocessor.h" // for the identifier table
-#include "llvm/Support/Compiler.h"
-using namespace clang;
-
-namespace {
- class VISIBILITY_HIDDEN TemplateExprInstantiator
- : public StmtVisitor<TemplateExprInstantiator, Sema::OwningExprResult> {
- Sema &SemaRef;
- const TemplateArgumentList &TemplateArgs;
-
- public:
- typedef Sema::OwningExprResult OwningExprResult;
-
- TemplateExprInstantiator(Sema &SemaRef,
- const TemplateArgumentList &TemplateArgs)
- : SemaRef(SemaRef), TemplateArgs(TemplateArgs) { }
-
- // Declare VisitXXXStmt nodes for all of the expression kinds.
-#define EXPR(Type, Base) OwningExprResult Visit##Type(Type *S);
-#define STMT(Type, Base)
-#include "clang/AST/StmtNodes.def"
-
- // Base case. We can't get here.
- Sema::OwningExprResult VisitStmt(Stmt *S) {
- S->dump();
- assert(false && "Cannot instantiate this kind of expression");
- return SemaRef.ExprError();
- }
- };
-}
-
-// Base case. We can't get here.
-Sema::OwningExprResult TemplateExprInstantiator::VisitExpr(Expr *E) {
- E->dump();
- assert(false && "Cannot instantiate this kind of expression");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitPredefinedExpr(PredefinedExpr *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitIntegerLiteral(IntegerLiteral *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitFloatingLiteral(FloatingLiteral *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitStringLiteral(StringLiteral *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCharacterLiteral(CharacterLiteral *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitImaginaryLiteral(ImaginaryLiteral *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitGNUNullExpr(GNUNullExpr *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitUnresolvedFunctionNameExpr(
- UnresolvedFunctionNameExpr *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitTemplateIdRefExpr(TemplateIdRefExpr *E) {
- TemplateName Template
- = SemaRef.InstantiateTemplateName(E->getTemplateName(), E->getTemplateNameLoc(),
- TemplateArgs);
- // FIXME: Can InstantiateTemplateName report an error?
-
- llvm::SmallVector<TemplateArgument, 4> InstantiatedArgs;
- for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) {
- TemplateArgument InstArg = SemaRef.Instantiate(E->getTemplateArgs()[I],
- TemplateArgs);
- if (InstArg.isNull())
- return SemaRef.ExprError();
-
- InstantiatedArgs.push_back(InstArg);
- }
-
- // FIXME: It's possible that we'll find out now that the template name
- // actually refers to a type, in which case this is a functional cast.
- // Implement this!
-
- return SemaRef.BuildTemplateIdExpr(Template, E->getTemplateNameLoc(),
- E->getLAngleLoc(),
- InstantiatedArgs.data(),
- InstantiatedArgs.size(),
- E->getRAngleLoc());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) {
- NamedDecl *D = E->getDecl();
- if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
- assert(NTTP->getDepth() == 0 && "No nested templates yet");
-
- // If the corresponding template argument is NULL or non-existent, it's
- // because we are performing instantiation from explicitly-specified
- // template arguments in a function template, but there were some
- // arguments left unspecified.
- if (NTTP->getPosition() >= TemplateArgs.size() ||
- TemplateArgs[NTTP->getPosition()].isNull())
- return SemaRef.Owned(E); // FIXME: Clone the expression!
-
- const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()];
-
- // The template argument itself might be an expression, in which
- // case we just return that expression.
- if (Arg.getKind() == TemplateArgument::Expression)
- // FIXME: Clone the expression!
- return SemaRef.Owned(Arg.getAsExpr());
-
- if (Arg.getKind() == TemplateArgument::Declaration) {
- ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
-
- // FIXME: Can VD ever have a dependent type?
- return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(),
- false, false);
- }
-
- assert(Arg.getKind() == TemplateArgument::Integral);
- QualType T = Arg.getIntegralType();
- if (T->isCharType() || T->isWideCharType())
- return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
- Arg.getAsIntegral()->getZExtValue(),
- T->isWideCharType(),
- T,
- E->getSourceRange().getBegin()));
- if (T->isBooleanType())
- return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
- Arg.getAsIntegral()->getBoolValue(),
- T,
- E->getSourceRange().getBegin()));
-
- assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
- return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
- *Arg.getAsIntegral(),
- T,
- E->getSourceRange().getBegin()));
- }
-
- if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
- // FIXME: instantiate each decl in the overload set
- return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Ovl,
- SemaRef.Context.OverloadTy,
- E->getLocation(),
- false, false));
- }
-
- NamedDecl *InstD = SemaRef.InstantiateCurrentDeclRef(D);
- if (!InstD)
- return SemaRef.ExprError();
-
- // FIXME: nested-name-specifier for QualifiedDeclRefExpr
- return SemaRef.BuildDeclarationNameExpr(E->getLocation(), InstD,
- /*FIXME:*/false,
- /*FIXME:*/0,
- /*FIXME:*/false);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitParenExpr(ParenExpr *E) {
- Sema::OwningExprResult SubExpr = Visit(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.Owned(new (SemaRef.Context) ParenExpr(
- E->getLParen(), E->getRParen(),
- (Expr *)SubExpr.release()));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitUnaryOperator(UnaryOperator *E) {
- Sema::OwningExprResult Arg = Visit(E->getSubExpr());
- if (Arg.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(),
- E->getOpcode(),
- move(Arg));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
- Sema::OwningExprResult LHS = Visit(E->getLHS());
- if (LHS.isInvalid())
- return SemaRef.ExprError();
-
- Sema::OwningExprResult RHS = Visit(E->getRHS());
- if (RHS.isInvalid())
- return SemaRef.ExprError();
-
- // Since the overloaded array-subscript operator (operator[]) can
- // only be a member function, we can make several simplifying
- // assumptions here:
- // 1) Normal name lookup (from the current scope) will not ever
- // find any declarations of operator[] that won't also be found be
- // member operator lookup, so it is safe to pass a NULL Scope
- // during the instantiation to avoid the lookup entirely.
- //
- // 2) Neither normal name lookup nor argument-dependent lookup at
- // template definition time will find any operators that won't be
- // found at template instantiation time, so we do not need to
- // cache the results of name lookup as we do for the binary
- // operators.
- SourceLocation LLocFake = ((Expr*)LHS.get())->getSourceRange().getBegin();
- return SemaRef.ActOnArraySubscriptExpr(/*Scope=*/0, move(LHS),
- /*FIXME:*/LLocFake,
- move(RHS),
- E->getRBracketLoc());
-}
-
-Sema::OwningExprResult TemplateExprInstantiator::VisitCallExpr(CallExpr *E) {
- // Instantiate callee
- OwningExprResult Callee = Visit(E->getCallee());
- if (Callee.isInvalid())
- return SemaRef.ExprError();
-
- // Instantiate arguments
- ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
- llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
- for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
- OwningExprResult Arg = Visit(E->getArg(I));
- if (Arg.isInvalid())
- return SemaRef.ExprError();
-
- FakeCommaLocs.push_back(
- SemaRef.PP.getLocForEndOfToken(E->getArg(I)->getSourceRange().getEnd()));
- Args.push_back(Arg.takeAs<Expr>());
- }
-
- SourceLocation FakeLParenLoc
- = ((Expr *)Callee.get())->getSourceRange().getBegin();
- return SemaRef.ActOnCallExpr(/*Scope=*/0, move(Callee),
- /*FIXME:*/FakeLParenLoc,
- move_arg(Args),
- /*FIXME:*/&FakeCommaLocs.front(),
- E->getRParenLoc());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitMemberExpr(MemberExpr *E) {
- // Instantiate the base of the expression.
- OwningExprResult Base = Visit(E->getBase());
- if (Base.isInvalid())
- return SemaRef.ExprError();
-
- // FIXME: Handle declaration names here
- SourceLocation FakeOperatorLoc =
- SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
- return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0,
- move(Base),
- /*FIXME*/FakeOperatorLoc,
- E->isArrow()? tok::arrow
- : tok::period,
- E->getMemberLoc(),
- /*FIXME:*/*E->getMemberDecl()->getIdentifier(),
- /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- SourceLocation FakeTypeLoc
- = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
- QualType T = SemaRef.InstantiateType(E->getType(), TemplateArgs,
- FakeTypeLoc,
- DeclarationName());
- if (T.isNull())
- return SemaRef.ExprError();
-
- OwningExprResult Init = Visit(E->getInitializer());
- if (Init.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.ActOnCompoundLiteral(E->getLParenLoc(),
- T.getAsOpaquePtr(),
- /*FIXME*/E->getLParenLoc(),
- move(Init));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) {
- Sema::OwningExprResult LHS = Visit(E->getLHS());
- if (LHS.isInvalid())
- return SemaRef.ExprError();
-
- Sema::OwningExprResult RHS = Visit(E->getRHS());
- if (RHS.isInvalid())
- return SemaRef.ExprError();
-
- Sema::OwningExprResult Result
- = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(),
- E->getOpcode(),
- (Expr *)LHS.get(),
- (Expr *)RHS.get());
- if (Result.isInvalid())
- return SemaRef.ExprError();
-
- LHS.release();
- RHS.release();
- return move(Result);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCompoundAssignOperator(
- CompoundAssignOperator *E) {
- return VisitBinaryOperator(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
- Sema::OwningExprResult First = Visit(E->getArg(0));
- if (First.isInvalid())
- return SemaRef.ExprError();
-
- Expr *Args[2] = { (Expr *)First.get(), 0 };
-
- Sema::OwningExprResult Second(SemaRef);
- if (E->getNumArgs() == 2) {
- Second = Visit(E->getArg(1));
-
- if (Second.isInvalid())
- return SemaRef.ExprError();
-
- Args[1] = (Expr *)Second.get();
- }
-
- if (!E->isTypeDependent()) {
- // Since our original expression was not type-dependent, we do not
- // perform lookup again at instantiation time (C++ [temp.dep]p1).
- // Instead, we just build the new overloaded operator call
- // expression.
- OwningExprResult Callee = Visit(E->getCallee());
- if (Callee.isInvalid())
- return SemaRef.ExprError();
-
- First.release();
- Second.release();
-
- return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr(
- SemaRef.Context,
- E->getOperator(),
- Callee.takeAs<Expr>(),
- Args, E->getNumArgs(),
- E->getType(),
- E->getOperatorLoc()));
- }
-
- bool isPostIncDec = E->getNumArgs() == 2 &&
- (E->getOperator() == OO_PlusPlus || E->getOperator() == OO_MinusMinus);
- if (E->getNumArgs() == 1 || isPostIncDec) {
- if (!Args[0]->getType()->isOverloadableType()) {
- // The argument is not of overloadable type, so try to create a
- // built-in unary operation.
- UnaryOperator::Opcode Opc
- = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec);
-
- return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(), Opc,
- move(First));
- }
-
- // Fall through to perform overload resolution
- } else {
- assert(E->getNumArgs() == 2 && "Expected binary operation");
-
- Sema::OwningExprResult Result(SemaRef);
- if (!Args[0]->getType()->isOverloadableType() &&
- !Args[1]->getType()->isOverloadableType()) {
- // Neither of the arguments is an overloadable type, so try to
- // create a built-in binary operation.
- BinaryOperator::Opcode Opc =
- BinaryOperator::getOverloadedOpcode(E->getOperator());
- Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc,
- Args[0], Args[1]);
- if (Result.isInvalid())
- return SemaRef.ExprError();
-
- First.release();
- Second.release();
- return move(Result);
- }
-
- // Fall through to perform overload resolution.
- }
-
- // Compute the set of functions that were found at template
- // definition time.
- Sema::FunctionSet Functions;
- DeclRefExpr *DRE = cast<DeclRefExpr>(E->getCallee());
- OverloadedFunctionDecl *Overloads
- = cast<OverloadedFunctionDecl>(DRE->getDecl());
-
- // FIXME: Do we have to check
- // IsAcceptableNonMemberOperatorCandidate for each of these?
- for (OverloadedFunctionDecl::function_iterator
- F = Overloads->function_begin(),
- FEnd = Overloads->function_end();
- F != FEnd; ++F)
- Functions.insert(cast<FunctionDecl>(*F));
-
- // Add any functions found via argument-dependent lookup.
- DeclarationName OpName
- = SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator());
- SemaRef.ArgumentDependentLookup(OpName, Args, E->getNumArgs(), Functions);
-
- // Create the overloaded operator invocation.
- if (E->getNumArgs() == 1 || isPostIncDec) {
- UnaryOperator::Opcode Opc
- = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec);
- return SemaRef.CreateOverloadedUnaryOp(E->getOperatorLoc(), Opc,
- Functions, move(First));
- }
-
- // FIXME: This would be far less ugly if CreateOverloadedBinOp took in ExprArg
- // arguments!
- BinaryOperator::Opcode Opc =
- BinaryOperator::getOverloadedOpcode(E->getOperator());
- OwningExprResult Result
- = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc,
- Functions, Args[0], Args[1]);
-
- if (Result.isInvalid())
- return SemaRef.ExprError();
-
- First.release();
- Second.release();
- return move(Result);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) {
- VarDecl *Var
- = cast_or_null<VarDecl>(SemaRef.InstantiateDecl(E->getVarDecl(),
- SemaRef.CurContext,
- TemplateArgs));
- if (!Var)
- return SemaRef.ExprError();
-
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(E->getVarDecl(), Var);
- return SemaRef.Owned(new (SemaRef.Context) CXXConditionDeclExpr(
- E->getStartLoc(),
- SourceLocation(),
- Var));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitConditionalOperator(ConditionalOperator *E) {
- Sema::OwningExprResult Cond = Visit(E->getCond());
- if (Cond.isInvalid())
- return SemaRef.ExprError();
-
- Sema::OwningExprResult LHS = SemaRef.InstantiateExpr(E->getLHS(),
- TemplateArgs);
- if (LHS.isInvalid())
- return SemaRef.ExprError();
-
- Sema::OwningExprResult RHS = Visit(E->getRHS());
- if (RHS.isInvalid())
- return SemaRef.ExprError();
-
- if (!E->isTypeDependent()) {
- // Since our original expression was not type-dependent, we do not
- // perform lookup again at instantiation time (C++ [temp.dep]p1).
- // Instead, we just build the new conditional operator call expression.
- return SemaRef.Owned(new (SemaRef.Context) ConditionalOperator(
- Cond.takeAs<Expr>(),
- LHS.takeAs<Expr>(),
- RHS.takeAs<Expr>(),
- E->getType()));
- }
-
-
- return SemaRef.ActOnConditionalOp(/*FIXME*/E->getCond()->getLocEnd(),
- /*FIXME*/E->getFalseExpr()->getLocStart(),
- move(Cond), move(LHS), move(RHS));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitAddrLabelExpr(AddrLabelExpr *E) {
- return SemaRef.ActOnAddrLabel(E->getAmpAmpLoc(),
- E->getLabelLoc(),
- E->getLabel()->getID());
-}
-
-Sema::OwningExprResult TemplateExprInstantiator::VisitStmtExpr(StmtExpr *E) {
- Sema::OwningStmtResult SubStmt
- = SemaRef.InstantiateCompoundStmt(E->getSubStmt(), TemplateArgs, true);
- if (SubStmt.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.ActOnStmtExpr(E->getLParenLoc(), move(SubStmt),
- E->getRParenLoc());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
- assert(false && "__builtin_types_compatible_p is not legal in C++");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
- ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef);
- for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) {
- OwningExprResult SubExpr = Visit(E->getExpr(I));
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- SubExprs.push_back(SubExpr.takeAs<Expr>());
- }
-
- // Find the declaration for __builtin_shufflevector
- const IdentifierInfo &Name
- = SemaRef.Context.Idents.get("__builtin_shufflevector");
- TranslationUnitDecl *TUDecl = SemaRef.Context.getTranslationUnitDecl();
- DeclContext::lookup_result Lookup = TUDecl->lookup(DeclarationName(&Name));
- assert(Lookup.first != Lookup.second && "No __builtin_shufflevector?");
-
- // Build a reference to the __builtin_shufflevector builtin
- FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
- Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(),
- E->getBuiltinLoc(),
- false, false);
- SemaRef.UsualUnaryConversions(Callee);
-
- // Build the CallExpr
- CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee,
- SubExprs.takeAs<Expr>(),
- SubExprs.size(),
- Builtin->getResultType(),
- E->getRParenLoc());
- OwningExprResult OwnedCall(SemaRef.Owned(TheCall));
-
- // Type-check the __builtin_shufflevector expression.
- OwningExprResult Result = SemaRef.SemaBuiltinShuffleVector(TheCall);
- if (Result.isInvalid())
- return SemaRef.ExprError();
-
- OwnedCall.release();
- return move(Result);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitChooseExpr(ChooseExpr *E) {
- OwningExprResult Cond = Visit(E->getCond());
- if (Cond.isInvalid())
- return SemaRef.ExprError();
-
- OwningExprResult LHS = SemaRef.InstantiateExpr(E->getLHS(), TemplateArgs);
- if (LHS.isInvalid())
- return SemaRef.ExprError();
-
- OwningExprResult RHS = Visit(E->getRHS());
- if (RHS.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.ActOnChooseExpr(E->getBuiltinLoc(),
- move(Cond), move(LHS), move(RHS),
- E->getRParenLoc());
-}
-
-Sema::OwningExprResult TemplateExprInstantiator::VisitVAArgExpr(VAArgExpr *E) {
- OwningExprResult SubExpr = Visit(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- SourceLocation FakeTypeLoc
- = SemaRef.PP.getLocForEndOfToken(E->getSubExpr()->getSourceRange()
- .getEnd());
- QualType T = SemaRef.InstantiateType(E->getType(), TemplateArgs,
- /*FIXME:*/FakeTypeLoc,
- DeclarationName());
- if (T.isNull())
- return SemaRef.ExprError();
-
- return SemaRef.ActOnVAArg(E->getBuiltinLoc(), move(SubExpr),
- T.getAsOpaquePtr(), E->getRParenLoc());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitInitListExpr(InitListExpr *E) {
- ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef);
- for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) {
- OwningExprResult Init = Visit(E->getInit(I));
- if (Init.isInvalid())
- return SemaRef.ExprError();
- Inits.push_back(Init.takeAs<Expr>());
- }
-
- return SemaRef.ActOnInitList(E->getLBraceLoc(), move_arg(Inits),
- E->getRBraceLoc());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
- Designation Desig;
-
- // Instantiate the initializer value
- OwningExprResult Init = Visit(E->getInit());
- if (Init.isInvalid())
- return SemaRef.ExprError();
-
- // Instantiate the designators.
- ASTOwningVector<&ActionBase::DeleteExpr, 4> ArrayExprs(SemaRef);
- for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
- DEnd = E->designators_end();
- D != DEnd; ++D) {
- if (D->isFieldDesignator()) {
- Desig.AddDesignator(Designator::getField(D->getFieldName(),
- D->getDotLoc(),
- D->getFieldLoc()));
- continue;
- }
-
- if (D->isArrayDesignator()) {
- OwningExprResult Index = Visit(E->getArrayIndex(*D));
- if (Index.isInvalid())
- return SemaRef.ExprError();
-
- Desig.AddDesignator(Designator::getArray(Index.get(),
- D->getLBracketLoc()));
-
- ArrayExprs.push_back(Index.release());
- continue;
- }
-
- assert(D->isArrayRangeDesignator() && "New kind of designator?");
- OwningExprResult Start = Visit(E->getArrayRangeStart(*D));
- if (Start.isInvalid())
- return SemaRef.ExprError();
-
- OwningExprResult End = Visit(E->getArrayRangeEnd(*D));
- if (End.isInvalid())
- return SemaRef.ExprError();
-
- Desig.AddDesignator(Designator::getArrayRange(Start.get(),
- End.get(),
- D->getLBracketLoc(),
- D->getEllipsisLoc()));
-
- ArrayExprs.push_back(Start.release());
- ArrayExprs.push_back(End.release());
- }
-
- OwningExprResult Result =
- SemaRef.ActOnDesignatedInitializer(Desig,
- E->getEqualOrColonLoc(),
- E->usesGNUSyntax(),
- move(Init));
- if (Result.isInvalid())
- return SemaRef.ExprError();
-
- ArrayExprs.take();
- return move(Result);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitImplicitValueInitExpr(
- ImplicitValueInitExpr *E) {
- assert(!E->isTypeDependent() && !E->isValueDependent() &&
- "ImplicitValueInitExprs are never dependent");
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
- OwningExprResult Base = Visit(E->getBase());
- if (Base.isInvalid())
- return SemaRef.ExprError();
-
- SourceLocation FakeOperatorLoc =
- SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
- return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0,
- move(Base),
- /*FIXME*/FakeOperatorLoc,
- tok::period,
- E->getAccessorLoc(),
- E->getAccessor(),
- /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitBlockExpr(BlockExpr *E) {
- assert(false && "FIXME:Template instantiation for blocks is unimplemented");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
- assert(false && "FIXME:Template instantiation for blocks is unimplemented");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
- bool isSizeOf = E->isSizeOf();
-
- if (E->isArgumentType()) {
- QualType T = E->getArgumentType();
- if (T->isDependentType()) {
- T = SemaRef.InstantiateType(T, TemplateArgs,
- /*FIXME*/E->getOperatorLoc(),
- &SemaRef.PP.getIdentifierTable().get("sizeof"));
- if (T.isNull())
- return SemaRef.ExprError();
- }
-
- return SemaRef.CreateSizeOfAlignOfExpr(T, E->getOperatorLoc(), isSizeOf,
- E->getSourceRange());
- }
-
- Sema::OwningExprResult Arg(SemaRef);
- {
- // C++0x [expr.sizeof]p1:
- // The operand is either an expression, which is an unevaluated operand
- // [...]
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
- Arg = Visit(E->getArgumentExpr());
- if (Arg.isInvalid())
- return SemaRef.ExprError();
- }
-
- Sema::OwningExprResult Result
- = SemaRef.CreateSizeOfAlignOfExpr((Expr *)Arg.get(), E->getOperatorLoc(),
- isSizeOf, E->getSourceRange());
- if (Result.isInvalid())
- return SemaRef.ExprError();
-
- Arg.release();
- return move(Result);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E) {
- NestedNameSpecifier *NNS
- = SemaRef.InstantiateNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange(),
- TemplateArgs);
- if (!NNS)
- return SemaRef.ExprError();
-
- CXXScopeSpec SS;
- SS.setRange(E->getQualifierRange());
- SS.setScopeRep(NNS);
-
- // FIXME: We're passing in a NULL scope, because
- // ActOnDeclarationNameExpr doesn't actually use the scope when we
- // give it a non-empty scope specifier. Investigate whether it would
- // be better to refactor ActOnDeclarationNameExpr.
- return SemaRef.ActOnDeclarationNameExpr(/*Scope=*/0, E->getLocation(),
- E->getDeclName(),
- /*HasTrailingLParen=*/false,
- &SS,
- /*FIXME:isAddressOfOperand=*/false);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXTemporaryObjectExpr(
- CXXTemporaryObjectExpr *E) {
- QualType T = E->getType();
- if (T->isDependentType()) {
- T = SemaRef.InstantiateType(T, TemplateArgs,
- E->getTypeBeginLoc(), DeclarationName());
- if (T.isNull())
- return SemaRef.ExprError();
- }
-
- ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
- Args.reserve(E->getNumArgs());
- for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(),
- ArgEnd = E->arg_end();
- Arg != ArgEnd; ++Arg) {
- OwningExprResult InstantiatedArg = Visit(*Arg);
- if (InstantiatedArg.isInvalid())
- return SemaRef.ExprError();
-
- Args.push_back((Expr *)InstantiatedArg.release());
- }
-
- SourceLocation CommaLoc;
- // FIXME: HACK!
- if (Args.size() > 1) {
- Expr *First = (Expr *)Args[0];
- CommaLoc
- = SemaRef.PP.getLocForEndOfToken(First->getSourceRange().getEnd());
- }
- return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc()
- /*, FIXME*/),
- T.getAsOpaquePtr(),
- /*FIXME*/E->getTypeBeginLoc(),
- move_arg(Args),
- /*HACK*/&CommaLoc,
- E->getSourceRange().getEnd());
-}
-
-Sema::OwningExprResult TemplateExprInstantiator::VisitCastExpr(CastExpr *E) {
- assert(false && "Cannot instantiate abstract CastExpr");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult TemplateExprInstantiator::VisitImplicitCastExpr(
- ImplicitCastExpr *E) {
- assert(!E->isTypeDependent() && "Implicit casts must have known types");
-
- Sema::OwningExprResult SubExpr = Visit(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- ImplicitCastExpr *ICE =
- new (SemaRef.Context) ImplicitCastExpr(E->getType(),
- (Expr *)SubExpr.release(),
- E->isLvalueCast());
- return SemaRef.Owned(ICE);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitExplicitCastExpr(ExplicitCastExpr *E) {
- assert(false && "Cannot instantiate abstract ExplicitCastExpr");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCStyleCastExpr(CStyleCastExpr *E) {
- // Instantiate the type that we're casting to.
- SourceLocation TypeStartLoc
- = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
- QualType ExplicitTy = SemaRef.InstantiateType(E->getTypeAsWritten(),
- TemplateArgs,
- TypeStartLoc,
- DeclarationName());
- if (ExplicitTy.isNull())
- return SemaRef.ExprError();
-
- // Instantiate the subexpression.
- OwningExprResult SubExpr = Visit(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.ActOnCastExpr(E->getLParenLoc(),
- ExplicitTy.getAsOpaquePtr(),
- E->getRParenLoc(),
- move(SubExpr));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
- return VisitCallExpr(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
- // Figure out which cast operator we're dealing with.
- tok::TokenKind Kind;
- switch (E->getStmtClass()) {
- case Stmt::CXXStaticCastExprClass:
- Kind = tok::kw_static_cast;
- break;
-
- case Stmt::CXXDynamicCastExprClass:
- Kind = tok::kw_dynamic_cast;
- break;
-
- case Stmt::CXXReinterpretCastExprClass:
- Kind = tok::kw_reinterpret_cast;
- break;
-
- case Stmt::CXXConstCastExprClass:
- Kind = tok::kw_const_cast;
- break;
-
- default:
- assert(false && "Invalid C++ named cast");
- return SemaRef.ExprError();
- }
-
- // Instantiate the type that we're casting to.
- SourceLocation TypeStartLoc
- = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
- QualType ExplicitTy = SemaRef.InstantiateType(E->getTypeAsWritten(),
- TemplateArgs,
- TypeStartLoc,
- DeclarationName());
- if (ExplicitTy.isNull())
- return SemaRef.ExprError();
-
- // Instantiate the subexpression.
- OwningExprResult SubExpr = Visit(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- SourceLocation FakeLAngleLoc
- = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
- SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin();
- SourceLocation FakeRParenLoc
- = SemaRef.PP.getLocForEndOfToken(
- E->getSubExpr()->getSourceRange().getEnd());
- return SemaRef.ActOnCXXNamedCast(E->getOperatorLoc(), Kind,
- /*FIXME:*/FakeLAngleLoc,
- ExplicitTy.getAsOpaquePtr(),
- /*FIXME:*/FakeRAngleLoc,
- /*FIXME:*/FakeRAngleLoc,
- move(SubExpr),
- /*FIXME:*/FakeRParenLoc);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
- return VisitCXXNamedCastExpr(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
- return VisitCXXNamedCastExpr(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXReinterpretCastExpr(
- CXXReinterpretCastExpr *E) {
- return VisitCXXNamedCastExpr(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
- return VisitCXXNamedCastExpr(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXThisExpr(CXXThisExpr *E) {
- QualType ThisType =
- cast<CXXMethodDecl>(SemaRef.CurContext)->getThisType(SemaRef.Context);
-
- CXXThisExpr *TE =
- new (SemaRef.Context) CXXThisExpr(E->getLocStart(), ThisType);
-
- return SemaRef.Owned(TE);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
- if (E->isTypeOperand()) {
- QualType T = SemaRef.InstantiateType(E->getTypeOperand(),
- TemplateArgs,
- /*FIXME*/E->getSourceRange().getBegin(),
- DeclarationName());
- if (T.isNull())
- return SemaRef.ExprError();
-
- return SemaRef.ActOnCXXTypeid(E->getSourceRange().getBegin(),
- /*FIXME*/E->getSourceRange().getBegin(),
- true, T.getAsOpaquePtr(),
- E->getSourceRange().getEnd());
- }
-
- // We don't know whether the expression is potentially evaluated until
- // after we perform semantic analysis, so the expression is potentially
- // potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Action::PotentiallyPotentiallyEvaluated);
-
- OwningExprResult Operand = Visit(E->getExprOperand());
- if (Operand.isInvalid())
- return SemaRef.ExprError();
-
- OwningExprResult Result
- = SemaRef.ActOnCXXTypeid(E->getSourceRange().getBegin(),
- /*FIXME*/E->getSourceRange().getBegin(),
- false, Operand.get(),
- E->getSourceRange().getEnd());
- if (Result.isInvalid())
- return SemaRef.ExprError();
-
- Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership
- return move(Result);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXThrowExpr(CXXThrowExpr *E) {
- OwningExprResult SubExpr(SemaRef, (void *)0);
- if (E->getSubExpr()) {
- SubExpr = Visit(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
- }
-
- return SemaRef.ActOnCXXThrow(E->getThrowLoc(), move(SubExpr));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
- assert(false &&
- "FIXME: Instantiation for default arguments is unimplemented");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXBindTemporaryExpr(
- CXXBindTemporaryExpr *E) {
- OwningExprResult SubExpr = Visit(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.MaybeBindToTemporary(SubExpr.takeAs<Expr>());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXConstructExpr(CXXConstructExpr *E) {
- assert(!cast<CXXRecordDecl>(E->getConstructor()->getDeclContext())
- ->isDependentType() && "Dependent constructor shouldn't be here");
-
- QualType T = SemaRef.InstantiateType(E->getType(), TemplateArgs,
- /*FIXME*/E->getSourceRange().getBegin(),
- DeclarationName());
- if (T.isNull())
- return SemaRef.ExprError();
-
- ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
- for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(),
- ArgEnd = E->arg_end();
- Arg != ArgEnd; ++Arg) {
- OwningExprResult ArgInst = Visit(*Arg);
- if (ArgInst.isInvalid())
- return SemaRef.ExprError();
-
- Args.push_back(ArgInst.takeAs<Expr>());
- }
-
- return SemaRef.Owned(CXXConstructExpr::Create(SemaRef.Context, T,
- E->getConstructor(),
- E->isElidable(),
- Args.takeAs<Expr>(),
- Args.size()));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXFunctionalCastExpr(
- CXXFunctionalCastExpr *E) {
- // Instantiate the type that we're casting to.
- QualType ExplicitTy = SemaRef.InstantiateType(E->getTypeAsWritten(),
- TemplateArgs,
- E->getTypeBeginLoc(),
- DeclarationName());
- if (ExplicitTy.isNull())
- return SemaRef.ExprError();
-
- // Instantiate the subexpression.
- OwningExprResult SubExpr = Visit(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- // FIXME: The end of the type's source range is wrong
- Expr *Sub = SubExpr.takeAs<Expr>();
- return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc()),
- ExplicitTy.getAsOpaquePtr(),
- /*FIXME:*/E->getTypeBeginLoc(),
- Sema::MultiExprArg(SemaRef,
- (void **)&Sub,
- 1),
- 0,
- E->getRParenLoc());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
- return SemaRef.Clone(E);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXNewExpr(CXXNewExpr *E) {
- // Instantiate the type that we're allocating
- QualType AllocType = SemaRef.InstantiateType(E->getAllocatedType(),
- TemplateArgs,
- /*FIXME:*/E->getSourceRange().getBegin(),
- DeclarationName());
- if (AllocType.isNull())
- return SemaRef.ExprError();
-
- // Instantiate the size of the array we're allocating (if any).
- OwningExprResult ArraySize = SemaRef.InstantiateExpr(E->getArraySize(),
- TemplateArgs);
- if (ArraySize.isInvalid())
- return SemaRef.ExprError();
-
- // Instantiate the placement arguments (if any).
- ASTOwningVector<&ActionBase::DeleteExpr> PlacementArgs(SemaRef);
- for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) {
- OwningExprResult Arg = Visit(E->getPlacementArg(I));
- if (Arg.isInvalid())
- return SemaRef.ExprError();
-
- PlacementArgs.push_back(Arg.take());
- }
-
- // Instantiate the constructor arguments (if any).
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef);
- for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) {
- OwningExprResult Arg = Visit(E->getConstructorArg(I));
- if (Arg.isInvalid())
- return SemaRef.ExprError();
-
- ConstructorArgs.push_back(Arg.take());
- }
-
- return SemaRef.BuildCXXNew(E->getSourceRange().getBegin(),
- E->isGlobalNew(),
- /*FIXME*/SourceLocation(),
- move_arg(PlacementArgs),
- /*FIXME*/SourceLocation(),
- E->isParenTypeId(),
- AllocType,
- /*FIXME*/E->getSourceRange().getBegin(),
- SourceRange(),
- move(ArraySize),
- /*FIXME*/SourceLocation(),
- Sema::MultiExprArg(SemaRef,
- ConstructorArgs.take(),
- ConstructorArgs.size()),
- E->getSourceRange().getEnd());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
- OwningExprResult Operand = Visit(E->getArgument());
- if (Operand.isInvalid())
- return SemaRef.ExprError();
-
- return SemaRef.ActOnCXXDelete(E->getSourceRange().getBegin(),
- E->isGlobalDelete(),
- E->isArrayForm(),
- move(Operand));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
- QualType T = SemaRef.InstantiateType(E->getQueriedType(), TemplateArgs,
- /*FIXME*/E->getSourceRange().getBegin(),
- DeclarationName());
- if (T.isNull())
- return SemaRef.ExprError();
-
- SourceLocation FakeLParenLoc
- = SemaRef.PP.getLocForEndOfToken(E->getSourceRange().getBegin());
- return SemaRef.ActOnUnaryTypeTrait(E->getTrait(),
- E->getSourceRange().getBegin(),
- /*FIXME*/FakeLParenLoc,
- T.getAsOpaquePtr(),
- E->getSourceRange().getEnd());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *E) {
- NestedNameSpecifier *NNS
- = SemaRef.InstantiateNestedNameSpecifier(E->getQualifier(),
- E->getQualifierRange(),
- TemplateArgs);
- if (!NNS)
- return SemaRef.ExprError();
-
- CXXScopeSpec SS;
- SS.setRange(E->getQualifierRange());
- SS.setScopeRep(NNS);
- return SemaRef.ActOnDeclarationNameExpr(/*Scope=*/0,
- E->getLocation(),
- E->getDecl()->getDeclName(),
- /*Trailing lparen=*/false,
- &SS,
- /*FIXME:*/false);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXExprWithTemporaries(
- CXXExprWithTemporaries *E) {
- OwningExprResult SubExpr = Visit(E->getSubExpr());
- if (SubExpr.isInvalid())
- return SemaRef.ExprError();
-
- Expr *Temp =
- SemaRef.MaybeCreateCXXExprWithTemporaries(SubExpr.takeAs<Expr>(),
- E->shouldDestroyTemporaries());
- return SemaRef.Owned(Temp);
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXUnresolvedConstructExpr(
- CXXUnresolvedConstructExpr *E) {
- QualType T = SemaRef.InstantiateType(E->getTypeAsWritten(), TemplateArgs,
- E->getTypeBeginLoc(),
- DeclarationName());
- if (T.isNull())
- return SemaRef.ExprError();
-
- ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
- llvm::SmallVector<SourceLocation, 8> FakeCommaLocs;
- for (CXXUnresolvedConstructExpr::arg_iterator Arg = E->arg_begin(),
- ArgEnd = E->arg_end();
- Arg != ArgEnd; ++Arg) {
- OwningExprResult InstArg = Visit(*Arg);
- if (InstArg.isInvalid())
- return SemaRef.ExprError();
-
- FakeCommaLocs.push_back(
- SemaRef.PP.getLocForEndOfToken((*Arg)->getSourceRange().getEnd()));
- Args.push_back(InstArg.takeAs<Expr>());
- }
-
- // FIXME: The end of the type range isn't exactly correct.
- // FIXME: we're faking the locations of the commas
- return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc(),
- E->getLParenLoc()),
- T.getAsOpaquePtr(),
- E->getLParenLoc(),
- move_arg(Args),
- &FakeCommaLocs.front(),
- E->getRParenLoc());
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitCXXUnresolvedMemberExpr(
- CXXUnresolvedMemberExpr *E) {
- // Instantiate the base of the expression.
- OwningExprResult Base = Visit(E->getBase());
- if (Base.isInvalid())
- return SemaRef.ExprError();
-
- // FIXME: Instantiate the declaration name.
- return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0,
- move(Base), E->getOperatorLoc(),
- E->isArrow()? tok::arrow
- : tok::period,
- E->getMemberLoc(),
- /*FIXME:*/*E->getMember().getAsIdentifierInfo(),
- /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
-}
-
-//----------------------------------------------------------------------------
-// Objective-C Expressions
-//----------------------------------------------------------------------------
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitObjCStringLiteral(ObjCStringLiteral *E) {
- return SemaRef.Owned(E->Clone(SemaRef.Context));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
- QualType EncodedType = SemaRef.InstantiateType(E->getEncodedType(),
- TemplateArgs,
- /*FIXME:*/E->getAtLoc(),
- DeclarationName());
- if (EncodedType.isNull())
- return SemaRef.ExprError();
-
- return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(E->getAtLoc(),
- EncodedType,
- E->getRParenLoc()));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitObjCMessageExpr(ObjCMessageExpr *E) {
- assert(false && "FIXME: Template instantiations for ObjC expressions");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
- return SemaRef.Owned(E->Clone(SemaRef.Context));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
- return SemaRef.Owned(E->Clone(SemaRef.Context));
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
- assert(false && "FIXME: Template instantiations for ObjC expressions");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- assert(false && "FIXME: Template instantiations for ObjC expressions");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
- assert(false && "FIXME: Template instantiations for ObjC expressions");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-TemplateExprInstantiator::VisitObjCSuperExpr(ObjCSuperExpr *E) {
- assert(false && "FIXME: Template instantiations for ObjC expressions");
- return SemaRef.ExprError();
-}
-
-Sema::OwningExprResult
-Sema::InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs) {
- if (!E)
- return Owned((Expr *)0);
-
- TemplateExprInstantiator Instantiator(*this, TemplateArgs);
- return Instantiator.Visit(E);
-}
diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp
deleted file mode 100644
index 565b95b329f73..0000000000000
--- a/lib/Sema/SemaTemplateInstantiateStmt.cpp
+++ /dev/null
@@ -1,450 +0,0 @@
-//===--- SemaTemplateInstantiateStmt.cpp - C++ Template Stmt Instantiation ===/
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//===----------------------------------------------------------------------===/
-//
-// This file implements C++ template instantiation for statements.
-//
-//===----------------------------------------------------------------------===/
-#include "Sema.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/Parse/DeclSpec.h"
-#include "llvm/Support/Compiler.h"
-using namespace clang;
-
-namespace {
- class VISIBILITY_HIDDEN TemplateStmtInstantiator
- : public StmtVisitor<TemplateStmtInstantiator, Sema::OwningStmtResult> {
- Sema &SemaRef;
- const TemplateArgumentList &TemplateArgs;
-
- template<typename T>
- Sema::FullExprArg FullExpr(T &expr) {
- return SemaRef.FullExpr(expr);
- }
-
- public:
- typedef Sema::OwningExprResult OwningExprResult;
- typedef Sema::OwningStmtResult OwningStmtResult;
-
- TemplateStmtInstantiator(Sema &SemaRef,
- const TemplateArgumentList &TemplateArgs)
- : SemaRef(SemaRef), TemplateArgs(TemplateArgs) { }
-
- // Declare VisitXXXStmt nodes for all of the statement kinds.
-#define STMT(Type, Base) OwningStmtResult Visit##Type(Type *S);
-#define EXPR(Type, Base)
-#include "clang/AST/StmtNodes.def"
-
- // Visit an expression (which will use the expression
- // instantiator).
- OwningStmtResult VisitExpr(Expr *E);
-
- // Base case. I'm supposed to ignore this.
- OwningStmtResult VisitStmt(Stmt *S) {
- S->dump();
- assert(false && "Cannot instantiate this kind of statement");
- return SemaRef.StmtError();
- }
- };
-}
-
-//===----------------------------------------------------------------------===/
-// Common/C statements
-//===----------------------------------------------------------------------===/
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitDeclStmt(DeclStmt *S) {
- llvm::SmallVector<Decl *, 4> Decls;
- for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
- D != DEnd; ++D) {
- Decl *Instantiated = SemaRef.InstantiateDecl(*D, SemaRef.CurContext,
- TemplateArgs);
- if (!Instantiated)
- return SemaRef.StmtError();
-
- Decls.push_back(Instantiated);
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(*D, Instantiated);
- }
-
- return SemaRef.Owned(new (SemaRef.Context) DeclStmt(
- DeclGroupRef::Create(SemaRef.Context,
- &Decls[0],
- Decls.size()),
- S->getStartLoc(),
- S->getEndLoc()));
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitNullStmt(NullStmt *S) {
- return SemaRef.Owned(S->Clone(SemaRef.Context));
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitLabelStmt(LabelStmt *S) {
- OwningStmtResult SubStmt = Visit(S->getSubStmt());
-
- if (SubStmt.isInvalid())
- return SemaRef.StmtError();
-
- // FIXME: Pass the real colon loc in.
- return SemaRef.ActOnLabelStmt(S->getIdentLoc(), S->getID(), SourceLocation(),
- move(SubStmt));
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitGotoStmt(GotoStmt *S) {
- return SemaRef.ActOnGotoStmt(S->getGotoLoc(), S->getLabelLoc(),
- S->getLabel()->getID());
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
- OwningExprResult Target = SemaRef.InstantiateExpr(S->getTarget(),
- TemplateArgs);
- if (Target.isInvalid())
- return SemaRef.StmtError();
-
- return SemaRef.ActOnIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(),
- move(Target));
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitBreakStmt(BreakStmt *S) {
- return SemaRef.Owned(S->Clone(SemaRef.Context));
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitContinueStmt(ContinueStmt *S) {
- return SemaRef.Owned(S->Clone(SemaRef.Context));
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitReturnStmt(ReturnStmt *S) {
- Sema::OwningExprResult Result = SemaRef.ExprEmpty();
- if (Expr *E = S->getRetValue()) {
- Result = SemaRef.InstantiateExpr(E, TemplateArgs);
-
- if (Result.isInvalid())
- return SemaRef.StmtError();
- }
-
- return SemaRef.ActOnReturnStmt(S->getReturnLoc(), FullExpr(Result));
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitCompoundStmt(CompoundStmt *S) {
- return SemaRef.InstantiateCompoundStmt(S, TemplateArgs, false);
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitSwitchCase(SwitchCase *S) {
- assert(false && "SwitchCase statements are never directly instantiated");
- return SemaRef.StmtError();
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitCaseStmt(CaseStmt *S) {
- // The case value expressions are not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
- // Instantiate left-hand case value.
- OwningExprResult LHS = SemaRef.InstantiateExpr(S->getLHS(), TemplateArgs);
- if (LHS.isInvalid())
- return SemaRef.StmtError();
-
- // Instantiate right-hand case value (for the GNU case-range extension).
- OwningExprResult RHS = SemaRef.InstantiateExpr(S->getRHS(), TemplateArgs);
- if (RHS.isInvalid())
- return SemaRef.StmtError();
-
- // Build the case statement.
- OwningStmtResult Case = SemaRef.ActOnCaseStmt(S->getCaseLoc(),
- move(LHS),
- S->getEllipsisLoc(),
- move(RHS),
- S->getColonLoc());
- if (Case.isInvalid())
- return SemaRef.StmtError();
-
- // Instantiate the statement following the case
- OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(),
- TemplateArgs);
- if (SubStmt.isInvalid())
- return SemaRef.StmtError();
-
- SemaRef.ActOnCaseStmtBody(Case.get(), move(SubStmt));
- return move(Case);
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitDefaultStmt(DefaultStmt *S) {
- // Instantiate the statement following the default case
- OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(),
- TemplateArgs);
- if (SubStmt.isInvalid())
- return SemaRef.StmtError();
-
- return SemaRef.ActOnDefaultStmt(S->getDefaultLoc(),
- S->getColonLoc(),
- move(SubStmt),
- /*CurScope=*/0);
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitIfStmt(IfStmt *S) {
- // Instantiate the condition
- OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
- if (Cond.isInvalid())
- return SemaRef.StmtError();
-
- Sema::FullExprArg FullCond(FullExpr(Cond));
-
- // Instantiate the "then" branch.
- OwningStmtResult Then = SemaRef.InstantiateStmt(S->getThen(), TemplateArgs);
- if (Then.isInvalid())
- return SemaRef.StmtError();
-
- // Instantiate the "else" branch.
- OwningStmtResult Else = SemaRef.InstantiateStmt(S->getElse(), TemplateArgs);
- if (Else.isInvalid())
- return SemaRef.StmtError();
-
- return SemaRef.ActOnIfStmt(S->getIfLoc(), FullCond, move(Then),
- S->getElseLoc(), move(Else));
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitSwitchStmt(SwitchStmt *S) {
- // Instantiate the condition.
- OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
- if (Cond.isInvalid())
- return SemaRef.StmtError();
-
- // Start the switch statement itself.
- OwningStmtResult Switch = SemaRef.ActOnStartOfSwitchStmt(move(Cond));
- if (Switch.isInvalid())
- return SemaRef.StmtError();
-
- // Instantiate the body of the switch statement.
- OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs);
- if (Body.isInvalid())
- return SemaRef.StmtError();
-
- // Complete the switch statement.
- return SemaRef.ActOnFinishSwitchStmt(S->getSwitchLoc(), move(Switch),
- move(Body));
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitWhileStmt(WhileStmt *S) {
- // Instantiate the condition
- OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
- if (Cond.isInvalid())
- return SemaRef.StmtError();
-
- Sema::FullExprArg FullCond(FullExpr(Cond));
-
- // Instantiate the body
- OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs);
- if (Body.isInvalid())
- return SemaRef.StmtError();
-
- return SemaRef.ActOnWhileStmt(S->getWhileLoc(), FullCond, move(Body));
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitDoStmt(DoStmt *S) {
- // Instantiate the condition
- OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
- if (Cond.isInvalid())
- return SemaRef.StmtError();
-
- // Instantiate the body
- OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs);
- if (Body.isInvalid())
- return SemaRef.StmtError();
-
- return SemaRef.ActOnDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(),
- SourceLocation(), move(Cond), S->getRParenLoc());
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitForStmt(ForStmt *S) {
- // Instantiate the initialization statement
- OwningStmtResult Init = SemaRef.InstantiateStmt(S->getInit(), TemplateArgs);
- if (Init.isInvalid())
- return SemaRef.StmtError();
-
- // Instantiate the condition
- OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs);
- if (Cond.isInvalid())
- return SemaRef.StmtError();
-
- // Instantiate the increment
- OwningExprResult Inc = SemaRef.InstantiateExpr(S->getInc(), TemplateArgs);
- if (Inc.isInvalid())
- return SemaRef.StmtError();
-
- // Instantiate the body
- OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs);
- if (Body.isInvalid())
- return SemaRef.StmtError();
-
- return SemaRef.ActOnForStmt(S->getForLoc(), S->getLParenLoc(),
- move(Init), move(Cond), move(Inc),
- S->getRParenLoc(), move(Body));
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitAsmStmt(AsmStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate an 'asm' statement");
- return SemaRef.StmtError();
-}
-
-//===----------------------------------------------------------------------===/
-// C++ statements
-//===----------------------------------------------------------------------===/
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitCXXTryStmt(CXXTryStmt *S) {
- // Instantiate the try block itself.
- OwningStmtResult TryBlock = VisitCompoundStmt(S->getTryBlock());
- if (TryBlock.isInvalid())
- return SemaRef.StmtError();
-
- // Instantiate the handlers.
- ASTOwningVector<&ActionBase::DeleteStmt> Handlers(SemaRef);
- for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) {
- OwningStmtResult Handler = VisitCXXCatchStmt(S->getHandler(I));
- if (Handler.isInvalid())
- return SemaRef.StmtError();
-
- Handlers.push_back(Handler.takeAs<Stmt>());
- }
-
- return SemaRef.ActOnCXXTryBlock(S->getTryLoc(), move(TryBlock),
- move_arg(Handlers));
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitCXXCatchStmt(CXXCatchStmt *S) {
- // Instantiate the exception declaration, if any.
- VarDecl *Var = 0;
- if (S->getExceptionDecl()) {
- VarDecl *ExceptionDecl = S->getExceptionDecl();
- QualType T = SemaRef.InstantiateType(ExceptionDecl->getType(),
- TemplateArgs,
- ExceptionDecl->getLocation(),
- ExceptionDecl->getDeclName());
- if (T.isNull())
- return SemaRef.StmtError();
-
- Var = SemaRef.BuildExceptionDeclaration(0, T,
- ExceptionDecl->getIdentifier(),
- ExceptionDecl->getLocation(),
- /*FIXME: Inaccurate*/
- SourceRange(ExceptionDecl->getLocation()));
- if (Var->isInvalidDecl()) {
- Var->Destroy(SemaRef.Context);
- return SemaRef.StmtError();
- }
-
- // Introduce the exception declaration into scope.
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var);
- }
-
- // Instantiate the actual exception handler.
- OwningStmtResult Handler = Visit(S->getHandlerBlock());
- if (Handler.isInvalid()) {
- if (Var)
- Var->Destroy(SemaRef.Context);
- return SemaRef.StmtError();
- }
-
- return SemaRef.Owned(new (SemaRef.Context) CXXCatchStmt(S->getCatchLoc(),
- Var,
- Handler.takeAs<Stmt>()));
-}
-
-//===----------------------------------------------------------------------===/
-// Objective-C statements
-//===----------------------------------------------------------------------===/
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate an Objective-C @finally statement");
- return SemaRef.StmtError();
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitObjCAtSynchronizedStmt(
- ObjCAtSynchronizedStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate an Objective-C @synchronized statement");
- return SemaRef.StmtError();
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate an Objective-C @try statement");
- return SemaRef.StmtError();
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitObjCForCollectionStmt(
- ObjCForCollectionStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate an Objective-C \"for\" statement");
- return SemaRef.StmtError();
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate an Objective-C @throw statement");
- return SemaRef.StmtError();
-}
-
-Sema::OwningStmtResult
-TemplateStmtInstantiator::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot instantiate an Objective-C @catch statement");
- return SemaRef.StmtError();
-}
-
-Sema::OwningStmtResult TemplateStmtInstantiator::VisitExpr(Expr *E) {
- Sema::OwningExprResult Result = SemaRef.InstantiateExpr(E, TemplateArgs);
- if (Result.isInvalid())
- return SemaRef.StmtError();
-
- return SemaRef.Owned(Result.takeAs<Stmt>());
-}
-
-Sema::OwningStmtResult
-Sema::InstantiateStmt(Stmt *S, const TemplateArgumentList &TemplateArgs) {
- if (!S)
- return Owned((Stmt *)0);
-
- TemplateStmtInstantiator Instantiator(*this, TemplateArgs);
- return Instantiator.Visit(S);
-}
-
-Sema::OwningStmtResult
-Sema::InstantiateCompoundStmt(CompoundStmt *S,
- const TemplateArgumentList &TemplateArgs,
- bool isStmtExpr) {
- if (!S)
- return Owned((Stmt *)0);
-
- TemplateStmtInstantiator Instantiator(*this, TemplateArgs);
- ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this);
- for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end();
- B != BEnd; ++B) {
- OwningStmtResult Result = Instantiator.Visit(*B);
- if (Result.isInvalid())
- return StmtError();
-
- Statements.push_back(Result.takeAs<Stmt>());
- }
-
- return ActOnCompoundStmt(S->getLBracLoc(), S->getRBracLoc(),
- move_arg(Statements), isStmtExpr);
-}
diff --git a/utils/test/Makefile.multi b/utils/test/Makefile.multi
deleted file mode 100644
index 3e9cd5669aa8a..0000000000000
--- a/utils/test/Makefile.multi
+++ /dev/null
@@ -1,21 +0,0 @@
-LEVEL = ../../..
-include $(LEVEL)/Makefile.common
-
-# Test in all immediate subdirectories if unset.
-TESTDIRS ?= $(shell echo $(PROJ_SRC_DIR)/*/)
-
-ifndef TESTARGS
-ifdef VERBOSE
-TESTARGS = -v
-else
-TESTARGS = -s
-endif
-endif
-
-all::
- @ PATH=$(ToolDir):$(LLVM_SRC_ROOT)/test/Scripts:$$PATH VG=$(VG) ../utils/test/MultiTestRunner.py $(TESTARGS) $(TESTDIRS)
-
-clean::
- @ rm -rf Output/
-
-.PHONY: all report clean
diff --git a/utils/test/MultiTestRunner.py b/utils/test/MultiTestRunner.py
deleted file mode 100755
index 6d0c14afad402..0000000000000
--- a/utils/test/MultiTestRunner.py
+++ /dev/null
@@ -1,347 +0,0 @@
-#!/usr/bin/python
-
-"""
-MultiTestRunner - Harness for running multiple tests in the simple clang style.
-
-TODO
---
- - Fix Ctrl-c issues
- - Use a timeout
- - Detect signalled failures (abort)
- - Better support for finding tests
-"""
-
-# TOD
-import os, sys, re, random, time
-import threading
-import ProgressBar
-import TestRunner
-from TestRunner import TestStatus
-from Queue import Queue
-
-kTestFileExtensions = set(['.mi','.i','.c','.cpp','.m','.mm','.ll'])
-
-def getTests(inputs):
- for path in inputs:
- if not os.path.exists(path):
- print >>sys.stderr,"WARNING: Invalid test \"%s\""%(path,)
- continue
-
- if os.path.isdir(path):
- for dirpath,dirnames,filenames in os.walk(path):
- dotTests = os.path.join(dirpath,'.tests')
- if os.path.exists(dotTests):
- for ln in open(dotTests):
- if ln.strip():
- yield os.path.join(dirpath,ln.strip())
- else:
- # FIXME: This doesn't belong here
- if 'Output' in dirnames:
- dirnames.remove('Output')
- for f in filenames:
- base,ext = os.path.splitext(f)
- if ext in kTestFileExtensions:
- yield os.path.join(dirpath,f)
- else:
- yield path
-
-class TestingProgressDisplay:
- def __init__(self, opts, numTests, progressBar=None):
- self.opts = opts
- self.numTests = numTests
- self.digits = len(str(self.numTests))
- self.current = None
- self.lock = threading.Lock()
- self.progressBar = progressBar
- self.progress = 0.
-
- def update(self, index, tr):
- # Avoid locking overhead in quiet mode
- if self.opts.quiet and not tr.failed():
- return
-
- # Output lock
- self.lock.acquire()
- try:
- self.handleUpdate(index, tr)
- finally:
- self.lock.release()
-
- def finish(self):
- if self.progressBar:
- self.progressBar.clear()
- elif self.opts.succinct:
- sys.stdout.write('\n')
-
- def handleUpdate(self, index, tr):
- if self.progressBar:
- if tr.failed():
- self.progressBar.clear()
- else:
- # Force monotonicity
- self.progress = max(self.progress, float(index)/self.numTests)
- self.progressBar.update(self.progress, tr.path)
- return
- elif self.opts.succinct:
- if not tr.failed():
- sys.stdout.write('.')
- sys.stdout.flush()
- return
- else:
- sys.stdout.write('\n')
-
- extra = ''
- if tr.code==TestStatus.Invalid:
- extra = ' - (Invalid test)'
- elif tr.code==TestStatus.NoRunLine:
- extra = ' - (No RUN line)'
- elif tr.failed():
- extra = ' - %s'%(TestStatus.getName(tr.code).upper(),)
- print '%*d/%*d - %s%s'%(self.digits, index+1, self.digits,
- self.numTests, tr.path, extra)
-
- if tr.failed() and self.opts.showOutput:
- TestRunner.cat(tr.testResults, sys.stdout)
-
-class TestResult:
- def __init__(self, path, code, testResults):
- self.path = path
- self.code = code
- self.testResults = testResults
-
- def failed(self):
- return self.code in (TestStatus.Fail,TestStatus.XPass)
-
-class TestProvider:
- def __init__(self, opts, tests, display):
- self.opts = opts
- self.tests = tests
- self.index = 0
- self.lock = threading.Lock()
- self.results = [None]*len(self.tests)
- self.startTime = time.time()
- self.progress = display
-
- def get(self):
- self.lock.acquire()
- try:
- if self.opts.maxTime is not None:
- if time.time() - self.startTime > self.opts.maxTime:
- return None
- if self.index >= len(self.tests):
- return None
- item = self.tests[self.index],self.index
- self.index += 1
- return item
- finally:
- self.lock.release()
-
- def setResult(self, index, result):
- self.results[index] = result
- self.progress.update(index, result)
-
-class Tester(threading.Thread):
- def __init__(self, provider):
- threading.Thread.__init__(self)
- self.provider = provider
-
- def run(self):
- while 1:
- item = self.provider.get()
- if item is None:
- break
- self.runTest(item)
-
- def runTest(self, (path,index)):
- command = path
- # Use hand concatentation here because we want to override
- # absolute paths.
- output = 'Output/' + path + '.out'
- testname = path
- testresults = 'Output/' + path + '.testresults'
- TestRunner.mkdir_p(os.path.dirname(testresults))
- numTests = len(self.provider.tests)
- digits = len(str(numTests))
- code = None
- try:
- opts = self.provider.opts
- if opts.debugDoNotTest:
- code = None
- else:
- code = TestRunner.runOneTest(path, command, output, testname,
- opts.clang, opts.clangcc,
- useValgrind=opts.useValgrind,
- useDGCompat=opts.useDGCompat,
- useScript=opts.testScript,
- output=open(testresults,'w'))
- except KeyboardInterrupt:
- # This is a sad hack. Unfortunately subprocess goes
- # bonkers with ctrl-c and we start forking merrily.
- print 'Ctrl-C detected, goodbye.'
- os.kill(0,9)
-
- self.provider.setResult(index, TestResult(path, code, testresults))
-
-def detectCPUs():
- """
- Detects the number of CPUs on a system. Cribbed from pp.
- """
- # Linux, Unix and MacOS:
- if hasattr(os, "sysconf"):
- if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
- # Linux & Unix:
- ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
- if isinstance(ncpus, int) and ncpus > 0:
- return ncpus
- else: # OSX:
- return int(os.popen2("sysctl -n hw.ncpu")[1].read())
- # Windows:
- if os.environ.has_key("NUMBER_OF_PROCESSORS"):
- ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]);
- if ncpus > 0:
- return ncpus
- return 1 # Default
-
-def main():
- global options
- from optparse import OptionParser
- parser = OptionParser("usage: %prog [options] {inputs}")
- parser.add_option("-j", "--threads", dest="numThreads",
- help="Number of testing threads",
- type=int, action="store",
- default=detectCPUs())
- parser.add_option("", "--clang", dest="clang",
- help="Program to use as \"clang\"",
- action="store", default=None)
- parser.add_option("", "--clang-cc", dest="clangcc",
- help="Program to use as \"clang-cc\"",
- action="store", default=None)
- parser.add_option("", "--vg", dest="useValgrind",
- help="Run tests under valgrind",
- action="store_true", default=False)
- parser.add_option("", "--dg", dest="useDGCompat",
- help="Use llvm dejagnu compatibility mode",
- action="store_true", default=False)
- parser.add_option("", "--script", dest="testScript",
- help="Default script to use",
- action="store", default=None)
- parser.add_option("-v", "--verbose", dest="showOutput",
- help="Show all test output",
- action="store_true", default=False)
- parser.add_option("-q", "--quiet", dest="quiet",
- help="Suppress no error output",
- action="store_true", default=False)
- parser.add_option("-s", "--succinct", dest="succinct",
- help="Reduce amount of output",
- action="store_true", default=False)
- parser.add_option("", "--max-tests", dest="maxTests",
- help="Maximum number of tests to run",
- action="store", type=int, default=None)
- parser.add_option("", "--max-time", dest="maxTime",
- help="Maximum time to spend testing (in seconds)",
- action="store", type=float, default=None)
- parser.add_option("", "--shuffle", dest="shuffle",
- help="Run tests in random order",
- action="store_true", default=False)
- parser.add_option("", "--seed", dest="seed",
- help="Seed for random number generator (default: random)",
- action="store", default=None)
- parser.add_option("", "--no-progress-bar", dest="useProgressBar",
- help="Do not use curses based progress bar",
- action="store_false", default=True)
- parser.add_option("", "--debug-do-not-test", dest="debugDoNotTest",
- help="DEBUG: Skip running actual test script",
- action="store_true", default=False)
- parser.add_option("", "--path", dest="path",
- help="Additional paths to add to testing environment",
- action="store", type=str, default=None)
-
- (opts, args) = parser.parse_args()
-
- if not args:
- parser.error('No inputs specified')
-
- if opts.clang is None:
- opts.clang = TestRunner.inferClang()
- if opts.clangcc is None:
- opts.clangcc = TestRunner.inferClangCC(opts.clang)
-
- # FIXME: It could be worth loading these in parallel with testing.
- allTests = list(getTests(args))
- allTests.sort()
-
- tests = allTests
- if opts.seed is not None:
- try:
- seed = int(opts.seed)
- except:
- parser.error('--seed argument should be an integer')
- random.seed(seed)
- if opts.shuffle:
- random.shuffle(tests)
- if opts.maxTests is not None:
- tests = tests[:opts.maxTests]
- if opts.path is not None:
- os.environ["PATH"] = opts.path + ":" + os.environ["PATH"];
-
- extra = ''
- if len(tests) != len(allTests):
- extra = ' of %d'%(len(allTests),)
- header = '-- Testing: %d%s tests, %d threads --'%(len(tests),extra,
- opts.numThreads)
-
- progressBar = None
- if not opts.quiet:
- if opts.useProgressBar:
- try:
- tc = ProgressBar.TerminalController()
- progressBar = ProgressBar.ProgressBar(tc, header)
- except ValueError:
- pass
-
- if not progressBar:
- print header
-
- display = TestingProgressDisplay(opts, len(tests), progressBar)
- provider = TestProvider(opts, tests, display)
-
- testers = [Tester(provider) for i in range(opts.numThreads)]
- startTime = time.time()
- for t in testers:
- t.start()
- try:
- for t in testers:
- t.join()
- except KeyboardInterrupt:
- sys.exit(1)
-
- display.finish()
-
- if not opts.quiet:
- print 'Testing Time: %.2fs'%(time.time() - startTime)
-
- # List test results organized organized by kind.
- byCode = {}
- for t in provider.results:
- if t:
- if t.code not in byCode:
- byCode[t.code] = []
- byCode[t.code].append(t)
- for title,code in (('Expected Failures', TestStatus.XFail),
- ('Unexpected Passing Tests', TestStatus.XPass),
- ('Failing Tests', TestStatus.Fail)):
- elts = byCode.get(code)
- if not elts:
- continue
- print '*'*20
- print '%s (%d):' % (title, len(elts))
- for tr in elts:
- print '\t%s'%(tr.path,)
-
- numFailures = len(byCode.get(TestStatus.Fail,[]))
- if numFailures:
- print '\nFailures: %d' % (numFailures,)
- sys.exit(1)
-
-if __name__=='__main__':
- main()
diff --git a/utils/test/ProgressBar.py b/utils/test/ProgressBar.py
deleted file mode 100644
index 2e1f24ae79a1d..0000000000000
--- a/utils/test/ProgressBar.py
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/python
-
-# Source: http://code.activestate.com/recipes/475116/, with
-# modifications by Daniel Dunbar.
-
-import sys, re, time
-
-class TerminalController:
- """
- A class that can be used to portably generate formatted output to
- a terminal.
-
- `TerminalController` defines a set of instance variables whose
- values are initialized to the control sequence necessary to
- perform a given action. These can be simply included in normal
- output to the terminal:
-
- >>> term = TerminalController()
- >>> print 'This is '+term.GREEN+'green'+term.NORMAL
-
- Alternatively, the `render()` method can used, which replaces
- '${action}' with the string required to perform 'action':
-
- >>> term = TerminalController()
- >>> print term.render('This is ${GREEN}green${NORMAL}')
-
- If the terminal doesn't support a given action, then the value of
- the corresponding instance variable will be set to ''. As a
- result, the above code will still work on terminals that do not
- support color, except that their output will not be colored.
- Also, this means that you can test whether the terminal supports a
- given action by simply testing the truth value of the
- corresponding instance variable:
-
- >>> term = TerminalController()
- >>> if term.CLEAR_SCREEN:
- ... print 'This terminal supports clearning the screen.'
-
- Finally, if the width and height of the terminal are known, then
- they will be stored in the `COLS` and `LINES` attributes.
- """
- # Cursor movement:
- BOL = '' #: Move the cursor to the beginning of the line
- UP = '' #: Move the cursor up one line
- DOWN = '' #: Move the cursor down one line
- LEFT = '' #: Move the cursor left one char
- RIGHT = '' #: Move the cursor right one char
-
- # Deletion:
- CLEAR_SCREEN = '' #: Clear the screen and move to home position
- CLEAR_EOL = '' #: Clear to the end of the line.
- CLEAR_BOL = '' #: Clear to the beginning of the line.
- CLEAR_EOS = '' #: Clear to the end of the screen
-
- # Output modes:
- BOLD = '' #: Turn on bold mode
- BLINK = '' #: Turn on blink mode
- DIM = '' #: Turn on half-bright mode
- REVERSE = '' #: Turn on reverse-video mode
- NORMAL = '' #: Turn off all modes
-
- # Cursor display:
- HIDE_CURSOR = '' #: Make the cursor invisible
- SHOW_CURSOR = '' #: Make the cursor visible
-
- # Terminal size:
- COLS = None #: Width of the terminal (None for unknown)
- LINES = None #: Height of the terminal (None for unknown)
-
- # Foreground colors:
- BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
-
- # Background colors:
- BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
- BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
-
- _STRING_CAPABILITIES = """
- BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
- CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
- BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
- HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
- _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
- _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
-
- def __init__(self, term_stream=sys.stdout):
- """
- Create a `TerminalController` and initialize its attributes
- with appropriate values for the current terminal.
- `term_stream` is the stream that will be used for terminal
- output; if this stream is not a tty, then the terminal is
- assumed to be a dumb terminal (i.e., have no capabilities).
- """
- # Curses isn't available on all platforms
- try: import curses
- except: return
-
- # If the stream isn't a tty, then assume it has no capabilities.
- if not term_stream.isatty(): return
-
- # Check the terminal type. If we fail, then assume that the
- # terminal has no capabilities.
- try: curses.setupterm()
- except: return
-
- # Look up numeric capabilities.
- self.COLS = curses.tigetnum('cols')
- self.LINES = curses.tigetnum('lines')
-
- # Look up string capabilities.
- for capability in self._STRING_CAPABILITIES:
- (attrib, cap_name) = capability.split('=')
- setattr(self, attrib, self._tigetstr(cap_name) or '')
-
- # Colors
- set_fg = self._tigetstr('setf')
- if set_fg:
- for i,color in zip(range(len(self._COLORS)), self._COLORS):
- setattr(self, color, curses.tparm(set_fg, i) or '')
- set_fg_ansi = self._tigetstr('setaf')
- if set_fg_ansi:
- for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
- setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
- set_bg = self._tigetstr('setb')
- if set_bg:
- for i,color in zip(range(len(self._COLORS)), self._COLORS):
- setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
- set_bg_ansi = self._tigetstr('setab')
- if set_bg_ansi:
- for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
- setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
-
- def _tigetstr(self, cap_name):
- # String capabilities can include "delays" of the form "$<2>".
- # For any modern terminal, we should be able to just ignore
- # these, so strip them out.
- import curses
- cap = curses.tigetstr(cap_name) or ''
- return re.sub(r'\$<\d+>[/*]?', '', cap)
-
- def render(self, template):
- """
- Replace each $-substitutions in the given template string with
- the corresponding terminal control string (if it's defined) or
- '' (if it's not).
- """
- return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
-
- def _render_sub(self, match):
- s = match.group()
- if s == '$$': return s
- else: return getattr(self, s[2:-1])
-
-#######################################################################
-# Example use case: progress bar
-#######################################################################
-
-class ProgressBar:
- """
- A 3-line progress bar, which looks like::
-
- Header
- 20% [===========----------------------------------]
- progress message
-
- The progress bar is colored, if the terminal supports color
- output; and adjusts to the width of the terminal.
- """
- BAR = '%s${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}%s\n'
- HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
-
- def __init__(self, term, header, useETA=True):
- self.term = term
- if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
- raise ValueError("Terminal isn't capable enough -- you "
- "should use a simpler progress dispaly.")
- self.width = self.term.COLS or 75
- self.bar = term.render(self.BAR)
- self.header = self.term.render(self.HEADER % header.center(self.width))
- self.cleared = 1 #: true if we haven't drawn the bar yet.
- self.useETA = useETA
- if self.useETA:
- self.startTime = time.time()
- self.update(0, '')
-
- def update(self, percent, message):
- if self.cleared:
- sys.stdout.write(self.header)
- self.cleared = 0
- prefix = '%3d%% ' % (percent*100,)
- suffix = ''
- if self.useETA:
- elapsed = time.time() - self.startTime
- if percent > .0001 and elapsed > 1:
- total = elapsed / percent
- eta = int(total - elapsed)
- h = eta//3600.
- m = (eta//60) % 60
- s = eta % 60
- suffix = ' ETA: %02d:%02d:%02d'%(h,m,s)
- barWidth = self.width - len(prefix) - len(suffix) - 2
- n = int(barWidth*percent)
- if len(message) < self.width:
- message = message + ' '*(self.width - len(message))
- else:
- message = '... ' + message[-(self.width-4):]
- sys.stdout.write(
- self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
- (self.bar % (prefix, '='*n, '-'*(barWidth-n), suffix)) +
- self.term.CLEAR_EOL + message)
-
- def clear(self):
- if not self.cleared:
- sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
- self.term.UP + self.term.CLEAR_EOL +
- self.term.UP + self.term.CLEAR_EOL)
- self.cleared = 1
-
-def test():
- import time
- tc = TerminalController()
- p = ProgressBar(tc, 'Tests')
- for i in range(101):
- p.update(i/100., str(i))
- time.sleep(.3)
-
-if __name__=='__main__':
- test()
diff --git a/utils/test/TestRunner.py b/utils/test/TestRunner.py
deleted file mode 100755
index 9020622350dc8..0000000000000
--- a/utils/test/TestRunner.py
+++ /dev/null
@@ -1,296 +0,0 @@
-#!/usr/bin/python
-#
-# TestRunner.py - This script is used to run arbitrary unit tests. Unit
-# tests must contain the command used to run them in the input file, starting
-# immediately after a "RUN:" string.
-#
-# This runner recognizes and replaces the following strings in the command:
-#
-# %s - Replaced with the input name of the program, or the program to
-# execute, as appropriate.
-# %S - Replaced with the directory where the input resides.
-# %llvmgcc - llvm-gcc command
-# %llvmgxx - llvm-g++ command
-# %prcontext - prcontext.tcl script
-# %t - temporary file name (derived from testcase name)
-#
-
-import errno
-import os
-import re
-import signal
-import subprocess
-import sys
-
-# Increase determinism for things that use the terminal width.
-#
-# FIXME: Find a better place for this hack.
-os.environ['COLUMNS'] = '0'
-
-class TestStatus:
- Pass = 0
- XFail = 1
- Fail = 2
- XPass = 3
- NoRunLine = 4
- Invalid = 5
-
- kNames = ['Pass','XFail','Fail','XPass','NoRunLine','Invalid']
- @staticmethod
- def getName(code):
- return TestStatus.kNames[code]
-
-def mkdir_p(path):
- if not path:
- pass
- elif os.path.exists(path):
- pass
- else:
- parent = os.path.dirname(path)
- if parent != path:
- mkdir_p(parent)
- try:
- os.mkdir(path)
- except OSError,e:
- if e.errno != errno.EEXIST:
- raise
-
-def remove(path):
- try:
- os.remove(path)
- except OSError:
- pass
-
-def cat(path, output):
- f = open(path)
- output.writelines(f)
- f.close()
-
-def runOneTest(FILENAME, SUBST, OUTPUT, TESTNAME, CLANG, CLANGCC,
- useValgrind=False,
- useDGCompat=False,
- useScript=None,
- output=sys.stdout):
- if useValgrind:
- VG_OUTPUT = '%s.vg'%(OUTPUT,)
- if os.path.exists:
- remove(VG_OUTPUT)
- CLANG = 'valgrind --leak-check=full --quiet --log-file=%s %s'%(VG_OUTPUT, CLANG)
-
- # Create the output directory if it does not already exist.
- mkdir_p(os.path.dirname(OUTPUT))
-
- # FIXME
- #ulimit -t 40
-
- # FIXME: Load script once
- # FIXME: Support "short" script syntax
-
- if useScript:
- scriptFile = useScript
- else:
- # See if we have a per-dir test script.
- dirScriptFile = os.path.join(os.path.dirname(FILENAME), 'test.script')
- if os.path.exists(dirScriptFile):
- scriptFile = dirScriptFile
- else:
- scriptFile = FILENAME
-
- # Verify the script contains a run line.
- for ln in open(scriptFile):
- if 'RUN:' in ln:
- break
- else:
- print >>output, "******************** TEST '%s' HAS NO RUN LINE! ********************"%(TESTNAME,)
- output.flush()
- return TestStatus.NoRunLine
-
- OUTPUT = os.path.abspath(OUTPUT)
- FILENAME = os.path.abspath(FILENAME)
- SCRIPT = OUTPUT + '.script'
- TEMPOUTPUT = OUTPUT + '.tmp'
-
- substitutions = [('%s',SUBST),
- ('%S',os.path.dirname(SUBST)),
- ('%llvmgcc','llvm-gcc -emit-llvm -w'),
- ('%llvmgxx','llvm-g++ -emit-llvm -w'),
- ('%prcontext','prcontext.tcl'),
- ('%t',TEMPOUTPUT),
- (' clang ', ' ' + CLANG + ' '),
- (' clang-cc ', ' ' + CLANGCC + ' ')]
- scriptLines = []
- xfailLines = []
- for ln in open(scriptFile):
- if 'RUN:' in ln:
- # Isolate run parameters
- index = ln.index('RUN:')
- ln = ln[index+4:]
-
- # Apply substitutions
- for a,b in substitutions:
- ln = ln.replace(a,b)
-
- if useDGCompat:
- ln = re.sub(r'\{(.*)\}', r'"\1"', ln)
- scriptLines.append(ln)
- elif 'XFAIL' in ln:
- xfailLines.append(ln)
-
- if xfailLines:
- print >>output, "XFAILED '%s':"%(TESTNAME,)
- output.writelines(xfailLines)
-
- # Write script file
- f = open(SCRIPT,'w')
- f.write(''.join(scriptLines))
- f.close()
-
- outputFile = open(OUTPUT,'w')
- p = None
- try:
- p = subprocess.Popen(["/bin/sh",SCRIPT],
- cwd=os.path.dirname(FILENAME),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out,err = p.communicate()
- outputFile.write(out)
- outputFile.write(err)
- SCRIPT_STATUS = p.wait()
-
- # Detect Ctrl-C in subprocess.
- if SCRIPT_STATUS == -signal.SIGINT:
- raise KeyboardInterrupt
- except KeyboardInterrupt:
- raise
- outputFile.close()
-
- if xfailLines:
- SCRIPT_STATUS = not SCRIPT_STATUS
-
- if useValgrind:
- VG_STATUS = len(list(open(VG_OUTPUT)))
- else:
- VG_STATUS = 0
-
- if SCRIPT_STATUS or VG_STATUS:
- print >>output, "******************** TEST '%s' FAILED! ********************"%(TESTNAME,)
- print >>output, "Command: "
- output.writelines(scriptLines)
- if not SCRIPT_STATUS:
- print >>output, "Output:"
- else:
- print >>output, "Incorrect Output:"
- cat(OUTPUT, output)
- if VG_STATUS:
- print >>output, "Valgrind Output:"
- cat(VG_OUTPUT, output)
- print >>output, "******************** TEST '%s' FAILED! ********************"%(TESTNAME,)
- output.flush()
- if xfailLines:
- return TestStatus.XPass
- else:
- return TestStatus.Fail
-
- if xfailLines:
- return TestStatus.XFail
- else:
- return TestStatus.Pass
-
-def capture(args):
- p = subprocess.Popen(args, stdout=subprocess.PIPE)
- out,_ = p.communicate()
- return out
-
-def which(command):
- # Would be nice if Python had a lib function for this.
- res = capture(['which',command])
- res = res.strip()
- if res and os.path.exists(res):
- return res
- return None
-
-def inferClang():
- # Determine which clang to use.
- clang = os.getenv('CLANG')
-
- # If the user set clang in the environment, definitely use that and don't
- # try to validate.
- if clang:
- return clang
-
- # Otherwise look in the path.
- clang = which('clang')
-
- if not clang:
- print >>sys.stderr, "error: couldn't find 'clang' program, try setting CLANG in your environment"
- sys.exit(1)
-
- return clang
-
-def inferClangCC(clang):
- clangcc = os.getenv('CLANGCC')
-
- # If the user set clang in the environment, definitely use that and don't
- # try to validate.
- if clangcc:
- return clangcc
-
- # Otherwise try adding -cc since we expect to be looking in a build
- # directory.
- clangcc = which(clang + '-cc')
- if not clangcc:
- # Otherwise ask clang.
- res = capture([clang, '-print-prog-name=clang-cc'])
- res = res.strip()
- if res and os.path.exists(res):
- clangcc = res
-
- if not clangcc:
- print >>sys.stderr, "error: couldn't find 'clang-cc' program, try setting CLANGCC in your environment"
- sys.exit(1)
-
- return clangcc
-
-def main():
- global options
- from optparse import OptionParser
- parser = OptionParser("usage: %prog [options] {tests}")
- parser.add_option("", "--clang", dest="clang",
- help="Program to use as \"clang\"",
- action="store", default=None)
- parser.add_option("", "--clang-cc", dest="clangcc",
- help="Program to use as \"clang-cc\"",
- action="store", default=None)
- parser.add_option("", "--vg", dest="useValgrind",
- help="Run tests under valgrind",
- action="store_true", default=False)
- parser.add_option("", "--dg", dest="useDGCompat",
- help="Use llvm dejagnu compatibility mode",
- action="store_true", default=False)
- (opts, args) = parser.parse_args()
-
- if not args:
- parser.error('No tests specified')
-
- if opts.clang is None:
- opts.clang = inferClang()
- if opts.clangcc is None:
- opts.clangcc = inferClangCC(opts.clang)
-
- for path in args:
- command = path
- # Use hand concatentation here because we want to override
- # absolute paths.
- output = 'Output/' + path + '.out'
- testname = path
-
- res = runOneTest(path, command, output, testname,
- opts.clang, opts.clangcc,
- useValgrind=opts.useValgrind,
- useDGCompat=opts.useDGCompat,
- useScript=os.getenv("TEST_SCRIPT"))
-
- sys.exit(res == TestStatus.Fail or res == TestStatus.XPass)
-
-if __name__=='__main__':
- main()