diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp deleted file mode 100644 index 69852f5fea5..00000000000 --- 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 -#include - -using namespace clang; - -namespace { - -// SaveAndRestore - A utility class that uses RIIA to save and restore -// the value of a variable. -template -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(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 { - 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 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 BackpatchBlocksTy; - BackpatchBlocksTy BackpatchBlocks; - - // A list of labels whose address has been taken (for indirect gotos). - typedef llvm::SmallPtrSet 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(t)) { - if (VariableArrayType* vat = dyn_cast(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(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(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(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(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 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::Alignment < 8 - ? 8 : llvm::AlignOf::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(Terminator); - AddressTakenLabels.insert(A->getLabel()); - - if (AlwaysAddStmt) Block->appendStmt(Terminator); - return Block; - } - - case Stmt::StmtExprClass: - return WalkAST_VisitStmtExpr(cast(Terminator)); - - case Stmt::SizeOfAlignOfExprClass: { - SizeOfAlignOfExpr* E = cast(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(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(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(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 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 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 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 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 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 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 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 BlkExprMapTy; -} - -static void FindSubExprAssignments(Stmt* Terminator, llvm::SmallPtrSet& 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(*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 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(*BI)) { - - if (BinaryOperator* B = dyn_cast(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(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(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(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(BlkExprMap)->size(); - } -} - -//===----------------------------------------------------------------------===// -// Cleanup: CFG dstor. -//===----------------------------------------------------------------------===// - -CFG::~CFG() { - delete reinterpret_cast(BlkExprMap); -} - -//===----------------------------------------------------------------------===// -// CFG pretty printing -//===----------------------------------------------------------------------===// - -namespace { - -class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper { - - typedef llvm::DenseMap > 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 { - - 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(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(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(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(B.getLabel())) { - - if (print_edges) - OS << " "; - - if (LabelStmt* L = dyn_cast(Terminator)) - OS << L->getName(); - else if (CaseStmt* C = dyn_cast(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(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(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(getTerminator())); -} - -Stmt* CFGBlock::getTerminatorCondition() { - - if (!Terminator) - return NULL; - - Expr* E = NULL; - - switch (Terminator->getStmtClass()) { - default: - break; - - case Stmt::ForStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::WhileStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::DoStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::IfStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::ChooseExprClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::IndirectGotoStmtClass: - E = cast(Terminator)->getTarget(); - break; - - case Stmt::SwitchStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::ConditionalOperatorClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::BinaryOperatorClass: // '&&' and '||' - E = cast(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 : 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 d7a9b4852a9..00000000000 --- 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 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 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 { -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 { -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 -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 2f914f14a81..00000000000 --- 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 -#include -#include -#include - -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 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& 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(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& 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(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(*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 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 b1e791a17ba..00000000000 --- 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 -#include - -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 { - /// 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 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, 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::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 daf6800ea0c..00000000000 --- 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 -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(); - 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\(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\(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\(SrcExpr) is -/// valid. -/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code -/// like this: -/// char *bytes = reinterpret_cast\(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(x) has the - // same effect as the conversion *reinterpret_cast(&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 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::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\(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(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(*((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 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\(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(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 c82e1a7da3c..00000000000 --- 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 { - 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 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(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(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(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 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()); - } - - 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(), - 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(E->getCallee()); - OverloadedFunctionDecl *Overloads - = cast(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(*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(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(), - LHS.takeAs(), - RHS.takeAs(), - 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()); - } - - // 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(*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(), - 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()); - } - - 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(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()); -} - -Sema::OwningExprResult -TemplateExprInstantiator::VisitCXXConstructExpr(CXXConstructExpr *E) { - assert(!cast(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()); - } - - return SemaRef.Owned(CXXConstructExpr::Create(SemaRef.Context, T, - E->getConstructor(), - E->isElidable(), - Args.takeAs(), - 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(); - 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(), - 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 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()); - } - - // 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 565b95b329f..00000000000 --- 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 { - Sema &SemaRef; - const TemplateArgumentList &TemplateArgs; - - template - 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 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()); - } - - 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())); -} - -//===----------------------------------------------------------------------===/ -// 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()); -} - -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()); - } - - 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 3e9cd5669aa..00000000000 --- 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 6d0c14afad4..00000000000 --- 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 2e1f24ae79a..00000000000 --- 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 9020622350d..00000000000 --- 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()